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