]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/env-util.c
test: add tests for %j and %J specifier in test-execute (#8838)
[thirdparty/systemd.git] / src / basic / env-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
4d1a6904
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
4d1a6904
LP
6***/
7
11c3a366 8#include <errno.h>
4d1a6904 9#include <limits.h>
11c3a366
TA
10#include <stdarg.h>
11#include <stdlib.h>
12#include <string.h>
4d1a6904
LP
13#include <unistd.h>
14
b5efdb8a 15#include "alloc-util.h"
b5efdb8a 16#include "env-util.h"
fe902fa4 17#include "escape.h"
11c3a366
TA
18#include "extract-word.h"
19#include "macro.h"
93cc7779 20#include "parse-util.h"
07630cea 21#include "string-util.h"
4d1a6904
LP
22#include "strv.h"
23#include "utf8.h"
4d1a6904
LP
24
25#define VALID_CHARS_ENV_NAME \
4b549144 26 DIGITS LETTERS \
4d1a6904
LP
27 "_"
28
29#ifndef ARG_MAX
30#define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
31#endif
32
33static bool env_name_is_valid_n(const char *e, size_t n) {
34 const char *p;
35
36 if (!e)
37 return false;
38
39 if (n <= 0)
40 return false;
41
42 if (e[0] >= '0' && e[0] <= '9')
43 return false;
44
45 /* POSIX says the overall size of the environment block cannot
46 * be > ARG_MAX, an individual assignment hence cannot be
47 * either. Discounting the equal sign and trailing NUL this
48 * hence leaves ARG_MAX-2 as longest possible variable
49 * name. */
50 if (n > ARG_MAX - 2)
51 return false;
52
53 for (p = e; p < e + n; p++)
54 if (!strchr(VALID_CHARS_ENV_NAME, *p))
55 return false;
56
57 return true;
58}
59
60bool env_name_is_valid(const char *e) {
61 if (!e)
62 return false;
63
64 return env_name_is_valid_n(e, strlen(e));
65}
66
67bool env_value_is_valid(const char *e) {
68 if (!e)
69 return false;
70
71 if (!utf8_is_valid(e))
72 return false;
73
b4346b9a
FB
74 /* bash allows tabs and newlines in environment variables, and so
75 * should we */
76 if (string_has_cc(e, "\t\n"))
4d1a6904
LP
77 return false;
78
79 /* POSIX says the overall size of the environment block cannot
80 * be > ARG_MAX, an individual assignment hence cannot be
81 * either. Discounting the shortest possible variable name of
82 * length 1, the equal sign and trailing NUL this hence leaves
83 * ARG_MAX-3 as longest possible variable value. */
84 if (strlen(e) > ARG_MAX - 3)
85 return false;
86
87 return true;
88}
89
90bool env_assignment_is_valid(const char *e) {
91 const char *eq;
92
93 eq = strchr(e, '=');
94 if (!eq)
95 return false;
96
97 if (!env_name_is_valid_n(e, eq - e))
98 return false;
99
100 if (!env_value_is_valid(eq + 1))
101 return false;
102
103 /* POSIX says the overall size of the environment block cannot
104 * be > ARG_MAX, hence the individual variable assignments
5f9cfd4c 105 * cannot be either, but let's leave room for one trailing NUL
4d1a6904
LP
106 * byte. */
107 if (strlen(e) > ARG_MAX - 1)
108 return false;
109
110 return true;
111}
112
113bool strv_env_is_valid(char **e) {
114 char **p, **q;
115
116 STRV_FOREACH(p, e) {
117 size_t k;
118
119 if (!env_assignment_is_valid(*p))
120 return false;
121
122 /* Check if there are duplicate assginments */
123 k = strcspn(*p, "=");
124 STRV_FOREACH(q, p + 1)
641906e9 125 if (strneq(*p, *q, k) && (*q)[k] == '=')
4d1a6904
LP
126 return false;
127 }
128
129 return true;
130}
131
b4c14404
FB
132bool strv_env_name_is_valid(char **l) {
133 char **p, **q;
134
135 STRV_FOREACH(p, l) {
136 if (!env_name_is_valid(*p))
137 return false;
138
139 STRV_FOREACH(q, p + 1)
140 if (streq(*p, *q))
141 return false;
142 }
143
144 return true;
145}
146
123b964a
LP
147bool strv_env_name_or_assignment_is_valid(char **l) {
148 char **p, **q;
149
150 STRV_FOREACH(p, l) {
151 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
152 return false;
153
154 STRV_FOREACH(q, p + 1)
155 if (streq(*p, *q))
156 return false;
157 }
158
159 return true;
160}
161
4d1a6904
LP
162static int env_append(char **r, char ***k, char **a) {
163 assert(r);
164 assert(k);
165
166 if (!a)
167 return 0;
168
169 /* Add the entries of a to *k unless they already exist in *r
170 * in which case they are overridden instead. This assumes
171 * there is enough space in the r array. */
172
173 for (; *a; a++) {
174 char **j;
175 size_t n;
176
177 n = strcspn(*a, "=");
178
179 if ((*a)[n] == '=')
180 n++;
181
182 for (j = r; j < *k; j++)
641906e9 183 if (strneq(*j, *a, n))
4d1a6904
LP
184 break;
185
186 if (j >= *k)
187 (*k)++;
188 else
189 free(*j);
190
191 *j = strdup(*a);
192 if (!*j)
193 return -ENOMEM;
194 }
195
196 return 0;
197}
198
199char **strv_env_merge(unsigned n_lists, ...) {
200 size_t n = 0;
201 char **l, **k, **r;
202 va_list ap;
203 unsigned i;
204
205 /* Merges an arbitrary number of environment sets */
206
207 va_start(ap, n_lists);
208 for (i = 0; i < n_lists; i++) {
209 l = va_arg(ap, char**);
210 n += strv_length(l);
211 }
212 va_end(ap);
213
214 r = new(char*, n+1);
215 if (!r)
216 return NULL;
217
218 k = r;
219
220 va_start(ap, n_lists);
221 for (i = 0; i < n_lists; i++) {
222 l = va_arg(ap, char**);
223 if (env_append(r, &k, l) < 0)
224 goto fail;
225 }
226 va_end(ap);
227
228 *k = NULL;
229
230 return r;
231
232fail:
233 va_end(ap);
234 strv_free(r);
235
236 return NULL;
237}
238
c8cebc36 239static bool env_match(const char *t, const char *pattern) {
4d1a6904
LP
240 assert(t);
241 assert(pattern);
242
243 /* pattern a matches string a
244 * a matches a=
245 * a matches a=b
246 * a= matches a=
247 * a=b matches a=b
248 * a= does not match a
249 * a=b does not match a=
250 * a=b does not match a
251 * a=b does not match a=c */
252
253 if (streq(t, pattern))
254 return true;
255
256 if (!strchr(pattern, '=')) {
257 size_t l = strlen(pattern);
258
641906e9 259 return strneq(t, pattern, l) && t[l] == '=';
4d1a6904
LP
260 }
261
262 return false;
263}
264
99003e01
ZJS
265static bool env_entry_has_name(const char *entry, const char *name) {
266 const char *t;
267
268 assert(entry);
269 assert(name);
270
271 t = startswith(entry, name);
272 if (!t)
273 return false;
274
275 return *t == '=';
276}
277
4d1a6904
LP
278char **strv_env_delete(char **x, unsigned n_lists, ...) {
279 size_t n, i = 0;
280 char **k, **r;
281 va_list ap;
282
283 /* Deletes every entry from x that is mentioned in the other
284 * string lists */
285
286 n = strv_length(x);
287
288 r = new(char*, n+1);
289 if (!r)
290 return NULL;
291
292 STRV_FOREACH(k, x) {
293 unsigned v;
294
295 va_start(ap, n_lists);
296 for (v = 0; v < n_lists; v++) {
297 char **l, **j;
298
299 l = va_arg(ap, char**);
300 STRV_FOREACH(j, l)
301 if (env_match(*k, *j))
302 goto skip;
303 }
304 va_end(ap);
305
306 r[i] = strdup(*k);
307 if (!r[i]) {
308 strv_free(r);
309 return NULL;
310 }
311
312 i++;
313 continue;
314
315 skip:
316 va_end(ap);
317 }
318
319 r[i] = NULL;
320
321 assert(i <= n);
322
323 return r;
324}
325
326char **strv_env_unset(char **l, const char *p) {
327
328 char **f, **t;
329
330 if (!l)
331 return NULL;
332
333 assert(p);
334
335 /* Drops every occurrence of the env var setting p in the
43d03a83 336 * string list. Edits in-place. */
4d1a6904
LP
337
338 for (f = t = l; *f; f++) {
339
340 if (env_match(*f, p)) {
341 free(*f);
342 continue;
343 }
344
345 *(t++) = *f;
346 }
43d03a83
LP
347
348 *t = NULL;
349 return l;
350}
351
352char **strv_env_unset_many(char **l, ...) {
353
354 char **f, **t;
355
356 if (!l)
357 return NULL;
358
359 /* Like strv_env_unset() but applies many at once. Edits in-place. */
360
361 for (f = t = l; *f; f++) {
362 bool found = false;
363 const char *p;
364 va_list ap;
365
366 va_start(ap, l);
367
368 while ((p = va_arg(ap, const char*))) {
369 if (env_match(*f, p)) {
370 found = true;
371 break;
372 }
373 }
374
375 va_end(ap);
376
377 if (found) {
378 free(*f);
379 continue;
380 }
381
382 *(t++) = *f;
383 }
4d1a6904
LP
384
385 *t = NULL;
386 return l;
387}
388
54ac3494
ZJS
389int strv_env_replace(char ***l, char *p) {
390 char **f;
99003e01 391 const char *t, *name;
54ac3494
ZJS
392
393 assert(p);
394
395 /* Replace first occurrence of the env var or add a new one in the
396 * string list. Drop other occurences. Edits in-place. Does not copy p.
99003e01 397 * p must be a valid key=value assignment.
54ac3494
ZJS
398 */
399
99003e01
ZJS
400 t = strchr(p, '=');
401 assert(t);
402
403 name = strndupa(p, t - p);
404
54ac3494 405 for (f = *l; f && *f; f++)
99003e01
ZJS
406 if (env_entry_has_name(*f, name)) {
407 free_and_replace(*f, p);
408 strv_env_unset(f + 1, *f);
54ac3494
ZJS
409 return 0;
410 }
411
412 /* We didn't find a match, we need to append p or create a new strv */
413 if (strv_push(l, p) < 0)
414 return -ENOMEM;
415 return 1;
416}
417
4d1a6904
LP
418char **strv_env_set(char **x, const char *p) {
419
420 char **k, **r;
421 char* m[2] = { (char*) p, NULL };
422
423 /* Overrides the env var setting of p, returns a new copy */
424
425 r = new(char*, strv_length(x)+2);
426 if (!r)
427 return NULL;
428
429 k = r;
430 if (env_append(r, &k, x) < 0)
431 goto fail;
432
433 if (env_append(r, &k, m) < 0)
434 goto fail;
435
436 *k = NULL;
437
438 return r;
439
440fail:
441 strv_free(r);
442 return NULL;
443}
444
37f3ffca 445char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
4d1a6904
LP
446 char **i;
447
448 assert(name);
449
450 if (k <= 0)
451 return NULL;
452
6162512c 453 STRV_FOREACH_BACKWARDS(i, l)
641906e9 454 if (strneq(*i, name, k) &&
4d1a6904
LP
455 (*i)[k] == '=')
456 return *i + k + 1;
457
37f3ffca
RS
458 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
459 const char *t;
460
461 t = strndupa(name, k);
462 return getenv(t);
463 };
464
4d1a6904
LP
465 return NULL;
466}
467
468char *strv_env_get(char **l, const char *name) {
469 assert(name);
470
37f3ffca 471 return strv_env_get_n(l, name, strlen(name), 0);
4d1a6904
LP
472}
473
039f0e70 474char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
4d1a6904
LP
475 char **p, **q;
476 int k = 0;
477
478 STRV_FOREACH(p, e) {
479 size_t n;
480 bool duplicate = false;
481
482 if (!env_assignment_is_valid(*p)) {
039f0e70
LP
483 if (invalid_callback)
484 invalid_callback(*p, userdata);
4d1a6904
LP
485 free(*p);
486 continue;
487 }
488
489 n = strcspn(*p, "=");
490 STRV_FOREACH(q, p + 1)
641906e9 491 if (strneq(*p, *q, n) && (*q)[n] == '=') {
4d1a6904
LP
492 duplicate = true;
493 break;
494 }
495
496 if (duplicate) {
497 free(*p);
498 continue;
499 }
500
501 e[k++] = *p;
502 }
503
5b4fb02d
LP
504 if (e)
505 e[k] = NULL;
506
4d1a6904
LP
507 return e;
508}
3c800095 509
4bed076c 510char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
3c800095
RC
511 enum {
512 WORD,
513 CURLY,
ccad1fd0
ZJS
514 VARIABLE,
515 VARIABLE_RAW,
b82f58bf
RS
516 TEST,
517 DEFAULT_VALUE,
518 ALTERNATE_VALUE,
3c800095
RC
519 } state = WORD;
520
b82f58bf 521 const char *e, *word = format, *test_value;
cb4499d0
ZJS
522 char *k;
523 _cleanup_free_ char *r = NULL;
b82f58bf
RS
524 size_t i, len;
525 int nest = 0;
3c800095
RC
526
527 assert(format);
528
00d4b1e6 529 for (e = format, i = 0; *e && i < n; e ++, i ++)
3c800095
RC
530 switch (state) {
531
532 case WORD:
533 if (*e == '$')
534 state = CURLY;
535 break;
536
537 case CURLY:
538 if (*e == '{') {
539 k = strnappend(r, word, e-word-1);
540 if (!k)
cb4499d0 541 return NULL;
3c800095 542
00d4b1e6 543 free_and_replace(r, k);
3c800095
RC
544
545 word = e-1;
546 state = VARIABLE;
b82f58bf 547 nest++;
3c800095
RC
548 } else if (*e == '$') {
549 k = strnappend(r, word, e-word);
550 if (!k)
cb4499d0 551 return NULL;
3c800095 552
00d4b1e6 553 free_and_replace(r, k);
3c800095
RC
554
555 word = e+1;
556 state = WORD;
ccad1fd0
ZJS
557
558 } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
559 k = strnappend(r, word, e-word-1);
560 if (!k)
561 return NULL;
562
00d4b1e6 563 free_and_replace(r, k);
ccad1fd0
ZJS
564
565 word = e-1;
566 state = VARIABLE_RAW;
567
3c800095
RC
568 } else
569 state = WORD;
570 break;
571
572 case VARIABLE:
573 if (*e == '}') {
574 const char *t;
575
37f3ffca 576 t = strv_env_get_n(env, word+2, e-word-2, flags);
3c800095
RC
577
578 k = strappend(r, t);
579 if (!k)
cb4499d0 580 return NULL;
3c800095 581
00d4b1e6 582 free_and_replace(r, k);
3c800095 583
b82f58bf
RS
584 word = e+1;
585 state = WORD;
586 } else if (*e == ':') {
587 if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
588 /* Treat this as unsupported syntax, i.e. do no replacement */
589 state = WORD;
590 else {
591 len = e-word-2;
592 state = TEST;
593 }
594 }
595 break;
596
597 case TEST:
598 if (*e == '-')
599 state = DEFAULT_VALUE;
600 else if (*e == '+')
601 state = ALTERNATE_VALUE;
602 else {
603 state = WORD;
604 break;
605 }
606
607 test_value = e+1;
608 break;
609
610 case DEFAULT_VALUE: /* fall through */
611 case ALTERNATE_VALUE:
612 assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
613
614 if (*e == '{') {
615 nest++;
616 break;
617 }
618
619 if (*e != '}')
620 break;
621
622 nest--;
1d046f57 623 if (nest == 0) {
b82f58bf
RS
624 const char *t;
625 _cleanup_free_ char *v = NULL;
626
627 t = strv_env_get_n(env, word+2, len, flags);
628
629 if (t && state == ALTERNATE_VALUE)
630 t = v = replace_env_n(test_value, e-test_value, env, flags);
631 else if (!t && state == DEFAULT_VALUE)
632 t = v = replace_env_n(test_value, e-test_value, env, flags);
633
634 k = strappend(r, t);
635 if (!k)
636 return NULL;
637
00d4b1e6 638 free_and_replace(r, k);
b82f58bf 639
3c800095
RC
640 word = e+1;
641 state = WORD;
642 }
643 break;
ccad1fd0
ZJS
644
645 case VARIABLE_RAW:
646 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
647
648 if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
649 const char *t;
650
651 t = strv_env_get_n(env, word+1, e-word-1, flags);
652
653 k = strappend(r, t);
654 if (!k)
655 return NULL;
656
00d4b1e6 657 free_and_replace(r, k);
ccad1fd0
ZJS
658
659 word = e--;
4bed076c 660 i--;
ccad1fd0
ZJS
661 state = WORD;
662 }
663 break;
3c800095 664 }
3c800095 665
ccad1fd0
ZJS
666 if (state == VARIABLE_RAW) {
667 const char *t;
668
669 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
670
671 t = strv_env_get_n(env, word+1, e-word-1, flags);
672 return strappend(r, t);
673 } else
674 return strnappend(r, word, e-word);
3c800095
RC
675}
676
677char **replace_env_argv(char **argv, char **env) {
678 char **ret, **i;
679 unsigned k = 0, l = 0;
680
681 l = strv_length(argv);
682
683 ret = new(char*, l+1);
684 if (!ret)
685 return NULL;
686
687 STRV_FOREACH(i, argv) {
688
689 /* If $FOO appears as single word, replace it by the split up variable */
4c701096 690 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
3c800095
RC
691 char *e;
692 char **w, **m = NULL;
693 unsigned q;
694
695 e = strv_env_get(env, *i+1);
696 if (e) {
697 int r;
698
8adaf7bd 699 r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES);
3c800095
RC
700 if (r < 0) {
701 ret[k] = NULL;
702 strv_free(ret);
703 return NULL;
704 }
705 } else
706 m = NULL;
707
708 q = strv_length(m);
709 l = l + q - 1;
710
62d74c78 711 w = reallocarray(ret, l + 1, sizeof(char *));
3c800095
RC
712 if (!w) {
713 ret[k] = NULL;
714 strv_free(ret);
715 strv_free(m);
716 return NULL;
717 }
718
719 ret = w;
720 if (m) {
721 memcpy(ret + k, m, q * sizeof(char*));
722 free(m);
723 }
724
725 k += q;
726 continue;
727 }
728
729 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
37f3ffca 730 ret[k] = replace_env(*i, env, 0);
3c800095
RC
731 if (!ret[k]) {
732 strv_free(ret);
733 return NULL;
734 }
735 k++;
736 }
737
738 ret[k] = NULL;
739 return ret;
740}
b41b9d2a
LP
741
742int getenv_bool(const char *p) {
743 const char *e;
744
745 e = getenv(p);
746 if (!e)
747 return -ENXIO;
748
749 return parse_boolean(e);
750}
fe902fa4 751
71e0accc
ZJS
752int getenv_bool_secure(const char *p) {
753 const char *e;
754
755 e = secure_getenv(p);
756 if (!e)
757 return -ENXIO;
758
759 return parse_boolean(e);
760}
761
fe902fa4
ZJS
762int serialize_environment(FILE *f, char **environment) {
763 char **e;
764
765 STRV_FOREACH(e, environment) {
766 _cleanup_free_ char *ce;
767
768 ce = cescape(*e);
769 if (!ce)
770 return -ENOMEM;
771
417eefb1 772 fprintf(f, "env=%s\n", ce);
fe902fa4
ZJS
773 }
774
775 /* caller should call ferror() */
776
777 return 0;
778}
779
780int deserialize_environment(char ***environment, const char *line) {
d233c99a 781 char *uce;
fe902fa4
ZJS
782 int r;
783
784 assert(line);
785 assert(environment);
786
787 assert(startswith(line, "env="));
c7d797bb 788 r = cunescape(line + 4, 0, &uce);
fe902fa4
ZJS
789 if (r < 0)
790 return r;
791
792 return strv_env_replace(environment, uce);
793}