]>
Commit | Line | Data |
---|---|---|
aafd7584 | 1 | #include "qemu/osdep.h" |
1de7afc9 PB |
2 | #include "qemu/queue.h" |
3 | #include "qemu/envlist.h" | |
04a6dfeb AJ |
4 | |
5 | struct envlist_entry { | |
6 | const char *ev_var; /* actual env value */ | |
72cf2d4f | 7 | QLIST_ENTRY(envlist_entry) ev_link; |
04a6dfeb AJ |
8 | }; |
9 | ||
10 | struct envlist { | |
72cf2d4f | 11 | QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */ |
04a6dfeb AJ |
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 | /* | |
ec45bbe5 | 19 | * Allocates new envlist and returns pointer to it. |
04a6dfeb AJ |
20 | */ |
21 | envlist_t * | |
22 | envlist_create(void) | |
23 | { | |
24 | envlist_t *envlist; | |
25 | ||
ec45bbe5 | 26 | envlist = g_malloc(sizeof(*envlist)); |
04a6dfeb | 27 | |
72cf2d4f | 28 | QLIST_INIT(&envlist->el_entries); |
04a6dfeb AJ |
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; | |
72cf2d4f | 46 | QLIST_REMOVE(entry, ev_link); |
04a6dfeb | 47 | |
ec45bbe5 SS |
48 | g_free((char *)entry->ev_var); |
49 | g_free(entry); | |
04a6dfeb | 50 | } |
ec45bbe5 | 51 | g_free(envlist); |
04a6dfeb AJ |
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; | |
459db780 OK |
95 | int ret = 0; |
96 | assert(callback != NULL); | |
04a6dfeb AJ |
97 | |
98 | if ((envlist == NULL) || (env == NULL)) | |
99 | return (EINVAL); | |
100 | ||
ec45bbe5 | 101 | tmpenv = g_strdup(env); |
459db780 OK |
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; | |
04a6dfeb | 112 | } |
459db780 OK |
113 | tmpenv = envvar + 1; |
114 | } while (envvar != NULL); | |
04a6dfeb | 115 | |
ec45bbe5 | 116 | g_free(envsave); |
459db780 | 117 | return ret; |
04a6dfeb AJ |
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) { | |
72cf2d4f | 153 | QLIST_REMOVE(entry, ev_link); |
ec45bbe5 SS |
154 | g_free((char *)entry->ev_var); |
155 | g_free(entry); | |
04a6dfeb AJ |
156 | } else { |
157 | envlist->el_count++; | |
158 | } | |
159 | ||
ec45bbe5 SS |
160 | entry = g_malloc(sizeof(*entry)); |
161 | entry->ev_var = g_strdup(env); | |
72cf2d4f | 162 | QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link); |
04a6dfeb AJ |
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) { | |
72cf2d4f | 195 | QLIST_REMOVE(entry, ev_link); |
ec45bbe5 SS |
196 | g_free((char *)entry->ev_var); |
197 | g_free(entry); | |
04a6dfeb AJ |
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 | |
ec45bbe5 SS |
207 | * by calling g_free for each element and the array. |
208 | * Returned array and given envlist are not related (no common | |
209 | * references). | |
04a6dfeb AJ |
210 | * |
211 | * If caller provides count pointer, number of items in array is | |
ec45bbe5 | 212 | * stored there. |
04a6dfeb AJ |
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 | ||
ec45bbe5 | 220 | penv = env = g_malloc((envlist->el_count + 1) * sizeof(char *)); |
04a6dfeb AJ |
221 | |
222 | for (entry = envlist->el_entries.lh_first; entry != NULL; | |
223 | entry = entry->ev_link.le_next) { | |
ec45bbe5 | 224 | *(penv++) = g_strdup(entry->ev_var); |
04a6dfeb AJ |
225 | } |
226 | *penv = NULL; /* NULL terminate the list */ | |
227 | ||
228 | if (count != NULL) | |
229 | *count = envlist->el_count; | |
230 | ||
231 | return (env); | |
232 | } |