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