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