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