]> git.proxmox.com Git - systemd.git/blob - src/shared/env-util.c
Imported Upstream version 208
[systemd.git] / src / shared / env-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <limits.h>
23 #include <sys/param.h>
24 #include <unistd.h>
25
26 #include "strv.h"
27 #include "utf8.h"
28 #include "util.h"
29 #include "env-util.h"
30 #include "def.h"
31
32 #define VALID_CHARS_ENV_NAME \
33 DIGITS LETTERS \
34 "_"
35
36 #ifndef ARG_MAX
37 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
38 #endif
39
40 static bool env_name_is_valid_n(const char *e, size_t n) {
41 const char *p;
42
43 if (!e)
44 return false;
45
46 if (n <= 0)
47 return false;
48
49 if (e[0] >= '0' && e[0] <= '9')
50 return false;
51
52 /* POSIX says the overall size of the environment block cannot
53 * be > ARG_MAX, an individual assignment hence cannot be
54 * either. Discounting the equal sign and trailing NUL this
55 * hence leaves ARG_MAX-2 as longest possible variable
56 * name. */
57 if (n > ARG_MAX - 2)
58 return false;
59
60 for (p = e; p < e + n; p++)
61 if (!strchr(VALID_CHARS_ENV_NAME, *p))
62 return false;
63
64 return true;
65 }
66
67 bool env_name_is_valid(const char *e) {
68 if (!e)
69 return false;
70
71 return env_name_is_valid_n(e, strlen(e));
72 }
73
74 bool env_value_is_valid(const char *e) {
75 if (!e)
76 return false;
77
78 if (!utf8_is_valid(e))
79 return false;
80
81 if (string_has_cc(e))
82 return false;
83
84 /* POSIX says the overall size of the environment block cannot
85 * be > ARG_MAX, an individual assignment hence cannot be
86 * either. Discounting the shortest possible variable name of
87 * length 1, the equal sign and trailing NUL this hence leaves
88 * ARG_MAX-3 as longest possible variable value. */
89 if (strlen(e) > ARG_MAX - 3)
90 return false;
91
92 return true;
93 }
94
95 bool env_assignment_is_valid(const char *e) {
96 const char *eq;
97
98 eq = strchr(e, '=');
99 if (!eq)
100 return false;
101
102 if (!env_name_is_valid_n(e, eq - e))
103 return false;
104
105 if (!env_value_is_valid(eq + 1))
106 return false;
107
108 /* POSIX says the overall size of the environment block cannot
109 * be > ARG_MAX, hence the individual variable assignments
110 * cannot be either, but let's leave room for one trailing NUL
111 * byte. */
112 if (strlen(e) > ARG_MAX - 1)
113 return false;
114
115 return true;
116 }
117
118 bool strv_env_is_valid(char **e) {
119 char **p, **q;
120
121 STRV_FOREACH(p, e) {
122 size_t k;
123
124 if (!env_assignment_is_valid(*p))
125 return false;
126
127 /* Check if there are duplicate assginments */
128 k = strcspn(*p, "=");
129 STRV_FOREACH(q, p + 1)
130 if (strneq(*p, *q, k) && (*q)[k] == '=')
131 return false;
132 }
133
134 return true;
135 }
136
137 bool strv_env_name_or_assignment_is_valid(char **l) {
138 char **p, **q;
139
140 STRV_FOREACH(p, l) {
141 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
142 return false;
143
144 STRV_FOREACH(q, p + 1)
145 if (streq(*p, *q))
146 return false;
147 }
148
149 return true;
150 }
151
152 static int env_append(char **r, char ***k, char **a) {
153 assert(r);
154 assert(k);
155
156 if (!a)
157 return 0;
158
159 /* Add the entries of a to *k unless they already exist in *r
160 * in which case they are overridden instead. This assumes
161 * there is enough space in the r array. */
162
163 for (; *a; a++) {
164 char **j;
165 size_t n;
166
167 n = strcspn(*a, "=");
168
169 if ((*a)[n] == '=')
170 n++;
171
172 for (j = r; j < *k; j++)
173 if (strneq(*j, *a, n))
174 break;
175
176 if (j >= *k)
177 (*k)++;
178 else
179 free(*j);
180
181 *j = strdup(*a);
182 if (!*j)
183 return -ENOMEM;
184 }
185
186 return 0;
187 }
188
189 char **strv_env_merge(unsigned n_lists, ...) {
190 size_t n = 0;
191 char **l, **k, **r;
192 va_list ap;
193 unsigned i;
194
195 /* Merges an arbitrary number of environment sets */
196
197 va_start(ap, n_lists);
198 for (i = 0; i < n_lists; i++) {
199 l = va_arg(ap, char**);
200 n += strv_length(l);
201 }
202 va_end(ap);
203
204 r = new(char*, n+1);
205 if (!r)
206 return NULL;
207
208 k = r;
209
210 va_start(ap, n_lists);
211 for (i = 0; i < n_lists; i++) {
212 l = va_arg(ap, char**);
213 if (env_append(r, &k, l) < 0)
214 goto fail;
215 }
216 va_end(ap);
217
218 *k = NULL;
219
220 return r;
221
222 fail:
223 va_end(ap);
224 strv_free(r);
225
226 return NULL;
227 }
228
229 _pure_ static bool env_match(const char *t, const char *pattern) {
230 assert(t);
231 assert(pattern);
232
233 /* pattern a matches string a
234 * a matches a=
235 * a matches a=b
236 * a= matches a=
237 * a=b matches a=b
238 * a= does not match a
239 * a=b does not match a=
240 * a=b does not match a
241 * a=b does not match a=c */
242
243 if (streq(t, pattern))
244 return true;
245
246 if (!strchr(pattern, '=')) {
247 size_t l = strlen(pattern);
248
249 return strneq(t, pattern, l) && t[l] == '=';
250 }
251
252 return false;
253 }
254
255 char **strv_env_delete(char **x, unsigned n_lists, ...) {
256 size_t n, i = 0;
257 char **k, **r;
258 va_list ap;
259
260 /* Deletes every entry from x that is mentioned in the other
261 * string lists */
262
263 n = strv_length(x);
264
265 r = new(char*, n+1);
266 if (!r)
267 return NULL;
268
269 STRV_FOREACH(k, x) {
270 unsigned v;
271
272 va_start(ap, n_lists);
273 for (v = 0; v < n_lists; v++) {
274 char **l, **j;
275
276 l = va_arg(ap, char**);
277 STRV_FOREACH(j, l)
278 if (env_match(*k, *j))
279 goto skip;
280 }
281 va_end(ap);
282
283 r[i] = strdup(*k);
284 if (!r[i]) {
285 strv_free(r);
286 return NULL;
287 }
288
289 i++;
290 continue;
291
292 skip:
293 va_end(ap);
294 }
295
296 r[i] = NULL;
297
298 assert(i <= n);
299
300 return r;
301 }
302
303 char **strv_env_unset(char **l, const char *p) {
304
305 char **f, **t;
306
307 if (!l)
308 return NULL;
309
310 assert(p);
311
312 /* Drops every occurrence of the env var setting p in the
313 * string list. edits in-place. */
314
315 for (f = t = l; *f; f++) {
316
317 if (env_match(*f, p)) {
318 free(*f);
319 continue;
320 }
321
322 *(t++) = *f;
323 }
324
325 *t = NULL;
326 return l;
327 }
328
329 char **strv_env_set(char **x, const char *p) {
330
331 char **k, **r;
332 char* m[2] = { (char*) p, NULL };
333
334 /* Overrides the env var setting of p, returns a new copy */
335
336 r = new(char*, strv_length(x)+2);
337 if (!r)
338 return NULL;
339
340 k = r;
341 if (env_append(r, &k, x) < 0)
342 goto fail;
343
344 if (env_append(r, &k, m) < 0)
345 goto fail;
346
347 *k = NULL;
348
349 return r;
350
351 fail:
352 strv_free(r);
353 return NULL;
354 }
355
356 char *strv_env_get_n(char **l, const char *name, size_t k) {
357 char **i;
358
359 assert(name);
360
361 if (k <= 0)
362 return NULL;
363
364 STRV_FOREACH(i, l)
365 if (strneq(*i, name, k) &&
366 (*i)[k] == '=')
367 return *i + k + 1;
368
369 return NULL;
370 }
371
372 char *strv_env_get(char **l, const char *name) {
373 assert(name);
374
375 return strv_env_get_n(l, name, strlen(name));
376 }
377
378 char **strv_env_clean_log(char **e, const char *message) {
379 char **p, **q;
380 int k = 0;
381
382 STRV_FOREACH(p, e) {
383 size_t n;
384 bool duplicate = false;
385
386 if (!env_assignment_is_valid(*p)) {
387 if (message)
388 log_error("Ignoring invalid environment '%s': %s", *p, message);
389 free(*p);
390 continue;
391 }
392
393 n = strcspn(*p, "=");
394 STRV_FOREACH(q, p + 1)
395 if (strneq(*p, *q, n) && (*q)[n] == '=') {
396 duplicate = true;
397 break;
398 }
399
400 if (duplicate) {
401 free(*p);
402 continue;
403 }
404
405 e[k++] = *p;
406 }
407
408 e[k] = NULL;
409 return e;
410 }
411
412 char **strv_env_clean(char **e) {
413 return strv_env_clean_log(e, NULL);
414 }