qemu
1#include "qemu/osdep.h"2#include "qemu/queue.h"3#include "qemu/envlist.h"4
5struct envlist_entry {6const char *ev_var; /* actual env value */7QLIST_ENTRY(envlist_entry) ev_link;8};9
10struct envlist {11QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */12size_t el_count; /* number of entries */13};14
15static int envlist_parse(envlist_t *envlist,16const char *env, int (*)(envlist_t *, const char *));17
18/*
19* Allocates new envlist and returns pointer to it.
20*/
21envlist_t *22envlist_create(void)23{
24envlist_t *envlist;25
26envlist = g_malloc(sizeof(*envlist));27
28QLIST_INIT(&envlist->el_entries);29envlist->el_count = 0;30
31return (envlist);32}
33
34/*
35* Releases given envlist and its entries.
36*/
37void
38envlist_free(envlist_t *envlist)39{
40struct envlist_entry *entry;41
42assert(envlist != NULL);43
44while (envlist->el_entries.lh_first != NULL) {45entry = envlist->el_entries.lh_first;46QLIST_REMOVE(entry, ev_link);47
48g_free((char *)entry->ev_var);49g_free(entry);50}51g_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*/
65int
66envlist_parse_set(envlist_t *envlist, const char *env)67{
68return (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*/
77int
78envlist_parse_unset(envlist_t *envlist, const char *env)79{
80return (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*/
89static int90envlist_parse(envlist_t *envlist, const char *env,91int (*callback)(envlist_t *, const char *))92{
93char *tmpenv, *envvar;94char *envsave = NULL;95int ret = 0;96assert(callback != NULL);97
98if ((envlist == NULL) || (env == NULL))99return (EINVAL);100
101tmpenv = g_strdup(env);102envsave = tmpenv;103
104do {105envvar = strchr(tmpenv, ',');106if (envvar != NULL) {107*envvar = '\0';108}109if ((*callback)(envlist, tmpenv) != 0) {110ret = errno;111break;112}113tmpenv = envvar + 1;114} while (envvar != NULL);115
116g_free(envsave);117return 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*/
126int
127envlist_setenv(envlist_t *envlist, const char *env)128{
129struct envlist_entry *entry = NULL;130const char *eq_sign;131size_t envname_len;132
133if ((envlist == NULL) || (env == NULL))134return (EINVAL);135
136/* find out first equals sign in given env */137if ((eq_sign = strchr(env, '=')) == NULL)138return (EINVAL);139envname_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*/
146for (entry = envlist->el_entries.lh_first; entry != NULL;147entry = entry->ev_link.le_next) {148if (strncmp(entry->ev_var, env, envname_len) == 0)149break;150}151
152if (entry != NULL) {153QLIST_REMOVE(entry, ev_link);154g_free((char *)entry->ev_var);155g_free(entry);156} else {157envlist->el_count++;158}159
160entry = g_malloc(sizeof(*entry));161entry->ev_var = g_strdup(env);162QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);163
164return (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*/
171int
172envlist_unsetenv(envlist_t *envlist, const char *env)173{
174struct envlist_entry *entry;175size_t envname_len;176
177if ((envlist == NULL) || (env == NULL))178return (EINVAL);179
180/* env is not allowed to contain '=' */181if (strchr(env, '=') != NULL)182return (EINVAL);183
184/*185* Find out the requested entry and remove
186* it from the list.
187*/
188envname_len = strlen(env);189for (entry = envlist->el_entries.lh_first; entry != NULL;190entry = entry->ev_link.le_next) {191if (strncmp(entry->ev_var, env, envname_len) == 0)192break;193}194if (entry != NULL) {195QLIST_REMOVE(entry, ev_link);196g_free((char *)entry->ev_var);197g_free(entry);198
199envlist->el_count--;200}201return (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*/
214char **215envlist_to_environ(const envlist_t *envlist, size_t *count)216{
217struct envlist_entry *entry;218char **env, **penv;219
220penv = env = g_new(char *, envlist->el_count + 1);221
222for (entry = envlist->el_entries.lh_first; entry != NULL;223entry = entry->ev_link.le_next) {224*(penv++) = g_strdup(entry->ev_var);225}226*penv = NULL; /* NULL terminate the list */227
228if (count != NULL)229*count = envlist->el_count;230
231return (env);232}
233