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