These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / util / envlist.c
1 #include "qemu/osdep.h"
2 #include "qemu-common.h"
3 #include "qemu/queue.h"
4 #include "qemu/envlist.h"
5
6 struct envlist_entry {
7         const char *ev_var;                     /* actual env value */
8         QLIST_ENTRY(envlist_entry) ev_link;
9 };
10
11 struct envlist {
12         QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
13         size_t el_count;                        /* number of entries */
14 };
15
16 static int envlist_parse(envlist_t *envlist,
17     const char *env, int (*)(envlist_t *, const char *));
18
19 /*
20  * Allocates new envlist and returns pointer to that or
21  * NULL in case of error.
22  */
23 envlist_t *
24 envlist_create(void)
25 {
26         envlist_t *envlist;
27
28         if ((envlist = malloc(sizeof (*envlist))) == NULL)
29                 return (NULL);
30
31         QLIST_INIT(&envlist->el_entries);
32         envlist->el_count = 0;
33
34         return (envlist);
35 }
36
37 /*
38  * Releases given envlist and its entries.
39  */
40 void
41 envlist_free(envlist_t *envlist)
42 {
43         struct envlist_entry *entry;
44
45         assert(envlist != NULL);
46
47         while (envlist->el_entries.lh_first != NULL) {
48                 entry = envlist->el_entries.lh_first;
49                 QLIST_REMOVE(entry, ev_link);
50
51                 free((char *)entry->ev_var);
52                 free(entry);
53         }
54         free(envlist);
55 }
56
57 /*
58  * Parses comma separated list of set/modify environment
59  * variable entries and updates given enlist accordingly.
60  *
61  * For example:
62  *     envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
63  *
64  * inserts/sets environment variables HOME and SHELL.
65  *
66  * Returns 0 on success, errno otherwise.
67  */
68 int
69 envlist_parse_set(envlist_t *envlist, const char *env)
70 {
71         return (envlist_parse(envlist, env, &envlist_setenv));
72 }
73
74 /*
75  * Parses comma separated list of unset environment variable
76  * entries and removes given variables from given envlist.
77  *
78  * Returns 0 on success, errno otherwise.
79  */
80 int
81 envlist_parse_unset(envlist_t *envlist, const char *env)
82 {
83         return (envlist_parse(envlist, env, &envlist_unsetenv));
84 }
85
86 /*
87  * Parses comma separated list of set, modify or unset entries
88  * and calls given callback for each entry.
89  *
90  * Returns 0 in case of success, errno otherwise.
91  */
92 static int
93 envlist_parse(envlist_t *envlist, const char *env,
94     int (*callback)(envlist_t *, const char *))
95 {
96         char *tmpenv, *envvar;
97         char *envsave = NULL;
98     int ret = 0;
99     assert(callback != NULL);
100
101         if ((envlist == NULL) || (env == NULL))
102                 return (EINVAL);
103
104         if ((tmpenv = strdup(env)) == NULL)
105                 return (errno);
106     envsave = tmpenv;
107
108     do {
109         envvar = strchr(tmpenv, ',');
110         if (envvar != NULL) {
111             *envvar = '\0';
112         }
113         if ((*callback)(envlist, tmpenv) != 0) {
114             ret = errno;
115             break;
116                 }
117         tmpenv = envvar + 1;
118     } while (envvar != NULL);
119
120     free(envsave);
121     return ret;
122 }
123
124 /*
125  * Sets environment value to envlist in similar manner
126  * than putenv(3).
127  *
128  * Returns 0 in success, errno otherwise.
129  */
130 int
131 envlist_setenv(envlist_t *envlist, const char *env)
132 {
133         struct envlist_entry *entry = NULL;
134         const char *eq_sign;
135         size_t envname_len;
136
137         if ((envlist == NULL) || (env == NULL))
138                 return (EINVAL);
139
140         /* find out first equals sign in given env */
141         if ((eq_sign = strchr(env, '=')) == NULL)
142                 return (EINVAL);
143         envname_len = eq_sign - env + 1;
144
145         /*
146          * If there already exists variable with given name
147          * we remove and release it before allocating a whole
148          * new entry.
149          */
150         for (entry = envlist->el_entries.lh_first; entry != NULL;
151             entry = entry->ev_link.le_next) {
152                 if (strncmp(entry->ev_var, env, envname_len) == 0)
153                         break;
154         }
155
156         if (entry != NULL) {
157                 QLIST_REMOVE(entry, ev_link);
158                 free((char *)entry->ev_var);
159                 free(entry);
160         } else {
161                 envlist->el_count++;
162         }
163
164         if ((entry = malloc(sizeof (*entry))) == NULL)
165                 return (errno);
166         if ((entry->ev_var = strdup(env)) == NULL) {
167                 free(entry);
168                 return (errno);
169         }
170         QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
171
172         return (0);
173 }
174
175 /*
176  * Removes given env value from envlist in similar manner
177  * than unsetenv(3).  Returns 0 in success, errno otherwise.
178  */
179 int
180 envlist_unsetenv(envlist_t *envlist, const char *env)
181 {
182         struct envlist_entry *entry;
183         size_t envname_len;
184
185         if ((envlist == NULL) || (env == NULL))
186                 return (EINVAL);
187
188         /* env is not allowed to contain '=' */
189         if (strchr(env, '=') != NULL)
190                 return (EINVAL);
191
192         /*
193          * Find out the requested entry and remove
194          * it from the list.
195          */
196         envname_len = strlen(env);
197         for (entry = envlist->el_entries.lh_first; entry != NULL;
198             entry = entry->ev_link.le_next) {
199                 if (strncmp(entry->ev_var, env, envname_len) == 0)
200                         break;
201         }
202         if (entry != NULL) {
203                 QLIST_REMOVE(entry, ev_link);
204                 free((char *)entry->ev_var);
205                 free(entry);
206
207                 envlist->el_count--;
208         }
209         return (0);
210 }
211
212 /*
213  * Returns given envlist as array of strings (in same form that
214  * global variable environ is).  Caller must free returned memory
215  * by calling free(3) for each element and for the array.  Returned
216  * array and given envlist are not related (no common references).
217  *
218  * If caller provides count pointer, number of items in array is
219  * stored there.  In case of error, NULL is returned and no memory
220  * is allocated.
221  */
222 char **
223 envlist_to_environ(const envlist_t *envlist, size_t *count)
224 {
225         struct envlist_entry *entry;
226         char **env, **penv;
227
228         penv = env = malloc((envlist->el_count + 1) * sizeof (char *));
229         if (env == NULL)
230                 return (NULL);
231
232         for (entry = envlist->el_entries.lh_first; entry != NULL;
233             entry = entry->ev_link.le_next) {
234                 *(penv++) = strdup(entry->ev_var);
235         }
236         *penv = NULL; /* NULL terminate the list */
237
238         if (count != NULL)
239                 *count = envlist->el_count;
240
241         return (env);
242 }