|  | #include "qemu/osdep.h" | 
|  | #include "qemu/queue.h" | 
|  | #include "qemu/envlist.h" | 
|  |  | 
|  | struct envlist_entry { | 
|  | const char *ev_var;            /* actual env value */ | 
|  | QLIST_ENTRY(envlist_entry) ev_link; | 
|  | }; | 
|  |  | 
|  | struct envlist { | 
|  | QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */ | 
|  | size_t el_count;                        /* number of entries */ | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Allocates new envlist and returns pointer to it. | 
|  | */ | 
|  | envlist_t * | 
|  | envlist_create(void) | 
|  | { | 
|  | envlist_t *envlist; | 
|  |  | 
|  | envlist = g_malloc(sizeof(*envlist)); | 
|  |  | 
|  | QLIST_INIT(&envlist->el_entries); | 
|  | envlist->el_count = 0; | 
|  |  | 
|  | return (envlist); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Releases given envlist and its entries. | 
|  | */ | 
|  | void | 
|  | envlist_free(envlist_t *envlist) | 
|  | { | 
|  | struct envlist_entry *entry; | 
|  |  | 
|  | assert(envlist != NULL); | 
|  |  | 
|  | while (envlist->el_entries.lh_first != NULL) { | 
|  | entry = envlist->el_entries.lh_first; | 
|  | QLIST_REMOVE(entry, ev_link); | 
|  |  | 
|  | g_free((char *)entry->ev_var); | 
|  | g_free(entry); | 
|  | } | 
|  | g_free(envlist); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Sets environment value to envlist in similar manner | 
|  | * than putenv(3). | 
|  | * | 
|  | * Returns 0 in success, errno otherwise. | 
|  | */ | 
|  | int | 
|  | envlist_setenv(envlist_t *envlist, const char *env) | 
|  | { | 
|  | struct envlist_entry *entry = NULL; | 
|  | const char *eq_sign; | 
|  | size_t envname_len; | 
|  |  | 
|  | if ((envlist == NULL) || (env == NULL)) | 
|  | return (EINVAL); | 
|  |  | 
|  | /* find out first equals sign in given env */ | 
|  | if ((eq_sign = strchr(env, '=')) == NULL) | 
|  | return (EINVAL); | 
|  | envname_len = eq_sign - env + 1; | 
|  |  | 
|  | /* | 
|  | * If there already exists variable with given name | 
|  | * we remove and release it before allocating a whole | 
|  | * new entry. | 
|  | */ | 
|  | for (entry = envlist->el_entries.lh_first; entry != NULL; | 
|  | entry = entry->ev_link.le_next) { | 
|  | if (strncmp(entry->ev_var, env, envname_len) == 0) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (entry != NULL) { | 
|  | QLIST_REMOVE(entry, ev_link); | 
|  | g_free((char *)entry->ev_var); | 
|  | g_free(entry); | 
|  | } else { | 
|  | envlist->el_count++; | 
|  | } | 
|  |  | 
|  | entry = g_malloc(sizeof(*entry)); | 
|  | entry->ev_var = g_strdup(env); | 
|  | QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link); | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Removes given env value from envlist in similar manner | 
|  | * than unsetenv(3).  Returns 0 in success, errno otherwise. | 
|  | */ | 
|  | int | 
|  | envlist_unsetenv(envlist_t *envlist, const char *env) | 
|  | { | 
|  | struct envlist_entry *entry; | 
|  | size_t envname_len; | 
|  |  | 
|  | if ((envlist == NULL) || (env == NULL)) | 
|  | return (EINVAL); | 
|  |  | 
|  | /* env is not allowed to contain '=' */ | 
|  | if (strchr(env, '=') != NULL) | 
|  | return (EINVAL); | 
|  |  | 
|  | /* | 
|  | * Find out the requested entry and remove | 
|  | * it from the list. | 
|  | */ | 
|  | envname_len = strlen(env); | 
|  | for (entry = envlist->el_entries.lh_first; entry != NULL; | 
|  | entry = entry->ev_link.le_next) { | 
|  | if (strncmp(entry->ev_var, env, envname_len) == 0) | 
|  | break; | 
|  | } | 
|  | if (entry != NULL) { | 
|  | QLIST_REMOVE(entry, ev_link); | 
|  | g_free((char *)entry->ev_var); | 
|  | g_free(entry); | 
|  |  | 
|  | envlist->el_count--; | 
|  | } | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Returns given envlist as array of strings (in same form that | 
|  | * global variable environ is).  Caller must free returned memory | 
|  | * by calling g_free for each element and the array. | 
|  | * Returned array and given envlist are not related (no common | 
|  | * references). | 
|  | * | 
|  | * If caller provides count pointer, number of items in array is | 
|  | * stored there. | 
|  | */ | 
|  | char ** | 
|  | envlist_to_environ(const envlist_t *envlist, size_t *count) | 
|  | { | 
|  | struct envlist_entry *entry; | 
|  | char **env, **penv; | 
|  |  | 
|  | penv = env = g_new(char *, envlist->el_count + 1); | 
|  |  | 
|  | for (entry = envlist->el_entries.lh_first; entry != NULL; | 
|  | entry = entry->ev_link.le_next) { | 
|  | *(penv++) = g_strdup(entry->ev_var); | 
|  | } | 
|  | *penv = NULL; /* NULL terminate the list */ | 
|  |  | 
|  | if (count != NULL) | 
|  | *count = envlist->el_count; | 
|  |  | 
|  | return (env); | 
|  | } |