| #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); | 
 | } |