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