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