]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/env-util.c
Merge pull request #8575 from keszybz/non-absolute-paths
[thirdparty/systemd.git] / src / basic / env-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <limits.h>
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include "alloc-util.h"
16 #include "env-util.h"
17 #include "escape.h"
18 #include "extract-word.h"
19 #include "macro.h"
20 #include "parse-util.h"
21 #include "string-util.h"
22 #include "strv.h"
23 #include "utf8.h"
24
25 #define VALID_CHARS_ENV_NAME \
26 DIGITS LETTERS \
27 "_"
28
29 #ifndef ARG_MAX
30 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
31 #endif
32
33 static bool env_name_is_valid_n(const char *e, size_t n) {
34 const char *p;
35
36 if (!e)
37 return false;
38
39 if (n <= 0)
40 return false;
41
42 if (e[0] >= '0' && e[0] <= '9')
43 return false;
44
45 /* POSIX says the overall size of the environment block cannot
46 * be > ARG_MAX, an individual assignment hence cannot be
47 * either. Discounting the equal sign and trailing NUL this
48 * hence leaves ARG_MAX-2 as longest possible variable
49 * name. */
50 if (n > ARG_MAX - 2)
51 return false;
52
53 for (p = e; p < e + n; p++)
54 if (!strchr(VALID_CHARS_ENV_NAME, *p))
55 return false;
56
57 return true;
58 }
59
60 bool env_name_is_valid(const char *e) {
61 if (!e)
62 return false;
63
64 return env_name_is_valid_n(e, strlen(e));
65 }
66
67 bool env_value_is_valid(const char *e) {
68 if (!e)
69 return false;
70
71 if (!utf8_is_valid(e))
72 return false;
73
74 /* bash allows tabs and newlines in environment variables, and so
75 * should we */
76 if (string_has_cc(e, "\t\n"))
77 return false;
78
79 /* POSIX says the overall size of the environment block cannot
80 * be > ARG_MAX, an individual assignment hence cannot be
81 * either. Discounting the shortest possible variable name of
82 * length 1, the equal sign and trailing NUL this hence leaves
83 * ARG_MAX-3 as longest possible variable value. */
84 if (strlen(e) > ARG_MAX - 3)
85 return false;
86
87 return true;
88 }
89
90 bool env_assignment_is_valid(const char *e) {
91 const char *eq;
92
93 eq = strchr(e, '=');
94 if (!eq)
95 return false;
96
97 if (!env_name_is_valid_n(e, eq - e))
98 return false;
99
100 if (!env_value_is_valid(eq + 1))
101 return false;
102
103 /* POSIX says the overall size of the environment block cannot
104 * be > ARG_MAX, hence the individual variable assignments
105 * cannot be either, but let's leave room for one trailing NUL
106 * byte. */
107 if (strlen(e) > ARG_MAX - 1)
108 return false;
109
110 return true;
111 }
112
113 bool strv_env_is_valid(char **e) {
114 char **p, **q;
115
116 STRV_FOREACH(p, e) {
117 size_t k;
118
119 if (!env_assignment_is_valid(*p))
120 return false;
121
122 /* Check if there are duplicate assginments */
123 k = strcspn(*p, "=");
124 STRV_FOREACH(q, p + 1)
125 if (strneq(*p, *q, k) && (*q)[k] == '=')
126 return false;
127 }
128
129 return true;
130 }
131
132 bool strv_env_name_is_valid(char **l) {
133 char **p, **q;
134
135 STRV_FOREACH(p, l) {
136 if (!env_name_is_valid(*p))
137 return false;
138
139 STRV_FOREACH(q, p + 1)
140 if (streq(*p, *q))
141 return false;
142 }
143
144 return true;
145 }
146
147 bool strv_env_name_or_assignment_is_valid(char **l) {
148 char **p, **q;
149
150 STRV_FOREACH(p, l) {
151 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
152 return false;
153
154 STRV_FOREACH(q, p + 1)
155 if (streq(*p, *q))
156 return false;
157 }
158
159 return true;
160 }
161
162 static int env_append(char **r, char ***k, char **a) {
163 assert(r);
164 assert(k);
165
166 if (!a)
167 return 0;
168
169 /* Add the entries of a to *k unless they already exist in *r
170 * in which case they are overridden instead. This assumes
171 * there is enough space in the r array. */
172
173 for (; *a; a++) {
174 char **j;
175 size_t n;
176
177 n = strcspn(*a, "=");
178
179 if ((*a)[n] == '=')
180 n++;
181
182 for (j = r; j < *k; j++)
183 if (strneq(*j, *a, n))
184 break;
185
186 if (j >= *k)
187 (*k)++;
188 else
189 free(*j);
190
191 *j = strdup(*a);
192 if (!*j)
193 return -ENOMEM;
194 }
195
196 return 0;
197 }
198
199 char **strv_env_merge(unsigned n_lists, ...) {
200 size_t n = 0;
201 char **l, **k, **r;
202 va_list ap;
203 unsigned i;
204
205 /* Merges an arbitrary number of environment sets */
206
207 va_start(ap, n_lists);
208 for (i = 0; i < n_lists; i++) {
209 l = va_arg(ap, char**);
210 n += strv_length(l);
211 }
212 va_end(ap);
213
214 r = new(char*, n+1);
215 if (!r)
216 return NULL;
217
218 k = r;
219
220 va_start(ap, n_lists);
221 for (i = 0; i < n_lists; i++) {
222 l = va_arg(ap, char**);
223 if (env_append(r, &k, l) < 0)
224 goto fail;
225 }
226 va_end(ap);
227
228 *k = NULL;
229
230 return r;
231
232 fail:
233 va_end(ap);
234 strv_free(r);
235
236 return NULL;
237 }
238
239 static bool env_match(const char *t, const char *pattern) {
240 assert(t);
241 assert(pattern);
242
243 /* pattern a matches string a
244 * a matches a=
245 * a matches a=b
246 * a= matches a=
247 * a=b matches a=b
248 * a= does not match a
249 * a=b does not match a=
250 * a=b does not match a
251 * a=b does not match a=c */
252
253 if (streq(t, pattern))
254 return true;
255
256 if (!strchr(pattern, '=')) {
257 size_t l = strlen(pattern);
258
259 return strneq(t, pattern, l) && t[l] == '=';
260 }
261
262 return false;
263 }
264
265 static bool env_entry_has_name(const char *entry, const char *name) {
266 const char *t;
267
268 assert(entry);
269 assert(name);
270
271 t = startswith(entry, name);
272 if (!t)
273 return false;
274
275 return *t == '=';
276 }
277
278 char **strv_env_delete(char **x, unsigned n_lists, ...) {
279 size_t n, i = 0;
280 char **k, **r;
281 va_list ap;
282
283 /* Deletes every entry from x that is mentioned in the other
284 * string lists */
285
286 n = strv_length(x);
287
288 r = new(char*, n+1);
289 if (!r)
290 return NULL;
291
292 STRV_FOREACH(k, x) {
293 unsigned v;
294
295 va_start(ap, n_lists);
296 for (v = 0; v < n_lists; v++) {
297 char **l, **j;
298
299 l = va_arg(ap, char**);
300 STRV_FOREACH(j, l)
301 if (env_match(*k, *j))
302 goto skip;
303 }
304 va_end(ap);
305
306 r[i] = strdup(*k);
307 if (!r[i]) {
308 strv_free(r);
309 return NULL;
310 }
311
312 i++;
313 continue;
314
315 skip:
316 va_end(ap);
317 }
318
319 r[i] = NULL;
320
321 assert(i <= n);
322
323 return r;
324 }
325
326 char **strv_env_unset(char **l, const char *p) {
327
328 char **f, **t;
329
330 if (!l)
331 return NULL;
332
333 assert(p);
334
335 /* Drops every occurrence of the env var setting p in the
336 * string list. Edits in-place. */
337
338 for (f = t = l; *f; f++) {
339
340 if (env_match(*f, p)) {
341 free(*f);
342 continue;
343 }
344
345 *(t++) = *f;
346 }
347
348 *t = NULL;
349 return l;
350 }
351
352 char **strv_env_unset_many(char **l, ...) {
353
354 char **f, **t;
355
356 if (!l)
357 return NULL;
358
359 /* Like strv_env_unset() but applies many at once. Edits in-place. */
360
361 for (f = t = l; *f; f++) {
362 bool found = false;
363 const char *p;
364 va_list ap;
365
366 va_start(ap, l);
367
368 while ((p = va_arg(ap, const char*))) {
369 if (env_match(*f, p)) {
370 found = true;
371 break;
372 }
373 }
374
375 va_end(ap);
376
377 if (found) {
378 free(*f);
379 continue;
380 }
381
382 *(t++) = *f;
383 }
384
385 *t = NULL;
386 return l;
387 }
388
389 int strv_env_replace(char ***l, char *p) {
390 char **f;
391 const char *t, *name;
392
393 assert(p);
394
395 /* Replace first occurrence of the env var or add a new one in the
396 * string list. Drop other occurences. Edits in-place. Does not copy p.
397 * p must be a valid key=value assignment.
398 */
399
400 t = strchr(p, '=');
401 assert(t);
402
403 name = strndupa(p, t - p);
404
405 for (f = *l; f && *f; f++)
406 if (env_entry_has_name(*f, name)) {
407 free_and_replace(*f, p);
408 strv_env_unset(f + 1, *f);
409 return 0;
410 }
411
412 /* We didn't find a match, we need to append p or create a new strv */
413 if (strv_push(l, p) < 0)
414 return -ENOMEM;
415 return 1;
416 }
417
418 char **strv_env_set(char **x, const char *p) {
419
420 char **k, **r;
421 char* m[2] = { (char*) p, NULL };
422
423 /* Overrides the env var setting of p, returns a new copy */
424
425 r = new(char*, strv_length(x)+2);
426 if (!r)
427 return NULL;
428
429 k = r;
430 if (env_append(r, &k, x) < 0)
431 goto fail;
432
433 if (env_append(r, &k, m) < 0)
434 goto fail;
435
436 *k = NULL;
437
438 return r;
439
440 fail:
441 strv_free(r);
442 return NULL;
443 }
444
445 char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
446 char **i;
447
448 assert(name);
449
450 if (k <= 0)
451 return NULL;
452
453 STRV_FOREACH_BACKWARDS(i, l)
454 if (strneq(*i, name, k) &&
455 (*i)[k] == '=')
456 return *i + k + 1;
457
458 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
459 const char *t;
460
461 t = strndupa(name, k);
462 return getenv(t);
463 };
464
465 return NULL;
466 }
467
468 char *strv_env_get(char **l, const char *name) {
469 assert(name);
470
471 return strv_env_get_n(l, name, strlen(name), 0);
472 }
473
474 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
475 char **p, **q;
476 int k = 0;
477
478 STRV_FOREACH(p, e) {
479 size_t n;
480 bool duplicate = false;
481
482 if (!env_assignment_is_valid(*p)) {
483 if (invalid_callback)
484 invalid_callback(*p, userdata);
485 free(*p);
486 continue;
487 }
488
489 n = strcspn(*p, "=");
490 STRV_FOREACH(q, p + 1)
491 if (strneq(*p, *q, n) && (*q)[n] == '=') {
492 duplicate = true;
493 break;
494 }
495
496 if (duplicate) {
497 free(*p);
498 continue;
499 }
500
501 e[k++] = *p;
502 }
503
504 if (e)
505 e[k] = NULL;
506
507 return e;
508 }
509
510 char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
511 enum {
512 WORD,
513 CURLY,
514 VARIABLE,
515 VARIABLE_RAW,
516 TEST,
517 DEFAULT_VALUE,
518 ALTERNATE_VALUE,
519 } state = WORD;
520
521 const char *e, *word = format, *test_value;
522 char *k;
523 _cleanup_free_ char *r = NULL;
524 size_t i, len;
525 int nest = 0;
526
527 assert(format);
528
529 for (e = format, i = 0; *e && i < n; e ++, i ++)
530 switch (state) {
531
532 case WORD:
533 if (*e == '$')
534 state = CURLY;
535 break;
536
537 case CURLY:
538 if (*e == '{') {
539 k = strnappend(r, word, e-word-1);
540 if (!k)
541 return NULL;
542
543 free_and_replace(r, k);
544
545 word = e-1;
546 state = VARIABLE;
547 nest++;
548 } else if (*e == '$') {
549 k = strnappend(r, word, e-word);
550 if (!k)
551 return NULL;
552
553 free_and_replace(r, k);
554
555 word = e+1;
556 state = WORD;
557
558 } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
559 k = strnappend(r, word, e-word-1);
560 if (!k)
561 return NULL;
562
563 free_and_replace(r, k);
564
565 word = e-1;
566 state = VARIABLE_RAW;
567
568 } else
569 state = WORD;
570 break;
571
572 case VARIABLE:
573 if (*e == '}') {
574 const char *t;
575
576 t = strv_env_get_n(env, word+2, e-word-2, flags);
577
578 k = strappend(r, t);
579 if (!k)
580 return NULL;
581
582 free_and_replace(r, k);
583
584 word = e+1;
585 state = WORD;
586 } else if (*e == ':') {
587 if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
588 /* Treat this as unsupported syntax, i.e. do no replacement */
589 state = WORD;
590 else {
591 len = e-word-2;
592 state = TEST;
593 }
594 }
595 break;
596
597 case TEST:
598 if (*e == '-')
599 state = DEFAULT_VALUE;
600 else if (*e == '+')
601 state = ALTERNATE_VALUE;
602 else {
603 state = WORD;
604 break;
605 }
606
607 test_value = e+1;
608 break;
609
610 case DEFAULT_VALUE: /* fall through */
611 case ALTERNATE_VALUE:
612 assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
613
614 if (*e == '{') {
615 nest++;
616 break;
617 }
618
619 if (*e != '}')
620 break;
621
622 nest--;
623 if (nest == 0) {
624 const char *t;
625 _cleanup_free_ char *v = NULL;
626
627 t = strv_env_get_n(env, word+2, len, flags);
628
629 if (t && state == ALTERNATE_VALUE)
630 t = v = replace_env_n(test_value, e-test_value, env, flags);
631 else if (!t && state == DEFAULT_VALUE)
632 t = v = replace_env_n(test_value, e-test_value, env, flags);
633
634 k = strappend(r, t);
635 if (!k)
636 return NULL;
637
638 free_and_replace(r, k);
639
640 word = e+1;
641 state = WORD;
642 }
643 break;
644
645 case VARIABLE_RAW:
646 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
647
648 if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
649 const char *t;
650
651 t = strv_env_get_n(env, word+1, e-word-1, flags);
652
653 k = strappend(r, t);
654 if (!k)
655 return NULL;
656
657 free_and_replace(r, k);
658
659 word = e--;
660 i--;
661 state = WORD;
662 }
663 break;
664 }
665
666 if (state == VARIABLE_RAW) {
667 const char *t;
668
669 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
670
671 t = strv_env_get_n(env, word+1, e-word-1, flags);
672 return strappend(r, t);
673 } else
674 return strnappend(r, word, e-word);
675 }
676
677 char **replace_env_argv(char **argv, char **env) {
678 char **ret, **i;
679 unsigned k = 0, l = 0;
680
681 l = strv_length(argv);
682
683 ret = new(char*, l+1);
684 if (!ret)
685 return NULL;
686
687 STRV_FOREACH(i, argv) {
688
689 /* If $FOO appears as single word, replace it by the split up variable */
690 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
691 char *e;
692 char **w, **m = NULL;
693 unsigned q;
694
695 e = strv_env_get(env, *i+1);
696 if (e) {
697 int r;
698
699 r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES);
700 if (r < 0) {
701 ret[k] = NULL;
702 strv_free(ret);
703 return NULL;
704 }
705 } else
706 m = NULL;
707
708 q = strv_length(m);
709 l = l + q - 1;
710
711 w = reallocarray(ret, l + 1, sizeof(char *));
712 if (!w) {
713 ret[k] = NULL;
714 strv_free(ret);
715 strv_free(m);
716 return NULL;
717 }
718
719 ret = w;
720 if (m) {
721 memcpy(ret + k, m, q * sizeof(char*));
722 free(m);
723 }
724
725 k += q;
726 continue;
727 }
728
729 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
730 ret[k] = replace_env(*i, env, 0);
731 if (!ret[k]) {
732 strv_free(ret);
733 return NULL;
734 }
735 k++;
736 }
737
738 ret[k] = NULL;
739 return ret;
740 }
741
742 int getenv_bool(const char *p) {
743 const char *e;
744
745 e = getenv(p);
746 if (!e)
747 return -ENXIO;
748
749 return parse_boolean(e);
750 }
751
752 int getenv_bool_secure(const char *p) {
753 const char *e;
754
755 e = secure_getenv(p);
756 if (!e)
757 return -ENXIO;
758
759 return parse_boolean(e);
760 }
761
762 int serialize_environment(FILE *f, char **environment) {
763 char **e;
764
765 STRV_FOREACH(e, environment) {
766 _cleanup_free_ char *ce;
767
768 ce = cescape(*e);
769 if (!ce)
770 return -ENOMEM;
771
772 fprintf(f, "env=%s\n", ce);
773 }
774
775 /* caller should call ferror() */
776
777 return 0;
778 }
779
780 int deserialize_environment(char ***environment, const char *line) {
781 char *uce;
782 int r;
783
784 assert(line);
785 assert(environment);
786
787 assert(startswith(line, "env="));
788 r = cunescape(line + 4, 0, &uce);
789 if (r < 0)
790 return r;
791
792 return strv_env_replace(environment, uce);
793 }