qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

envlist.c (5141B)


      1 #include "qemu/osdep.h"
      2 #include "qemu/queue.h"
      3 #include "qemu/envlist.h"
      4 
      5 struct envlist_entry {
      6 	const char *ev_var;			/* actual env value */
      7 	QLIST_ENTRY(envlist_entry) ev_link;
      8 };
      9 
     10 struct envlist {
     11 	QLIST_HEAD(, envlist_entry) el_entries;	/* actual entries */
     12 	size_t el_count;			/* number of entries */
     13 };
     14 
     15 static int envlist_parse(envlist_t *envlist,
     16     const char *env, int (*)(envlist_t *, const char *));
     17 
     18 /*
     19  * Allocates new envlist and returns pointer to it.
     20  */
     21 envlist_t *
     22 envlist_create(void)
     23 {
     24 	envlist_t *envlist;
     25 
     26 	envlist = g_malloc(sizeof(*envlist));
     27 
     28 	QLIST_INIT(&envlist->el_entries);
     29 	envlist->el_count = 0;
     30 
     31 	return (envlist);
     32 }
     33 
     34 /*
     35  * Releases given envlist and its entries.
     36  */
     37 void
     38 envlist_free(envlist_t *envlist)
     39 {
     40 	struct envlist_entry *entry;
     41 
     42 	assert(envlist != NULL);
     43 
     44 	while (envlist->el_entries.lh_first != NULL) {
     45 		entry = envlist->el_entries.lh_first;
     46 		QLIST_REMOVE(entry, ev_link);
     47 
     48 		g_free((char *)entry->ev_var);
     49 		g_free(entry);
     50 	}
     51 	g_free(envlist);
     52 }
     53 
     54 /*
     55  * Parses comma separated list of set/modify environment
     56  * variable entries and updates given enlist accordingly.
     57  *
     58  * For example:
     59  *     envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
     60  *
     61  * inserts/sets environment variables HOME and SHELL.
     62  *
     63  * Returns 0 on success, errno otherwise.
     64  */
     65 int
     66 envlist_parse_set(envlist_t *envlist, const char *env)
     67 {
     68 	return (envlist_parse(envlist, env, &envlist_setenv));
     69 }
     70 
     71 /*
     72  * Parses comma separated list of unset environment variable
     73  * entries and removes given variables from given envlist.
     74  *
     75  * Returns 0 on success, errno otherwise.
     76  */
     77 int
     78 envlist_parse_unset(envlist_t *envlist, const char *env)
     79 {
     80 	return (envlist_parse(envlist, env, &envlist_unsetenv));
     81 }
     82 
     83 /*
     84  * Parses comma separated list of set, modify or unset entries
     85  * and calls given callback for each entry.
     86  *
     87  * Returns 0 in case of success, errno otherwise.
     88  */
     89 static int
     90 envlist_parse(envlist_t *envlist, const char *env,
     91     int (*callback)(envlist_t *, const char *))
     92 {
     93 	char *tmpenv, *envvar;
     94 	char *envsave = NULL;
     95     int ret = 0;
     96     assert(callback != NULL);
     97 
     98 	if ((envlist == NULL) || (env == NULL))
     99 		return (EINVAL);
    100 
    101 	tmpenv = g_strdup(env);
    102     envsave = tmpenv;
    103 
    104     do {
    105         envvar = strchr(tmpenv, ',');
    106         if (envvar != NULL) {
    107             *envvar = '\0';
    108         }
    109         if ((*callback)(envlist, tmpenv) != 0) {
    110             ret = errno;
    111             break;
    112 		}
    113         tmpenv = envvar + 1;
    114     } while (envvar != NULL);
    115 
    116     g_free(envsave);
    117     return ret;
    118 }
    119 
    120 /*
    121  * Sets environment value to envlist in similar manner
    122  * than putenv(3).
    123  *
    124  * Returns 0 in success, errno otherwise.
    125  */
    126 int
    127 envlist_setenv(envlist_t *envlist, const char *env)
    128 {
    129 	struct envlist_entry *entry = NULL;
    130 	const char *eq_sign;
    131 	size_t envname_len;
    132 
    133 	if ((envlist == NULL) || (env == NULL))
    134 		return (EINVAL);
    135 
    136 	/* find out first equals sign in given env */
    137 	if ((eq_sign = strchr(env, '=')) == NULL)
    138 		return (EINVAL);
    139 	envname_len = eq_sign - env + 1;
    140 
    141 	/*
    142 	 * If there already exists variable with given name
    143 	 * we remove and release it before allocating a whole
    144 	 * new entry.
    145 	 */
    146 	for (entry = envlist->el_entries.lh_first; entry != NULL;
    147 	    entry = entry->ev_link.le_next) {
    148 		if (strncmp(entry->ev_var, env, envname_len) == 0)
    149 			break;
    150 	}
    151 
    152 	if (entry != NULL) {
    153 		QLIST_REMOVE(entry, ev_link);
    154 		g_free((char *)entry->ev_var);
    155 		g_free(entry);
    156 	} else {
    157 		envlist->el_count++;
    158 	}
    159 
    160 	entry = g_malloc(sizeof(*entry));
    161 	entry->ev_var = g_strdup(env);
    162 	QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
    163 
    164 	return (0);
    165 }
    166 
    167 /*
    168  * Removes given env value from envlist in similar manner
    169  * than unsetenv(3).  Returns 0 in success, errno otherwise.
    170  */
    171 int
    172 envlist_unsetenv(envlist_t *envlist, const char *env)
    173 {
    174 	struct envlist_entry *entry;
    175 	size_t envname_len;
    176 
    177 	if ((envlist == NULL) || (env == NULL))
    178 		return (EINVAL);
    179 
    180 	/* env is not allowed to contain '=' */
    181 	if (strchr(env, '=') != NULL)
    182 		return (EINVAL);
    183 
    184 	/*
    185 	 * Find out the requested entry and remove
    186 	 * it from the list.
    187 	 */
    188 	envname_len = strlen(env);
    189 	for (entry = envlist->el_entries.lh_first; entry != NULL;
    190 	    entry = entry->ev_link.le_next) {
    191 		if (strncmp(entry->ev_var, env, envname_len) == 0)
    192 			break;
    193 	}
    194 	if (entry != NULL) {
    195 		QLIST_REMOVE(entry, ev_link);
    196 		g_free((char *)entry->ev_var);
    197 		g_free(entry);
    198 
    199 		envlist->el_count--;
    200 	}
    201 	return (0);
    202 }
    203 
    204 /*
    205  * Returns given envlist as array of strings (in same form that
    206  * global variable environ is).  Caller must free returned memory
    207  * by calling g_free for each element and the array.
    208  * Returned array and given envlist are not related (no common
    209  * references).
    210  *
    211  * If caller provides count pointer, number of items in array is
    212  * stored there.
    213  */
    214 char **
    215 envlist_to_environ(const envlist_t *envlist, size_t *count)
    216 {
    217 	struct envlist_entry *entry;
    218 	char **env, **penv;
    219 
    220 	penv = env = g_new(char *, envlist->el_count + 1);
    221 
    222 	for (entry = envlist->el_entries.lh_first; entry != NULL;
    223 	    entry = entry->ev_link.le_next) {
    224 		*(penv++) = g_strdup(entry->ev_var);
    225 	}
    226 	*penv = NULL; /* NULL terminate the list */
    227 
    228 	if (count != NULL)
    229 		*count = envlist->el_count;
    230 
    231 	return (env);
    232 }