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