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