]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/env-util.c
env-util: rename getenv_bool_secure() → secure_getenv_bool()
[thirdparty/systemd.git] / src / basic / env-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <limits.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8
9 #include "alloc-util.h"
10 #include "env-util.h"
11 #include "errno-util.h"
12 #include "escape.h"
13 #include "extract-word.h"
14 #include "macro.h"
15 #include "parse-util.h"
16 #include "path-util.h"
17 #include "process-util.h"
18 #include "stdio-util.h"
19 #include "string-util.h"
20 #include "strv.h"
21 #include "syslog-util.h"
22 #include "utf8.h"
23
24 /* We follow bash for the character set. Different shells have different rules. */
25 #define VALID_BASH_ENV_NAME_CHARS \
26 DIGITS LETTERS \
27 "_"
28
29 static bool env_name_is_valid_n(const char *e, size_t n) {
30
31 if (n == SIZE_MAX)
32 n = strlen_ptr(e);
33
34 if (n <= 0)
35 return false;
36
37 assert(e);
38
39 if (ascii_isdigit(e[0]))
40 return false;
41
42 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
43 * hence cannot be either. Discounting the equal sign and trailing NUL this hence leaves ARG_MAX-2 as
44 * longest possible variable name. */
45 if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
46 return false;
47
48 for (const char *p = e; p < e + n; p++)
49 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
50 return false;
51
52 return true;
53 }
54
55 bool env_name_is_valid(const char *e) {
56 return env_name_is_valid_n(e, strlen_ptr(e));
57 }
58
59 bool env_value_is_valid(const char *e) {
60 if (!e)
61 return false;
62
63 if (!utf8_is_valid(e))
64 return false;
65
66 /* Note that variable *values* may contain control characters, in particular NL, TAB, BS, DEL, ESC…
67 * When printing those variables with show-environment, we'll escape them. Make sure to print
68 * environment variables carefully! */
69
70 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
71 * hence cannot be either. Discounting the shortest possible variable name of length 1, the equal
72 * sign and trailing NUL this hence leaves ARG_MAX-3 as longest possible variable value. */
73 if (strlen(e) > sc_arg_max() - 3)
74 return false;
75
76 return true;
77 }
78
79 bool env_assignment_is_valid(const char *e) {
80 const char *eq;
81
82 eq = strchr(e, '=');
83 if (!eq)
84 return false;
85
86 if (!env_name_is_valid_n(e, eq - e))
87 return false;
88
89 if (!env_value_is_valid(eq + 1))
90 return false;
91
92 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, hence the individual
93 * variable assignments cannot be either, but let's leave room for one trailing NUL byte. */
94 if (strlen(e) > sc_arg_max() - 1)
95 return false;
96
97 return true;
98 }
99
100 bool strv_env_is_valid(char **e) {
101 STRV_FOREACH(p, e) {
102 size_t k;
103
104 if (!env_assignment_is_valid(*p))
105 return false;
106
107 /* Check if there are duplicate assignments */
108 k = strcspn(*p, "=");
109 STRV_FOREACH(q, p + 1)
110 if (strneq(*p, *q, k) && (*q)[k] == '=')
111 return false;
112 }
113
114 return true;
115 }
116
117 bool strv_env_name_is_valid(char **l) {
118 STRV_FOREACH(p, l) {
119 if (!env_name_is_valid(*p))
120 return false;
121
122 if (strv_contains(p + 1, *p))
123 return false;
124 }
125
126 return true;
127 }
128
129 bool strv_env_name_or_assignment_is_valid(char **l) {
130 STRV_FOREACH(p, l) {
131 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
132 return false;
133
134 if (strv_contains(p + 1, *p))
135 return false;
136 }
137
138 return true;
139 }
140
141 static int env_append(char **e, char ***k, char **a) {
142 assert(e);
143 assert(k);
144 assert(*k >= e);
145
146 if (!a)
147 return 0;
148
149 /* Expects the following arguments: 'e' shall point to the beginning of an strv we are going to append to, 'k'
150 * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
151 *
152 * This call adds every entry of 'a' to 'e', either overriding an existing matching entry, or appending to it.
153 *
154 * This call assumes 'e' has enough pre-allocated space to grow by all of 'a''s items. */
155
156 for (; *a; a++) {
157 char **j, *c;
158 size_t n;
159
160 n = strcspn(*a, "=");
161 if ((*a)[n] == '=')
162 n++;
163
164 for (j = e; j < *k; j++)
165 if (strneq(*j, *a, n))
166 break;
167
168 c = strdup(*a);
169 if (!c)
170 return -ENOMEM;
171
172 if (j >= *k) { /* Append to the end? */
173 (*k)[0] = c;
174 (*k)[1] = NULL;
175 (*k)++;
176 } else
177 free_and_replace(*j, c); /* Override existing item */
178 }
179
180 return 0;
181 }
182
183 char** _strv_env_merge(char **first, ...) {
184 _cleanup_strv_free_ char **merged = NULL;
185 char **k;
186 va_list ap;
187
188 /* Merges an arbitrary number of environment sets */
189
190 size_t n = strv_length(first);
191
192 va_start(ap, first);
193 for (;;) {
194 char **l;
195
196 l = va_arg(ap, char**);
197 if (l == POINTER_MAX)
198 break;
199
200 n += strv_length(l);
201 }
202 va_end(ap);
203
204 k = merged = new(char*, n + 1);
205 if (!merged)
206 return NULL;
207 merged[0] = NULL;
208
209 if (env_append(merged, &k, first) < 0)
210 return NULL;
211
212 va_start(ap, first);
213 for (;;) {
214 char **l;
215
216 l = va_arg(ap, char**);
217 if (l == POINTER_MAX)
218 break;
219
220 if (env_append(merged, &k, l) < 0) {
221 va_end(ap);
222 return NULL;
223 }
224 }
225 va_end(ap);
226
227 return TAKE_PTR(merged);
228 }
229
230 static bool env_match(const char *t, const char *pattern) {
231 assert(t);
232 assert(pattern);
233
234 /* pattern a matches string a
235 * a matches a=
236 * a matches a=b
237 * a= matches a=
238 * a=b matches a=b
239 * a= does not match a
240 * a=b does not match a=
241 * a=b does not match a
242 * a=b does not match a=c */
243
244 if (streq(t, pattern))
245 return true;
246
247 if (!strchr(pattern, '=')) {
248 t = startswith(t, pattern);
249
250 return t && *t == '=';
251 }
252
253 return false;
254 }
255
256 static bool env_entry_has_name(const char *entry, const char *name) {
257 const char *t;
258
259 assert(entry);
260 assert(name);
261
262 t = startswith(entry, name);
263 if (!t)
264 return false;
265
266 return *t == '=';
267 }
268
269 char **strv_env_delete(char **x, size_t n_lists, ...) {
270 size_t n, i = 0;
271 _cleanup_strv_free_ char **t = NULL;
272 va_list ap;
273
274 /* Deletes every entry from x that is mentioned in the other
275 * string lists */
276
277 n = strv_length(x);
278
279 t = new(char*, n+1);
280 if (!t)
281 return NULL;
282
283 STRV_FOREACH(k, x) {
284 va_start(ap, n_lists);
285 for (size_t v = 0; v < n_lists; v++) {
286 char **l;
287
288 l = va_arg(ap, char**);
289 STRV_FOREACH(j, l)
290 if (env_match(*k, *j))
291 goto skip;
292 }
293 va_end(ap);
294
295 t[i] = strdup(*k);
296 if (!t[i])
297 return NULL;
298
299 i++;
300 continue;
301
302 skip:
303 va_end(ap);
304 }
305
306 t[i] = NULL;
307
308 assert(i <= n);
309
310 return TAKE_PTR(t);
311 }
312
313 char** strv_env_unset(char **l, const char *p) {
314 assert(p);
315
316 if (!l)
317 return NULL;
318
319 /* Drops every occurrence of the env var setting p in the
320 * string list. Edits in-place. */
321
322 char **f, **t;
323 for (f = t = l; *f; f++) {
324 if (env_match(*f, p)) {
325 free(*f);
326 continue;
327 }
328
329 *(t++) = *f;
330 }
331
332 *t = NULL;
333 return l;
334 }
335
336 char** strv_env_unset_many_internal(char **l, ...) {
337 if (!l)
338 return NULL;
339
340 /* Like strv_env_unset() but applies many at once. Edits in-place. */
341
342 char **f, **t;
343 for (f = t = l; *f; f++) {
344 bool found = false;
345 const char *p;
346 va_list ap;
347
348 va_start(ap, l);
349
350 while ((p = va_arg(ap, const char*)))
351 if (env_match(*f, p)) {
352 found = true;
353 break;
354 }
355
356 va_end(ap);
357
358 if (found) {
359 free(*f);
360 continue;
361 }
362
363 *(t++) = *f;
364 }
365
366 *t = NULL;
367 return l;
368 }
369
370 int strv_env_replace_consume(char ***l, char *p) {
371 const char *t, *name;
372 int r;
373
374 assert(p);
375
376 /* Replace first occurrence of the env var or add a new one in the string list. Drop other
377 * occurrences. Edits in-place. Does not copy p and CONSUMES p EVEN ON FAILURE.
378 *
379 * p must be a valid key=value assignment. */
380
381 t = strchr(p, '=');
382 if (!t) {
383 free(p);
384 return -EINVAL;
385 }
386
387 name = strndupa_safe(p, t - p);
388
389 STRV_FOREACH(f, *l)
390 if (env_entry_has_name(*f, name)) {
391 free_and_replace(*f, p);
392 strv_env_unset(f + 1, *f);
393 return 0;
394 }
395
396 /* We didn't find a match, we need to append p or create a new strv */
397 r = strv_consume(l, p);
398 if (r < 0)
399 return r;
400
401 return 1;
402 }
403
404 int strv_env_replace_strdup(char ***l, const char *assignment) {
405 /* Like strv_env_replace_consume(), but copies the argument. */
406
407 char *p = strdup(assignment);
408 if (!p)
409 return -ENOMEM;
410
411 return strv_env_replace_consume(l, p);
412 }
413
414 int strv_env_replace_strdup_passthrough(char ***l, const char *assignment) {
415 /* Like strv_env_replace_strdup(), but pulls the variable from the environment of
416 * the calling program, if a variable name without value is specified.
417 */
418 char *p;
419
420 if (strchr(assignment, '=')) {
421 if (!env_assignment_is_valid(assignment))
422 return -EINVAL;
423
424 p = strdup(assignment);
425 } else {
426 if (!env_name_is_valid(assignment))
427 return -EINVAL;
428
429 /* If we can't find the variable in our environment, we will use
430 * the empty string. This way "passthrough" is equivalent to passing
431 * --setenv=FOO=$FOO in the shell. */
432 p = strjoin(assignment, "=", secure_getenv(assignment));
433 }
434 if (!p)
435 return -ENOMEM;
436
437 return strv_env_replace_consume(l, p);
438 }
439
440 int strv_env_assign(char ***l, const char *key, const char *value) {
441 if (!env_name_is_valid(key))
442 return -EINVAL;
443
444 /* NULL removes assignment, "" creates an empty assignment. */
445
446 if (!value) {
447 strv_env_unset(*l, key);
448 return 0;
449 }
450
451 char *p = strjoin(key, "=", value);
452 if (!p)
453 return -ENOMEM;
454
455 return strv_env_replace_consume(l, p);
456 }
457
458 int strv_env_assignf(char ***l, const char *key, const char *valuef, ...) {
459 int r;
460
461 assert(l);
462 assert(key);
463
464 if (!env_name_is_valid(key))
465 return -EINVAL;
466
467 if (!valuef) {
468 strv_env_unset(*l, key);
469 return 0;
470 }
471
472 _cleanup_free_ char *value = NULL;
473 va_list ap;
474 va_start(ap, valuef);
475 r = vasprintf(&value, valuef, ap);
476 va_end(ap);
477 if (r < 0)
478 return -ENOMEM;
479
480 char *p = strjoin(key, "=", value);
481 if (!p)
482 return -ENOMEM;
483
484 return strv_env_replace_consume(l, p);
485 }
486
487 int _strv_env_assign_many(char ***l, ...) {
488 va_list ap;
489 int r;
490
491 assert(l);
492
493 va_start(ap, l);
494 for (;;) {
495 const char *key, *value;
496
497 key = va_arg(ap, const char *);
498 if (!key)
499 break;
500
501 if (!env_name_is_valid(key)) {
502 va_end(ap);
503 return -EINVAL;
504 }
505
506 value = va_arg(ap, const char *);
507 if (!value) {
508 strv_env_unset(*l, key);
509 continue;
510 }
511
512 char *p = strjoin(key, "=", value);
513 if (!p) {
514 va_end(ap);
515 return -ENOMEM;
516 }
517
518 r = strv_env_replace_consume(l, p);
519 if (r < 0) {
520 va_end(ap);
521 return r;
522 }
523 }
524 va_end(ap);
525
526 return 0;
527 }
528
529 char* strv_env_get_n(char * const *l, const char *name, size_t k, ReplaceEnvFlags flags) {
530 assert(name);
531
532 if (k == SIZE_MAX)
533 k = strlen(name);
534 if (k <= 0)
535 return NULL;
536
537 STRV_FOREACH_BACKWARDS(i, l)
538 if (strneq(*i, name, k) && (*i)[k] == '=')
539 return (char*) *i + k + 1;
540
541 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
542 const char *t;
543
544 /* Safety check that the name is not overly long, before we do a stack allocation */
545 if (k > (size_t) sysconf(_SC_ARG_MAX) - 2)
546 return NULL;
547
548 t = strndupa_safe(name, k);
549 return getenv(t);
550 };
551
552 return NULL;
553 }
554
555 char *strv_env_pairs_get(char **l, const char *name) {
556 char *result = NULL;
557
558 assert(name);
559
560 STRV_FOREACH_PAIR(key, value, l)
561 if (streq(*key, name))
562 result = *value;
563
564 return result;
565 }
566
567 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
568 int k = 0;
569
570 STRV_FOREACH(p, e) {
571 size_t n;
572 bool duplicate = false;
573
574 if (!env_assignment_is_valid(*p)) {
575 if (invalid_callback)
576 invalid_callback(*p, userdata);
577 free(*p);
578 continue;
579 }
580
581 n = strcspn(*p, "=");
582 STRV_FOREACH(q, p + 1)
583 if (strneq(*p, *q, n) && (*q)[n] == '=') {
584 duplicate = true;
585 break;
586 }
587
588 if (duplicate) {
589 free(*p);
590 continue;
591 }
592
593 e[k++] = *p;
594 }
595
596 if (e)
597 e[k] = NULL;
598
599 return e;
600 }
601
602 static int strv_extend_with_length(char ***l, const char *s, size_t n) {
603 char *c;
604
605 c = strndup(s, n);
606 if (!c)
607 return -ENOMEM;
608
609 return strv_consume(l, c);
610 }
611
612 static int strv_env_get_n_validated(
613 char **env,
614 const char *name,
615 size_t l,
616 ReplaceEnvFlags flags,
617 char **ret, /* points into the env block! do not free! */
618 char ***unset_variables, /* updated in place */
619 char ***bad_variables) { /* ditto */
620
621 char *e;
622 int r;
623
624 assert(l == 0 || name);
625 assert(ret);
626
627 if (env_name_is_valid_n(name, l)) {
628 e = strv_env_get_n(env, name, l, flags);
629 if (!e && unset_variables) {
630 r = strv_extend_with_length(unset_variables, name, l);
631 if (r < 0)
632 return r;
633 }
634 } else {
635 e = NULL; /* Resolve invalid variable names the same way as unset ones */
636
637 if (bad_variables) {
638 r = strv_extend_with_length(bad_variables, name, l);
639 if (r < 0)
640 return r;
641 }
642 }
643
644 *ret = e;
645 return !!e;
646 }
647
648 int replace_env_full(
649 const char *format,
650 size_t n,
651 char **env,
652 ReplaceEnvFlags flags,
653 char **ret,
654 char ***ret_unset_variables,
655 char ***ret_bad_variables) {
656
657 enum {
658 WORD,
659 CURLY,
660 VARIABLE,
661 VARIABLE_RAW,
662 TEST,
663 DEFAULT_VALUE,
664 ALTERNATE_VALUE,
665 } state = WORD;
666
667 _cleanup_strv_free_ char **unset_variables = NULL, **bad_variables = NULL;
668 const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */
669 _cleanup_free_ char *s = NULL;
670 char ***pu, ***pb, *k;
671 size_t i, len = 0; /* len is initialized to appease gcc */
672 int nest = 0, r;
673
674 assert(format);
675
676 if (n == SIZE_MAX)
677 n = strlen(format);
678
679 pu = ret_unset_variables ? &unset_variables : NULL;
680 pb = ret_bad_variables ? &bad_variables : NULL;
681
682 for (e = format, i = 0; *e && i < n; e++, i++)
683 switch (state) {
684
685 case WORD:
686 if (*e == '$')
687 state = CURLY;
688 break;
689
690 case CURLY:
691 if (*e == '{') {
692 k = strnappend(s, word, e-word-1);
693 if (!k)
694 return -ENOMEM;
695
696 free_and_replace(s, k);
697
698 word = e-1;
699 state = VARIABLE;
700 nest++;
701
702 } else if (*e == '$') {
703 k = strnappend(s, word, e-word);
704 if (!k)
705 return -ENOMEM;
706
707 free_and_replace(s, k);
708
709 word = e+1;
710 state = WORD;
711
712 } else if (FLAGS_SET(flags, REPLACE_ENV_ALLOW_BRACELESS) && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
713 k = strnappend(s, word, e-word-1);
714 if (!k)
715 return -ENOMEM;
716
717 free_and_replace(s, k);
718
719 word = e-1;
720 state = VARIABLE_RAW;
721
722 } else
723 state = WORD;
724 break;
725
726 case VARIABLE:
727 if (*e == '}') {
728 char *t;
729
730 r = strv_env_get_n_validated(env, word+2, e-word-2, flags, &t, pu, pb);
731 if (r < 0)
732 return r;
733
734 if (!strextend(&s, t))
735 return -ENOMEM;
736
737 word = e+1;
738 state = WORD;
739 nest--;
740 } else if (*e == ':') {
741 if (flags & REPLACE_ENV_ALLOW_EXTENDED) {
742 len = e - word - 2;
743 state = TEST;
744 } else
745 /* Treat this as unsupported syntax, i.e. do no replacement */
746 state = WORD;
747 }
748 break;
749
750 case TEST:
751 if (*e == '-')
752 state = DEFAULT_VALUE;
753 else if (*e == '+')
754 state = ALTERNATE_VALUE;
755 else {
756 state = WORD;
757 break;
758 }
759
760 test_value = e+1;
761 break;
762
763 case DEFAULT_VALUE: /* fall through */
764 case ALTERNATE_VALUE:
765 assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
766
767 if (*e == '{') {
768 nest++;
769 break;
770 }
771
772 if (*e != '}')
773 break;
774
775 nest--;
776 if (nest == 0) {
777 _cleanup_strv_free_ char **u = NULL, **b = NULL;
778 _cleanup_free_ char *v = NULL;
779 char *t = NULL;
780
781 r = strv_env_get_n_validated(env, word+2, len, flags, &t, pu, pb);
782 if (r < 0)
783 return r;
784
785 if (t && state == ALTERNATE_VALUE) {
786 r = replace_env_full(test_value, e-test_value, env, flags, &v, pu ? &u : NULL, pb ? &b : NULL);
787 if (r < 0)
788 return r;
789
790 t = v;
791 } else if (!t && state == DEFAULT_VALUE) {
792 r = replace_env_full(test_value, e-test_value, env, flags, &v, pu ? &u : NULL, pb ? &b : NULL);
793 if (r < 0)
794 return r;
795
796 t = v;
797 }
798
799 r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
800 if (r < 0)
801 return r;
802 r = strv_extend_strv(&bad_variables, b, /* filter_duplicates= */ true);
803 if (r < 0)
804 return r;
805
806 if (!strextend(&s, t))
807 return -ENOMEM;
808
809 word = e+1;
810 state = WORD;
811 }
812 break;
813
814 case VARIABLE_RAW:
815 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
816
817 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
818 char *t = NULL;
819
820 r = strv_env_get_n_validated(env, word+1, e-word-1, flags, &t, &unset_variables, &bad_variables);
821 if (r < 0)
822 return r;
823
824 if (!strextend(&s, t))
825 return -ENOMEM;
826
827 word = e--;
828 i--;
829 state = WORD;
830 }
831 break;
832 }
833
834 if (state == VARIABLE_RAW) {
835 char *t;
836
837 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
838
839 r = strv_env_get_n_validated(env, word+1, e-word-1, flags, &t, &unset_variables, &bad_variables);
840 if (r < 0)
841 return r;
842
843 if (!strextend(&s, t))
844 return -ENOMEM;
845
846 } else if (!strextendn(&s, word, e-word))
847 return -ENOMEM;
848
849 if (ret_unset_variables)
850 *ret_unset_variables = TAKE_PTR(unset_variables);
851 if (ret_bad_variables)
852 *ret_bad_variables = TAKE_PTR(bad_variables);
853
854 if (ret)
855 *ret = TAKE_PTR(s);
856
857 return 0;
858 }
859
860 int replace_env_argv(
861 char **argv,
862 char **env,
863 char ***ret,
864 char ***ret_unset_variables,
865 char ***ret_bad_variables) {
866
867 _cleanup_strv_free_ char **n = NULL, **unset_variables = NULL, **bad_variables = NULL;
868 size_t k = 0, l = 0;
869 int r;
870
871 l = strv_length(argv);
872
873 n = new(char*, l+1);
874 if (!n)
875 return -ENOMEM;
876
877 STRV_FOREACH(i, argv) {
878 const char *word = *i;
879
880 /* If $FOO appears as single word, replace it by the split up variable */
881 if (word[0] == '$' && !IN_SET(word[1], '{', '$')) {
882 _cleanup_strv_free_ char **m = NULL;
883 const char *name = word + 1;
884 char *e, **w;
885 size_t q;
886
887 if (env_name_is_valid(name)) {
888 e = strv_env_get(env, name);
889 if (e)
890 r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
891 else if (ret_unset_variables)
892 r = strv_extend(&unset_variables, name);
893 else
894 r = 0;
895 } else if (ret_bad_variables)
896 r = strv_extend(&bad_variables, name);
897 else
898 r = 0;
899 if (r < 0)
900 return r;
901
902 q = strv_length(m);
903 l = l + q - 1;
904
905 w = reallocarray(n, l + 1, sizeof(char*));
906 if (!w)
907 return -ENOMEM;
908
909 n = w;
910 if (m) {
911 memcpy(n + k, m, (q + 1) * sizeof(char*));
912 m = mfree(m);
913 }
914
915 k += q;
916 continue;
917 }
918
919 _cleanup_strv_free_ char **u = NULL, **b = NULL;
920
921 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
922 r = replace_env_full(
923 word,
924 /* length= */ SIZE_MAX,
925 env,
926 /* flags= */ 0,
927 n + k,
928 ret_unset_variables ? &u : NULL,
929 ret_bad_variables ? &b : NULL);
930 if (r < 0)
931 return r;
932 n[++k] = NULL;
933
934 r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
935 if (r < 0)
936 return r;
937
938 r = strv_extend_strv(&bad_variables, b, /*filter_duplicates= */ true);
939 if (r < 0)
940 return r;
941 }
942
943 if (ret_unset_variables) {
944 strv_uniq(strv_sort(unset_variables));
945 *ret_unset_variables = TAKE_PTR(unset_variables);
946 }
947 if (ret_bad_variables) {
948 strv_uniq(strv_sort(bad_variables));
949 *ret_bad_variables = TAKE_PTR(bad_variables);
950 }
951
952 *ret = TAKE_PTR(n);
953 return 0;
954 }
955
956 int getenv_bool(const char *p) {
957 const char *e;
958
959 e = getenv(p);
960 if (!e)
961 return -ENXIO;
962
963 return parse_boolean(e);
964 }
965
966 int secure_getenv_bool(const char *p) {
967 const char *e;
968
969 e = secure_getenv(p);
970 if (!e)
971 return -ENXIO;
972
973 return parse_boolean(e);
974 }
975
976 int getenv_uint64_secure(const char *p, uint64_t *ret) {
977 const char *e;
978
979 assert(p);
980
981 e = secure_getenv(p);
982 if (!e)
983 return -ENXIO;
984
985 return safe_atou64(e, ret);
986 }
987
988 int set_unset_env(const char *name, const char *value, bool overwrite) {
989 assert(name);
990
991 if (value)
992 return RET_NERRNO(setenv(name, value, overwrite));
993
994 return RET_NERRNO(unsetenv(name));
995 }
996
997 int putenv_dup(const char *assignment, bool override) {
998 const char *e, *n;
999
1000 e = strchr(assignment, '=');
1001 if (!e)
1002 return -EINVAL;
1003
1004 n = strndupa_safe(assignment, e - assignment);
1005
1006 /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
1007 return RET_NERRNO(setenv(n, e + 1, override));
1008 }
1009
1010 int setenv_systemd_exec_pid(bool update_only) {
1011 const char *e;
1012 int r;
1013
1014 /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
1015
1016 e = secure_getenv("SYSTEMD_EXEC_PID");
1017 if (!e && update_only)
1018 return 0;
1019
1020 if (streq_ptr(e, "*"))
1021 return 0;
1022
1023 r = setenvf("SYSTEMD_EXEC_PID", /* overwrite= */ 1, PID_FMT, getpid_cached());
1024 if (r < 0)
1025 return r;
1026
1027 return 1;
1028 }
1029
1030 int setenv_systemd_log_level(void) {
1031 _cleanup_free_ char *val = NULL;
1032 int r;
1033
1034 r = log_level_to_string_alloc(log_get_max_level(), &val);
1035 if (r < 0)
1036 return r;
1037
1038 return RET_NERRNO(setenv("SYSTEMD_LOG_LEVEL", val, /* overwrite= */ true));
1039 }
1040
1041 int getenv_path_list(const char *name, char ***ret_paths) {
1042 _cleanup_strv_free_ char **l = NULL;
1043 const char *e;
1044 int r;
1045
1046 assert(name);
1047 assert(ret_paths);
1048
1049 e = secure_getenv(name);
1050 if (!e)
1051 return -ENXIO;
1052
1053 r = strv_split_full(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1054 if (r < 0)
1055 return log_debug_errno(r, "Failed to parse $%s: %m", name);
1056
1057 STRV_FOREACH(p, l) {
1058 if (!path_is_absolute(*p))
1059 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
1060 "Path '%s' is not absolute, refusing.", *p);
1061
1062 if (!path_is_normalized(*p))
1063 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
1064 "Path '%s' is not normalized, refusing.", *p);
1065
1066 if (path_equal(*p, "/"))
1067 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
1068 "Path '%s' is the root fs, refusing.", *p);
1069 }
1070
1071 if (strv_isempty(l))
1072 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
1073 "No paths specified, refusing.");
1074
1075 *ret_paths = TAKE_PTR(l);
1076 return 1;
1077 }
1078
1079 int getenv_steal_erase(const char *name, char **ret) {
1080 _cleanup_(erase_and_freep) char *a = NULL;
1081 char *e;
1082
1083 assert(name);
1084
1085 /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes
1086 * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for
1087 * testing, and given that people are likely going to misuse this, be thorough) */
1088
1089 e = getenv(name);
1090 if (!e) {
1091 if (ret)
1092 *ret = NULL;
1093 return 0;
1094 }
1095
1096 if (ret) {
1097 a = strdup(e);
1098 if (!a)
1099 return -ENOMEM;
1100 }
1101
1102 string_erase(e);
1103
1104 if (unsetenv(name) < 0)
1105 return -errno;
1106
1107 if (ret)
1108 *ret = TAKE_PTR(a);
1109
1110 return 1;
1111 }
1112
1113 int set_full_environment(char **env) {
1114 int r;
1115
1116 clearenv();
1117
1118 STRV_FOREACH(e, env) {
1119 _cleanup_free_ char *k = NULL, *v = NULL;
1120
1121 r = split_pair(*e, "=", &k, &v);
1122 if (r < 0)
1123 return r;
1124
1125 if (setenv(k, v, /* overwrite= */ true) < 0)
1126 return -errno;
1127 }
1128
1129 return 0;
1130 }
1131
1132 int setenvf(const char *name, bool overwrite, const char *valuef, ...) {
1133 _cleanup_free_ char *value = NULL;
1134 va_list ap;
1135 int r;
1136
1137 assert(name);
1138
1139 if (!valuef)
1140 return RET_NERRNO(unsetenv(name));
1141
1142 va_start(ap, valuef);
1143 DISABLE_WARNING_FORMAT_NONLITERAL;
1144 r = vasprintf(&value, valuef, ap);
1145 REENABLE_WARNING;
1146 va_end(ap);
1147
1148 if (r < 0)
1149 return -ENOMEM;
1150
1151 return RET_NERRNO(setenv(name, value, overwrite));
1152 }