]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/env-util.c
Merge pull request #33452 from bluca/repart_pkg
[thirdparty/systemd.git] / src / basic / env-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
4d1a6904 2
11c3a366 3#include <errno.h>
4d1a6904 4#include <limits.h>
11c3a366
TA
5#include <stdarg.h>
6#include <stdlib.h>
4d1a6904
LP
7#include <unistd.h>
8
b5efdb8a 9#include "alloc-util.h"
b5efdb8a 10#include "env-util.h"
7c248223 11#include "errno-util.h"
fe902fa4 12#include "escape.h"
11c3a366
TA
13#include "extract-word.h"
14#include "macro.h"
93cc7779 15#include "parse-util.h"
93547f28 16#include "path-util.h"
cfd1c6e2
YW
17#include "process-util.h"
18#include "stdio-util.h"
07630cea 19#include "string-util.h"
4d1a6904 20#include "strv.h"
83b45761 21#include "syslog-util.h"
4d1a6904 22#include "utf8.h"
4d1a6904 23
b45c068d
ZJS
24/* We follow bash for the character set. Different shells have different rules. */
25#define VALID_BASH_ENV_NAME_CHARS \
4b549144 26 DIGITS LETTERS \
4d1a6904
LP
27 "_"
28
b45c068d 29static bool env_name_is_valid_n(const char *e, size_t n) {
2b07147e
LP
30
31 if (n == SIZE_MAX)
32 n = strlen_ptr(e);
4d1a6904
LP
33
34 if (n <= 0)
35 return false;
36
2b07147e
LP
37 assert(e);
38
ff25d338 39 if (ascii_isdigit(e[0]))
ff461576
ZJS
40 return false;
41
2b07147e
LP
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. */
d3e66e68 45 if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
4d1a6904
LP
46 return false;
47
5b935a38 48 for (const char *p = e; p < e + n; p++)
ff461576 49 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
4d1a6904
LP
50 return false;
51
52 return true;
53}
54
55bool env_name_is_valid(const char *e) {
451ae5a1 56 return env_name_is_valid_n(e, strlen_ptr(e));
4d1a6904
LP
57}
58
59bool env_value_is_valid(const char *e) {
60 if (!e)
61 return false;
62
63 if (!utf8_is_valid(e))
64 return false;
65
30927a24
ZJS
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! */
4d1a6904 69
30927a24
ZJS
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. */
21c491e1 73 if (strlen(e) > sc_arg_max() - 3)
4d1a6904
LP
74 return false;
75
76 return true;
77}
78
79bool 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
30927a24
ZJS
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. */
21c491e1 94 if (strlen(e) > sc_arg_max() - 1)
4d1a6904
LP
95 return false;
96
97 return true;
98}
99
100bool strv_env_is_valid(char **e) {
4d1a6904
LP
101 STRV_FOREACH(p, e) {
102 size_t k;
103
104 if (!env_assignment_is_valid(*p))
105 return false;
106
f21f31b2 107 /* Check if there are duplicate assignments */
4d1a6904
LP
108 k = strcspn(*p, "=");
109 STRV_FOREACH(q, p + 1)
641906e9 110 if (strneq(*p, *q, k) && (*q)[k] == '=')
4d1a6904
LP
111 return false;
112 }
113
114 return true;
115}
116
b4c14404 117bool strv_env_name_is_valid(char **l) {
b4c14404
FB
118 STRV_FOREACH(p, l) {
119 if (!env_name_is_valid(*p))
120 return false;
121
68ac147e
LP
122 if (strv_contains(p + 1, *p))
123 return false;
b4c14404
FB
124 }
125
126 return true;
127}
128
123b964a 129bool strv_env_name_or_assignment_is_valid(char **l) {
123b964a
LP
130 STRV_FOREACH(p, l) {
131 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
132 return false;
133
68ac147e
LP
134 if (strv_contains(p + 1, *p))
135 return false;
123b964a
LP
136 }
137
138 return true;
139}
140
5013d6de
DT
141static int env_append(char **e, char ***k, char **a) {
142 assert(e);
4d1a6904 143 assert(k);
5013d6de 144 assert(*k >= e);
4d1a6904
LP
145
146 if (!a)
147 return 0;
148
5013d6de 149 /* Expects the following arguments: 'e' shall point to the beginning of an strv we are going to append to, 'k'
2a13184a
LP
150 * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
151 *
5013d6de 152 * This call adds every entry of 'a' to 'e', either overriding an existing matching entry, or appending to it.
2a13184a 153 *
5013d6de 154 * This call assumes 'e' has enough pre-allocated space to grow by all of 'a''s items. */
4d1a6904
LP
155
156 for (; *a; a++) {
2a13184a 157 char **j, *c;
4d1a6904
LP
158 size_t n;
159
160 n = strcspn(*a, "=");
4d1a6904
LP
161 if ((*a)[n] == '=')
162 n++;
163
5013d6de 164 for (j = e; j < *k; j++)
641906e9 165 if (strneq(*j, *a, n))
4d1a6904
LP
166 break;
167
2a13184a
LP
168 c = strdup(*a);
169 if (!c)
4d1a6904 170 return -ENOMEM;
2a13184a
LP
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 */
4d1a6904
LP
178 }
179
180 return 0;
181}
182
4ab3d29f
ZJS
183char** _strv_env_merge(char **first, ...) {
184 _cleanup_strv_free_ char **merged = NULL;
185 char **k;
4d1a6904 186 va_list ap;
4d1a6904
LP
187
188 /* Merges an arbitrary number of environment sets */
189
4ab3d29f
ZJS
190 size_t n = strv_length(first);
191
192 va_start(ap, first);
193 for (;;) {
194 char **l;
195
4d1a6904 196 l = va_arg(ap, char**);
4ab3d29f
ZJS
197 if (l == POINTER_MAX)
198 break;
199
4d1a6904
LP
200 n += strv_length(l);
201 }
202 va_end(ap);
203
4ab3d29f
ZJS
204 k = merged = new(char*, n + 1);
205 if (!merged)
4d1a6904 206 return NULL;
4ab3d29f 207 merged[0] = NULL;
4d1a6904 208
4ab3d29f
ZJS
209 if (env_append(merged, &k, first) < 0)
210 return NULL;
211
212 va_start(ap, first);
213 for (;;) {
214 char **l;
4d1a6904 215
4d1a6904 216 l = va_arg(ap, char**);
4ab3d29f
ZJS
217 if (l == POINTER_MAX)
218 break;
219
220 if (env_append(merged, &k, l) < 0) {
2d3ff1de
LP
221 va_end(ap);
222 return NULL;
223 }
4d1a6904
LP
224 }
225 va_end(ap);
226
4ab3d29f 227 return TAKE_PTR(merged);
4d1a6904
LP
228}
229
c8cebc36 230static bool env_match(const char *t, const char *pattern) {
4d1a6904
LP
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, '=')) {
aa9ff6c2 248 t = startswith(t, pattern);
4d1a6904 249
aa9ff6c2 250 return t && *t == '=';
4d1a6904
LP
251 }
252
253 return false;
254}
255
99003e01
ZJS
256static 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
da6053d0 269char **strv_env_delete(char **x, size_t n_lists, ...) {
4d1a6904 270 size_t n, i = 0;
5013d6de 271 _cleanup_strv_free_ char **t = NULL;
4d1a6904
LP
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
5013d6de
DT
279 t = new(char*, n+1);
280 if (!t)
4d1a6904
LP
281 return NULL;
282
283 STRV_FOREACH(k, x) {
4d1a6904 284 va_start(ap, n_lists);
5b935a38 285 for (size_t v = 0; v < n_lists; v++) {
de010b0b 286 char **l;
4d1a6904
LP
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
5013d6de
DT
295 t[i] = strdup(*k);
296 if (!t[i])
4d1a6904 297 return NULL;
4d1a6904
LP
298
299 i++;
300 continue;
301
302 skip:
303 va_end(ap);
304 }
305
5013d6de 306 t[i] = NULL;
4d1a6904
LP
307
308 assert(i <= n);
309
5013d6de 310 return TAKE_PTR(t);
4d1a6904
LP
311}
312
9128fd55
MY
313char** strv_env_unset(char **l, const char *p) {
314 assert(p);
4d1a6904
LP
315
316 if (!l)
317 return NULL;
318
4d1a6904 319 /* Drops every occurrence of the env var setting p in the
43d03a83 320 * string list. Edits in-place. */
4d1a6904 321
9128fd55 322 char **f, **t;
4d1a6904 323 for (f = t = l; *f; f++) {
4d1a6904
LP
324 if (env_match(*f, p)) {
325 free(*f);
326 continue;
327 }
328
329 *(t++) = *f;
330 }
43d03a83
LP
331
332 *t = NULL;
333 return l;
334}
335
9128fd55 336char** strv_env_unset_many_internal(char **l, ...) {
43d03a83
LP
337 if (!l)
338 return NULL;
339
340 /* Like strv_env_unset() but applies many at once. Edits in-place. */
341
9128fd55 342 char **f, **t;
43d03a83
LP
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
9128fd55 350 while ((p = va_arg(ap, const char*)))
43d03a83
LP
351 if (env_match(*f, p)) {
352 found = true;
353 break;
354 }
43d03a83
LP
355
356 va_end(ap);
357
358 if (found) {
359 free(*f);
360 continue;
361 }
362
363 *(t++) = *f;
364 }
4d1a6904
LP
365
366 *t = NULL;
367 return l;
368}
369
13734c75 370int strv_env_replace_consume(char ***l, char *p) {
99003e01 371 const char *t, *name;
04effffd 372 int r;
54ac3494
ZJS
373
374 assert(p);
375
aaf057c4 376 /* Replace first occurrence of the env var or add a new one in the string list. Drop other
13734c75
ZJS
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. */
54ac3494 380
99003e01 381 t = strchr(p, '=');
13734c75
ZJS
382 if (!t) {
383 free(p);
04effffd 384 return -EINVAL;
13734c75 385 }
99003e01 386
2f82562b 387 name = strndupa_safe(p, t - p);
99003e01 388
04effffd 389 STRV_FOREACH(f, *l)
99003e01
ZJS
390 if (env_entry_has_name(*f, name)) {
391 free_and_replace(*f, p);
392 strv_env_unset(f + 1, *f);
54ac3494
ZJS
393 return 0;
394 }
395
396 /* We didn't find a match, we need to append p or create a new strv */
13734c75 397 r = strv_consume(l, p);
04effffd
LP
398 if (r < 0)
399 return r;
400
54ac3494
ZJS
401 return 1;
402}
403
aaf057c4 404int strv_env_replace_strdup(char ***l, const char *assignment) {
13734c75 405 /* Like strv_env_replace_consume(), but copies the argument. */
aaf057c4 406
13734c75 407 char *p = strdup(assignment);
aaf057c4
ZJS
408 if (!p)
409 return -ENOMEM;
410
13734c75 411 return strv_env_replace_consume(l, p);
f08231fe
ZJS
412}
413
a14af47e
ZJS
414int 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
f08231fe 440int strv_env_assign(char ***l, const char *key, const char *value) {
f08231fe
ZJS
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
13734c75 455 return strv_env_replace_consume(l, p);
aaf057c4
ZJS
456}
457
20f8b345
LP
458int 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
40975963
YW
487int _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
70e80269 529char* strv_env_get_n(char * const *l, const char *name, size_t k, ReplaceEnvFlags flags) {
4d1a6904
LP
530 assert(name);
531
7658139c 532 if (k == SIZE_MAX)
17ca1517 533 k = strlen(name);
4d1a6904
LP
534 if (k <= 0)
535 return NULL;
536
6162512c 537 STRV_FOREACH_BACKWARDS(i, l)
17ca1517 538 if (strneq(*i, name, k) && (*i)[k] == '=')
70e80269 539 return (char*) *i + k + 1;
4d1a6904 540
37f3ffca
RS
541 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
542 const char *t;
543
10930fbb
LP
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
2f82562b 548 t = strndupa_safe(name, k);
37f3ffca
RS
549 return getenv(t);
550 };
551
4d1a6904
LP
552 return NULL;
553}
554
ff3f2953 555char* strv_env_pairs_get(char **l, const char *name) {
de010b0b 556 char *result = NULL;
42e6a77b
LB
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
039f0e70 567char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
4d1a6904
LP
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)) {
039f0e70
LP
575 if (invalid_callback)
576 invalid_callback(*p, userdata);
4d1a6904
LP
577 free(*p);
578 continue;
579 }
580
581 n = strcspn(*p, "=");
582 STRV_FOREACH(q, p + 1)
641906e9 583 if (strneq(*p, *q, n) && (*q)[n] == '=') {
4d1a6904
LP
584 duplicate = true;
585 break;
586 }
587
588 if (duplicate) {
589 free(*p);
590 continue;
591 }
592
593 e[k++] = *p;
594 }
595
5b4fb02d
LP
596 if (e)
597 e[k] = NULL;
598
4d1a6904
LP
599 return e;
600}
3c800095 601
f331434d
LP
602static 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
612static 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
648int 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
3c800095
RC
657 enum {
658 WORD,
659 CURLY,
ccad1fd0
ZJS
660 VARIABLE,
661 VARIABLE_RAW,
b82f58bf
RS
662 TEST,
663 DEFAULT_VALUE,
664 ALTERNATE_VALUE,
3c800095
RC
665 } state = WORD;
666
f331434d 667 _cleanup_strv_free_ char **unset_variables = NULL, **bad_variables = NULL;
1dbd0bdb 668 const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */
5013d6de 669 _cleanup_free_ char *s = NULL;
f331434d 670 char ***pu, ***pb, *k;
1dbd0bdb 671 size_t i, len = 0; /* len is initialized to appease gcc */
f331434d 672 int nest = 0, r;
3c800095
RC
673
674 assert(format);
675
f331434d
LP
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
b3a9d980 682 for (e = format, i = 0; *e && i < n; e++, i++)
3c800095
RC
683 switch (state) {
684
685 case WORD:
686 if (*e == '$')
687 state = CURLY;
688 break;
689
690 case CURLY:
691 if (*e == '{') {
5013d6de 692 k = strnappend(s, word, e-word-1);
3c800095 693 if (!k)
f331434d 694 return -ENOMEM;
3c800095 695
5013d6de 696 free_and_replace(s, k);
3c800095
RC
697
698 word = e-1;
699 state = VARIABLE;
b82f58bf 700 nest++;
f331434d 701
3c800095 702 } else if (*e == '$') {
5013d6de 703 k = strnappend(s, word, e-word);
3c800095 704 if (!k)
f331434d 705 return -ENOMEM;
3c800095 706
5013d6de 707 free_and_replace(s, k);
3c800095
RC
708
709 word = e+1;
710 state = WORD;
ccad1fd0 711
f331434d 712 } else if (FLAGS_SET(flags, REPLACE_ENV_ALLOW_BRACELESS) && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
5013d6de 713 k = strnappend(s, word, e-word-1);
ccad1fd0 714 if (!k)
f331434d 715 return -ENOMEM;
ccad1fd0 716
5013d6de 717 free_and_replace(s, k);
ccad1fd0
ZJS
718
719 word = e-1;
720 state = VARIABLE_RAW;
721
3c800095
RC
722 } else
723 state = WORD;
724 break;
725
726 case VARIABLE:
727 if (*e == '}') {
f331434d 728 char *t;
3c800095 729
f331434d
LP
730 r = strv_env_get_n_validated(env, word+2, e-word-2, flags, &t, pu, pb);
731 if (r < 0)
732 return r;
3c800095 733
5013d6de 734 if (!strextend(&s, t))
f331434d 735 return -ENOMEM;
3c800095 736
b82f58bf
RS
737 word = e+1;
738 state = WORD;
5ef97a71 739 nest--;
b82f58bf 740 } else if (*e == ':') {
1dbd0bdb
ZJS
741 if (flags & REPLACE_ENV_ALLOW_EXTENDED) {
742 len = e - word - 2;
743 state = TEST;
744 } else
b82f58bf
RS
745 /* Treat this as unsupported syntax, i.e. do no replacement */
746 state = WORD;
b82f58bf
RS
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--;
1d046f57 776 if (nest == 0) {
f331434d 777 _cleanup_strv_free_ char **u = NULL, **b = NULL;
b82f58bf 778 _cleanup_free_ char *v = NULL;
f331434d
LP
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;
b82f58bf 784
f331434d
LP
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;
b82f58bf 789
f331434d
LP
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;
b82f58bf 805
5013d6de 806 if (!strextend(&s, t))
f331434d 807 return -ENOMEM;
b82f58bf 808
3c800095
RC
809 word = e+1;
810 state = WORD;
811 }
812 break;
ccad1fd0
ZJS
813
814 case VARIABLE_RAW:
815 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
816
b45c068d 817 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
f331434d 818 char *t = NULL;
ccad1fd0 819
f331434d
LP
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;
ccad1fd0 823
5013d6de 824 if (!strextend(&s, t))
f331434d 825 return -ENOMEM;
ccad1fd0 826
ccad1fd0 827 word = e--;
4bed076c 828 i--;
ccad1fd0
ZJS
829 state = WORD;
830 }
831 break;
3c800095 832 }
3c800095 833
ccad1fd0 834 if (state == VARIABLE_RAW) {
f331434d 835 char *t;
ccad1fd0
ZJS
836
837 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
838
f331434d
LP
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;
3c800095
RC
858}
859
f331434d
LP
860int 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;
da6053d0 868 size_t k = 0, l = 0;
f331434d 869 int r;
3c800095
RC
870
871 l = strv_length(argv);
872
f331434d
LP
873 n = new(char*, l+1);
874 if (!n)
875 return -ENOMEM;
3c800095
RC
876
877 STRV_FOREACH(i, argv) {
f331434d 878 const char *word = *i;
3c800095
RC
879
880 /* If $FOO appears as single word, replace it by the split up variable */
f331434d 881 if (word[0] == '$' && !IN_SET(word[1], '{', '$')) {
93eceb59 882 _cleanup_strv_free_ char **m = NULL;
f331434d
LP
883 const char *name = word + 1;
884 char *e, **w;
da6053d0 885 size_t q;
3c800095 886
f331434d
LP
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;
3c800095
RC
901
902 q = strv_length(m);
903 l = l + q - 1;
904
f331434d
LP
905 w = reallocarray(n, l + 1, sizeof(char*));
906 if (!w)
907 return -ENOMEM;
3c800095 908
f331434d 909 n = w;
3c800095 910 if (m) {
f331434d 911 memcpy(n + k, m, (q + 1) * sizeof(char*));
93eceb59 912 m = mfree(m);
3c800095
RC
913 }
914
915 k += q;
916 continue;
917 }
918
f331434d
LP
919 _cleanup_strv_free_ char **u = NULL, **b = NULL;
920
3c800095 921 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
f331434d
LP
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) {
e367b426 944 strv_sort_uniq(unset_variables);
f331434d
LP
945 *ret_unset_variables = TAKE_PTR(unset_variables);
946 }
947 if (ret_bad_variables) {
e367b426 948 strv_sort_uniq(bad_variables);
f331434d 949 *ret_bad_variables = TAKE_PTR(bad_variables);
3c800095
RC
950 }
951
f331434d
LP
952 *ret = TAKE_PTR(n);
953 return 0;
3c800095 954}
b41b9d2a
LP
955
956int 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}
fe902fa4 965
efb9b3ba 966int secure_getenv_bool(const char *p) {
71e0accc
ZJS
967 const char *e;
968
969 e = secure_getenv(p);
970 if (!e)
971 return -ENXIO;
972
973 return parse_boolean(e);
974}
063f9f0d 975
dbe253aa 976int secure_getenv_uint64(const char *p, uint64_t *ret) {
3fa8a114
JSMR
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
063f9f0d 988int set_unset_env(const char *name, const char *value, bool overwrite) {
7c248223 989 assert(name);
063f9f0d
ZJS
990
991 if (value)
7c248223
LP
992 return RET_NERRNO(setenv(name, value, overwrite));
993
994 return RET_NERRNO(unsetenv(name));
063f9f0d 995}
cfd1c6e2 996
fa256f43
ZJS
997int putenv_dup(const char *assignment, bool override) {
998 const char *e, *n;
999
1000 e = strchr(assignment, '=');
1001 if (!e)
1002 return -EINVAL;
1003
2f82562b 1004 n = strndupa_safe(assignment, e - assignment);
fa256f43
ZJS
1005
1006 /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
7c248223 1007 return RET_NERRNO(setenv(n, e + 1, override));
fa256f43
ZJS
1008}
1009
cfd1c6e2 1010int setenv_systemd_exec_pid(bool update_only) {
cfd1c6e2 1011 const char *e;
b20e9dc5 1012 int r;
cfd1c6e2
YW
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
b20e9dc5
LP
1023 r = setenvf("SYSTEMD_EXEC_PID", /* overwrite= */ 1, PID_FMT, getpid_cached());
1024 if (r < 0)
1025 return r;
cfd1c6e2
YW
1026
1027 return 1;
1028}
93547f28 1029
83b45761
AV
1030int 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
93547f28
LB
1041int getenv_path_list(const char *name, char ***ret_paths) {
1042 _cleanup_strv_free_ char **l = NULL;
1043 const char *e;
93547f28
LB
1044 int r;
1045
1046 assert(name);
1047 assert(ret_paths);
1048
93547f28
LB
1049 e = secure_getenv(name);
1050 if (!e)
33d31c0e 1051 return -ENXIO;
93547f28
LB
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);
33d31c0e 1076 return 1;
93547f28 1077}
7a6abbe9 1078
e99ca147
LP
1079int getenv_steal_erase(const char *name, char **ret) {
1080 _cleanup_(erase_and_freep) char *a = NULL;
1081 char *e;
7a6abbe9
LP
1082
1083 assert(name);
1084
e99ca147
LP
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;
7a6abbe9 1093 return 0;
e99ca147 1094 }
7a6abbe9 1095
e99ca147
LP
1096 if (ret) {
1097 a = strdup(e);
1098 if (!a)
1099 return -ENOMEM;
1100 }
1101
1102 string_erase(e);
7a6abbe9
LP
1103
1104 if (unsetenv(name) < 0)
1105 return -errno;
1106
e99ca147
LP
1107 if (ret)
1108 *ret = TAKE_PTR(a);
1109
7a6abbe9
LP
1110 return 1;
1111}
58cb36e5
LB
1112
1113int 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}
b20e9dc5
LP
1131
1132int 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);
b20e9dc5 1143 r = vasprintf(&value, valuef, ap);
b20e9dc5
LP
1144 va_end(ap);
1145
1146 if (r < 0)
1147 return -ENOMEM;
1148
1149 return RET_NERRNO(setenv(name, value, overwrite));
1150}