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 } 233