]> Git Repo - qemu.git/blob - util/envlist.c
Merge remote-tracking branch 'remotes/armbru/tags/pull-misc-2019-06-11-v3' into staging
[qemu.git] / util / envlist.c
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_malloc((envlist->el_count + 1) * sizeof(char *));
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 }
This page took 0.045082 seconds and 4 git commands to generate.