]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/env-util.c
env-util: modernize env_name_is_valid_n() a bit
[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
LP
20#include "strv.h"
21#include "utf8.h"
4d1a6904 22
b45c068d
ZJS
23/* We follow bash for the character set. Different shells have different rules. */
24#define VALID_BASH_ENV_NAME_CHARS \
4b549144 25 DIGITS LETTERS \
4d1a6904
LP
26 "_"
27
b45c068d 28static bool env_name_is_valid_n(const char *e, size_t n) {
2b07147e
LP
29
30 if (n == SIZE_MAX)
31 n = strlen_ptr(e);
4d1a6904
LP
32
33 if (n <= 0)
34 return false;
35
2b07147e
LP
36 assert(e);
37
ff25d338 38 if (ascii_isdigit(e[0]))
ff461576
ZJS
39 return false;
40
2b07147e
LP
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. */
d3e66e68 44 if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
4d1a6904
LP
45 return false;
46
5b935a38 47 for (const char *p = e; p < e + n; p++)
ff461576 48 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p))
4d1a6904
LP
49 return false;
50
51 return true;
52}
53
54bool env_name_is_valid(const char *e) {
451ae5a1 55 return env_name_is_valid_n(e, strlen_ptr(e));
4d1a6904
LP
56}
57
58bool env_value_is_valid(const char *e) {
59 if (!e)
60 return false;
61
62 if (!utf8_is_valid(e))
63 return false;
64
30927a24
ZJS
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! */
4d1a6904 68
30927a24
ZJS
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. */
21c491e1 72 if (strlen(e) > sc_arg_max() - 3)
4d1a6904
LP
73 return false;
74
75 return true;
76}
77
78bool 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
30927a24
ZJS
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. */
21c491e1 93 if (strlen(e) > sc_arg_max() - 1)
4d1a6904
LP
94 return false;
95
96 return true;
97}
98
99bool strv_env_is_valid(char **e) {
4d1a6904
LP
100 STRV_FOREACH(p, e) {
101 size_t k;
102
103 if (!env_assignment_is_valid(*p))
104 return false;
105
f21f31b2 106 /* Check if there are duplicate assignments */
4d1a6904
LP
107 k = strcspn(*p, "=");
108 STRV_FOREACH(q, p + 1)
641906e9 109 if (strneq(*p, *q, k) && (*q)[k] == '=')
4d1a6904
LP
110 return false;
111 }
112
113 return true;
114}
115
b4c14404 116bool strv_env_name_is_valid(char **l) {
b4c14404
FB
117 STRV_FOREACH(p, l) {
118 if (!env_name_is_valid(*p))
119 return false;
120
68ac147e
LP
121 if (strv_contains(p + 1, *p))
122 return false;
b4c14404
FB
123 }
124
125 return true;
126}
127
123b964a 128bool strv_env_name_or_assignment_is_valid(char **l) {
123b964a
LP
129 STRV_FOREACH(p, l) {
130 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
131 return false;
132
68ac147e
LP
133 if (strv_contains(p + 1, *p))
134 return false;
123b964a
LP
135 }
136
137 return true;
138}
139
5013d6de
DT
140static int env_append(char **e, char ***k, char **a) {
141 assert(e);
4d1a6904 142 assert(k);
5013d6de 143 assert(*k >= e);
4d1a6904
LP
144
145 if (!a)
146 return 0;
147
5013d6de 148 /* Expects the following arguments: 'e' shall point to the beginning of an strv we are going to append to, 'k'
2a13184a
LP
149 * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
150 *
5013d6de 151 * This call adds every entry of 'a' to 'e', either overriding an existing matching entry, or appending to it.
2a13184a 152 *
5013d6de 153 * This call assumes 'e' has enough pre-allocated space to grow by all of 'a''s items. */
4d1a6904
LP
154
155 for (; *a; a++) {
2a13184a 156 char **j, *c;
4d1a6904
LP
157 size_t n;
158
159 n = strcspn(*a, "=");
4d1a6904
LP
160 if ((*a)[n] == '=')
161 n++;
162
5013d6de 163 for (j = e; j < *k; j++)
641906e9 164 if (strneq(*j, *a, n))
4d1a6904
LP
165 break;
166
2a13184a
LP
167 c = strdup(*a);
168 if (!c)
4d1a6904 169 return -ENOMEM;
2a13184a
LP
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 */
4d1a6904
LP
177 }
178
179 return 0;
180}
181
4ab3d29f
ZJS
182char** _strv_env_merge(char **first, ...) {
183 _cleanup_strv_free_ char **merged = NULL;
184 char **k;
4d1a6904 185 va_list ap;
4d1a6904
LP
186
187 /* Merges an arbitrary number of environment sets */
188
4ab3d29f
ZJS
189 size_t n = strv_length(first);
190
191 va_start(ap, first);
192 for (;;) {
193 char **l;
194
4d1a6904 195 l = va_arg(ap, char**);
4ab3d29f
ZJS
196 if (l == POINTER_MAX)
197 break;
198
4d1a6904
LP
199 n += strv_length(l);
200 }
201 va_end(ap);
202
4ab3d29f
ZJS
203 k = merged = new(char*, n + 1);
204 if (!merged)
4d1a6904 205 return NULL;
4ab3d29f 206 merged[0] = NULL;
4d1a6904 207
4ab3d29f
ZJS
208 if (env_append(merged, &k, first) < 0)
209 return NULL;
210
211 va_start(ap, first);
212 for (;;) {
213 char **l;
4d1a6904 214
4d1a6904 215 l = va_arg(ap, char**);
4ab3d29f
ZJS
216 if (l == POINTER_MAX)
217 break;
218
219 if (env_append(merged, &k, l) < 0) {
2d3ff1de
LP
220 va_end(ap);
221 return NULL;
222 }
4d1a6904
LP
223 }
224 va_end(ap);
225
4ab3d29f 226 return TAKE_PTR(merged);
4d1a6904
LP
227}
228
c8cebc36 229static bool env_match(const char *t, const char *pattern) {
4d1a6904
LP
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
641906e9 249 return strneq(t, pattern, l) && t[l] == '=';
4d1a6904
LP
250 }
251
252 return false;
253}
254
99003e01
ZJS
255static 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
da6053d0 268char **strv_env_delete(char **x, size_t n_lists, ...) {
4d1a6904 269 size_t n, i = 0;
5013d6de 270 _cleanup_strv_free_ char **t = NULL;
4d1a6904
LP
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
5013d6de
DT
278 t = new(char*, n+1);
279 if (!t)
4d1a6904
LP
280 return NULL;
281
282 STRV_FOREACH(k, x) {
4d1a6904 283 va_start(ap, n_lists);
5b935a38 284 for (size_t v = 0; v < n_lists; v++) {
de010b0b 285 char **l;
4d1a6904
LP
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
5013d6de
DT
294 t[i] = strdup(*k);
295 if (!t[i])
4d1a6904 296 return NULL;
4d1a6904
LP
297
298 i++;
299 continue;
300
301 skip:
302 va_end(ap);
303 }
304
5013d6de 305 t[i] = NULL;
4d1a6904
LP
306
307 assert(i <= n);
308
5013d6de 309 return TAKE_PTR(t);
4d1a6904
LP
310}
311
312char **strv_env_unset(char **l, const char *p) {
4d1a6904
LP
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
43d03a83 321 * string list. Edits in-place. */
4d1a6904
LP
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 }
43d03a83
LP
332
333 *t = NULL;
334 return l;
335}
336
337char **strv_env_unset_many(char **l, ...) {
43d03a83
LP
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 }
4d1a6904
LP
368
369 *t = NULL;
370 return l;
371}
372
13734c75 373int strv_env_replace_consume(char ***l, char *p) {
99003e01 374 const char *t, *name;
04effffd 375 int r;
54ac3494
ZJS
376
377 assert(p);
378
aaf057c4 379 /* Replace first occurrence of the env var or add a new one in the string list. Drop other
13734c75
ZJS
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. */
54ac3494 383
99003e01 384 t = strchr(p, '=');
13734c75
ZJS
385 if (!t) {
386 free(p);
04effffd 387 return -EINVAL;
13734c75 388 }
99003e01 389
2f82562b 390 name = strndupa_safe(p, t - p);
99003e01 391
04effffd 392 STRV_FOREACH(f, *l)
99003e01
ZJS
393 if (env_entry_has_name(*f, name)) {
394 free_and_replace(*f, p);
395 strv_env_unset(f + 1, *f);
54ac3494
ZJS
396 return 0;
397 }
398
399 /* We didn't find a match, we need to append p or create a new strv */
13734c75 400 r = strv_consume(l, p);
04effffd
LP
401 if (r < 0)
402 return r;
403
54ac3494
ZJS
404 return 1;
405}
406
aaf057c4 407int strv_env_replace_strdup(char ***l, const char *assignment) {
13734c75 408 /* Like strv_env_replace_consume(), but copies the argument. */
aaf057c4 409
13734c75 410 char *p = strdup(assignment);
aaf057c4
ZJS
411 if (!p)
412 return -ENOMEM;
413
13734c75 414 return strv_env_replace_consume(l, p);
f08231fe
ZJS
415}
416
a14af47e
ZJS
417int 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
f08231fe 443int strv_env_assign(char ***l, const char *key, const char *value) {
f08231fe
ZJS
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
13734c75 458 return strv_env_replace_consume(l, p);
aaf057c4
ZJS
459}
460
40975963
YW
461int _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
37f3ffca 503char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
4d1a6904
LP
504 assert(name);
505
506 if (k <= 0)
507 return NULL;
508
6162512c 509 STRV_FOREACH_BACKWARDS(i, l)
641906e9 510 if (strneq(*i, name, k) &&
4d1a6904
LP
511 (*i)[k] == '=')
512 return *i + k + 1;
513
37f3ffca
RS
514 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
515 const char *t;
516
2f82562b 517 t = strndupa_safe(name, k);
37f3ffca
RS
518 return getenv(t);
519 };
520
4d1a6904
LP
521 return NULL;
522}
523
524char *strv_env_get(char **l, const char *name) {
525 assert(name);
526
37f3ffca 527 return strv_env_get_n(l, name, strlen(name), 0);
4d1a6904
LP
528}
529
42e6a77b 530char *strv_env_pairs_get(char **l, const char *name) {
de010b0b 531 char *result = NULL;
42e6a77b
LB
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
039f0e70 542char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
4d1a6904
LP
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)) {
039f0e70
LP
550 if (invalid_callback)
551 invalid_callback(*p, userdata);
4d1a6904
LP
552 free(*p);
553 continue;
554 }
555
556 n = strcspn(*p, "=");
557 STRV_FOREACH(q, p + 1)
641906e9 558 if (strneq(*p, *q, n) && (*q)[n] == '=') {
4d1a6904
LP
559 duplicate = true;
560 break;
561 }
562
563 if (duplicate) {
564 free(*p);
565 continue;
566 }
567
568 e[k++] = *p;
569 }
570
5b4fb02d
LP
571 if (e)
572 e[k] = NULL;
573
4d1a6904
LP
574 return e;
575}
3c800095 576
4bed076c 577char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
3c800095
RC
578 enum {
579 WORD,
580 CURLY,
ccad1fd0
ZJS
581 VARIABLE,
582 VARIABLE_RAW,
b82f58bf
RS
583 TEST,
584 DEFAULT_VALUE,
585 ALTERNATE_VALUE,
3c800095
RC
586 } state = WORD;
587
1dbd0bdb 588 const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */
cb4499d0 589 char *k;
5013d6de 590 _cleanup_free_ char *s = NULL;
1dbd0bdb 591 size_t i, len = 0; /* len is initialized to appease gcc */
b82f58bf 592 int nest = 0;
3c800095
RC
593
594 assert(format);
595
00d4b1e6 596 for (e = format, i = 0; *e && i < n; e ++, i ++)
3c800095
RC
597 switch (state) {
598
599 case WORD:
600 if (*e == '$')
601 state = CURLY;
602 break;
603
604 case CURLY:
605 if (*e == '{') {
5013d6de 606 k = strnappend(s, word, e-word-1);
3c800095 607 if (!k)
cb4499d0 608 return NULL;
3c800095 609
5013d6de 610 free_and_replace(s, k);
3c800095
RC
611
612 word = e-1;
613 state = VARIABLE;
b82f58bf 614 nest++;
3c800095 615 } else if (*e == '$') {
5013d6de 616 k = strnappend(s, word, e-word);
3c800095 617 if (!k)
cb4499d0 618 return NULL;
3c800095 619
5013d6de 620 free_and_replace(s, k);
3c800095
RC
621
622 word = e+1;
623 state = WORD;
ccad1fd0 624
b45c068d 625 } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
5013d6de 626 k = strnappend(s, word, e-word-1);
ccad1fd0
ZJS
627 if (!k)
628 return NULL;
629
5013d6de 630 free_and_replace(s, k);
ccad1fd0
ZJS
631
632 word = e-1;
633 state = VARIABLE_RAW;
634
3c800095
RC
635 } else
636 state = WORD;
637 break;
638
639 case VARIABLE:
640 if (*e == '}') {
641 const char *t;
642
37f3ffca 643 t = strv_env_get_n(env, word+2, e-word-2, flags);
3c800095 644
5013d6de 645 if (!strextend(&s, t))
cb4499d0 646 return NULL;
3c800095 647
b82f58bf
RS
648 word = e+1;
649 state = WORD;
5ef97a71 650 nest--;
b82f58bf 651 } else if (*e == ':') {
1dbd0bdb
ZJS
652 if (flags & REPLACE_ENV_ALLOW_EXTENDED) {
653 len = e - word - 2;
654 state = TEST;
655 } else
b82f58bf
RS
656 /* Treat this as unsupported syntax, i.e. do no replacement */
657 state = WORD;
b82f58bf
RS
658 }
659 break;
660
661 case TEST:
662 if (*e == '-')
663 state = DEFAULT_VALUE;
664 else if (*e == '+')
665 state = ALTERNATE_VALUE;
666 else {
667 state = WORD;
668 break;
669 }
670
671 test_value = e+1;
672 break;
673
674 case DEFAULT_VALUE: /* fall through */
675 case ALTERNATE_VALUE:
676 assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
677
678 if (*e == '{') {
679 nest++;
680 break;
681 }
682
683 if (*e != '}')
684 break;
685
686 nest--;
1d046f57 687 if (nest == 0) {
b82f58bf
RS
688 const char *t;
689 _cleanup_free_ char *v = NULL;
690
691 t = strv_env_get_n(env, word+2, len, flags);
692
693 if (t && state == ALTERNATE_VALUE)
694 t = v = replace_env_n(test_value, e-test_value, env, flags);
695 else if (!t && state == DEFAULT_VALUE)
696 t = v = replace_env_n(test_value, e-test_value, env, flags);
697
5013d6de 698 if (!strextend(&s, t))
b82f58bf
RS
699 return NULL;
700
3c800095
RC
701 word = e+1;
702 state = WORD;
703 }
704 break;
ccad1fd0
ZJS
705
706 case VARIABLE_RAW:
707 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
708
b45c068d 709 if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
ccad1fd0
ZJS
710 const char *t;
711
712 t = strv_env_get_n(env, word+1, e-word-1, flags);
713
5013d6de 714 if (!strextend(&s, t))
ccad1fd0
ZJS
715 return NULL;
716
ccad1fd0 717 word = e--;
4bed076c 718 i--;
ccad1fd0
ZJS
719 state = WORD;
720 }
721 break;
3c800095 722 }
3c800095 723
ccad1fd0
ZJS
724 if (state == VARIABLE_RAW) {
725 const char *t;
726
727 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
728
729 t = strv_env_get_n(env, word+1, e-word-1, flags);
5013d6de 730 return strjoin(s, t);
ccad1fd0 731 } else
5013d6de 732 return strnappend(s, word, e-word);
3c800095
RC
733}
734
735char **replace_env_argv(char **argv, char **env) {
cc09d8a5 736 _cleanup_strv_free_ char **ret = NULL;
da6053d0 737 size_t k = 0, l = 0;
3c800095
RC
738
739 l = strv_length(argv);
740
741 ret = new(char*, l+1);
742 if (!ret)
743 return NULL;
744
745 STRV_FOREACH(i, argv) {
746
747 /* If $FOO appears as single word, replace it by the split up variable */
4c701096 748 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
3c800095 749 char *e;
93eceb59
DT
750 char **w;
751 _cleanup_strv_free_ char **m = NULL;
da6053d0 752 size_t q;
3c800095
RC
753
754 e = strv_env_get(env, *i+1);
755 if (e) {
756 int r;
757
90e30d76 758 r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
3c800095
RC
759 if (r < 0) {
760 ret[k] = NULL;
3c800095
RC
761 return NULL;
762 }
93eceb59 763 }
3c800095
RC
764
765 q = strv_length(m);
766 l = l + q - 1;
767
62d74c78 768 w = reallocarray(ret, l + 1, sizeof(char *));
3c800095
RC
769 if (!w) {
770 ret[k] = NULL;
3c800095
RC
771 return NULL;
772 }
773
774 ret = w;
775 if (m) {
776 memcpy(ret + k, m, q * sizeof(char*));
93eceb59 777 m = mfree(m);
3c800095
RC
778 }
779
780 k += q;
781 continue;
782 }
783
784 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
37f3ffca 785 ret[k] = replace_env(*i, env, 0);
cc09d8a5 786 if (!ret[k])
3c800095 787 return NULL;
3c800095
RC
788 k++;
789 }
790
791 ret[k] = NULL;
cc09d8a5 792 return TAKE_PTR(ret);
3c800095 793}
b41b9d2a
LP
794
795int getenv_bool(const char *p) {
796 const char *e;
797
798 e = getenv(p);
799 if (!e)
800 return -ENXIO;
801
802 return parse_boolean(e);
803}
fe902fa4 804
71e0accc
ZJS
805int getenv_bool_secure(const char *p) {
806 const char *e;
807
808 e = secure_getenv(p);
809 if (!e)
810 return -ENXIO;
811
812 return parse_boolean(e);
813}
063f9f0d 814
3fa8a114
JSMR
815int getenv_uint64_secure(const char *p, uint64_t *ret) {
816 const char *e;
817
818 assert(p);
819
820 e = secure_getenv(p);
821 if (!e)
822 return -ENXIO;
823
824 return safe_atou64(e, ret);
825}
826
063f9f0d 827int set_unset_env(const char *name, const char *value, bool overwrite) {
7c248223 828 assert(name);
063f9f0d
ZJS
829
830 if (value)
7c248223
LP
831 return RET_NERRNO(setenv(name, value, overwrite));
832
833 return RET_NERRNO(unsetenv(name));
063f9f0d 834}
cfd1c6e2 835
fa256f43
ZJS
836int putenv_dup(const char *assignment, bool override) {
837 const char *e, *n;
838
839 e = strchr(assignment, '=');
840 if (!e)
841 return -EINVAL;
842
2f82562b 843 n = strndupa_safe(assignment, e - assignment);
fa256f43
ZJS
844
845 /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
7c248223 846 return RET_NERRNO(setenv(n, e + 1, override));
fa256f43
ZJS
847}
848
cfd1c6e2
YW
849int setenv_systemd_exec_pid(bool update_only) {
850 char str[DECIMAL_STR_MAX(pid_t)];
851 const char *e;
852
853 /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
854
855 e = secure_getenv("SYSTEMD_EXEC_PID");
856 if (!e && update_only)
857 return 0;
858
859 if (streq_ptr(e, "*"))
860 return 0;
861
862 xsprintf(str, PID_FMT, getpid_cached());
863
864 if (setenv("SYSTEMD_EXEC_PID", str, 1) < 0)
865 return -errno;
866
867 return 1;
868}
93547f28
LB
869
870int getenv_path_list(const char *name, char ***ret_paths) {
871 _cleanup_strv_free_ char **l = NULL;
872 const char *e;
93547f28
LB
873 int r;
874
875 assert(name);
876 assert(ret_paths);
877
93547f28
LB
878 e = secure_getenv(name);
879 if (!e)
33d31c0e 880 return -ENXIO;
93547f28
LB
881
882 r = strv_split_full(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
883 if (r < 0)
884 return log_debug_errno(r, "Failed to parse $%s: %m", name);
885
886 STRV_FOREACH(p, l) {
887 if (!path_is_absolute(*p))
888 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
889 "Path '%s' is not absolute, refusing.", *p);
890
891 if (!path_is_normalized(*p))
892 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
893 "Path '%s' is not normalized, refusing.", *p);
894
895 if (path_equal(*p, "/"))
896 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
897 "Path '%s' is the root fs, refusing.", *p);
898 }
899
900 if (strv_isempty(l))
901 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
902 "No paths specified, refusing.");
903
904 *ret_paths = TAKE_PTR(l);
33d31c0e 905 return 1;
93547f28 906}
7a6abbe9 907
e99ca147
LP
908int getenv_steal_erase(const char *name, char **ret) {
909 _cleanup_(erase_and_freep) char *a = NULL;
910 char *e;
7a6abbe9
LP
911
912 assert(name);
913
e99ca147
LP
914 /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes
915 * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for
916 * testing, and given that people are likely going to misuse this, be thorough) */
917
918 e = getenv(name);
919 if (!e) {
920 if (ret)
921 *ret = NULL;
7a6abbe9 922 return 0;
e99ca147 923 }
7a6abbe9 924
e99ca147
LP
925 if (ret) {
926 a = strdup(e);
927 if (!a)
928 return -ENOMEM;
929 }
930
931 string_erase(e);
7a6abbe9
LP
932
933 if (unsetenv(name) < 0)
934 return -errno;
935
e99ca147
LP
936 if (ret)
937 *ret = TAKE_PTR(a);
938
7a6abbe9
LP
939 return 1;
940}