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