envlist.c (5155B)
1#include "qemu/osdep.h" 2#include "qemu/queue.h" 3#include "qemu/envlist.h" 4 5struct envlist_entry { 6 const char *ev_var; /* actual env value */ 7 QLIST_ENTRY(envlist_entry) ev_link; 8}; 9 10struct envlist { 11 QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */ 12 size_t el_count; /* number of entries */ 13}; 14 15static 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 */ 21envlist_t * 22envlist_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 */ 37void 38envlist_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 */ 65int 66envlist_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 */ 77int 78envlist_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 */ 89static int 90envlist_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 */ 126int 127envlist_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 */ 171int 172envlist_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 */ 214char ** 215envlist_to_environ(const envlist_t *envlist, size_t *count) 216{ 217 struct envlist_entry *entry; 218 char **env, **penv; 219 220 penv = env = g_malloc((envlist->el_count + 1) * sizeof(char *)); 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}