1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
11 #include "errno-util.h"
13 #include "extract-word.h"
15 #include "parse-util.h"
16 #include "path-util.h"
17 #include "process-util.h"
18 #include "stdio-util.h"
19 #include "string-util.h"
23 /* We follow bash for the character set. Different shells have different rules. */
24 #define VALID_BASH_ENV_NAME_CHARS \
28 static bool env_name_is_valid_n(const char *e
, size_t n
) {
35 if (e
[0] >= '0' && e
[0] <= '9')
38 /* POSIX says the overall size of the environment block cannot
39 * be > ARG_MAX, an individual assignment hence cannot be
40 * either. Discounting the equal sign and trailing NUL this
41 * hence leaves ARG_MAX-2 as longest possible variable
43 if (n
> (size_t) sysconf(_SC_ARG_MAX
) - 2)
46 for (const char *p
= e
; p
< e
+ n
; p
++)
47 if (!strchr(VALID_BASH_ENV_NAME_CHARS
, *p
))
53 bool env_name_is_valid(const char *e
) {
54 return env_name_is_valid_n(e
, strlen_ptr(e
));
57 bool env_value_is_valid(const char *e
) {
61 if (!utf8_is_valid(e
))
64 /* Note that variable *values* may contain control characters, in particular NL, TAB, BS, DEL, ESC…
65 * When printing those variables with show-environment, we'll escape them. Make sure to print
66 * environment variables carefully! */
68 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
69 * hence cannot be either. Discounting the shortest possible variable name of length 1, the equal
70 * sign and trailing NUL this hence leaves ARG_MAX-3 as longest possible variable value. */
71 if (strlen(e
) > sc_arg_max() - 3)
77 bool env_assignment_is_valid(const char *e
) {
84 if (!env_name_is_valid_n(e
, eq
- e
))
87 if (!env_value_is_valid(eq
+ 1))
90 /* POSIX says the overall size of the environment block cannot be > ARG_MAX, hence the individual
91 * variable assignments cannot be either, but let's leave room for one trailing NUL byte. */
92 if (strlen(e
) > sc_arg_max() - 1)
98 bool strv_env_is_valid(char **e
) {
104 if (!env_assignment_is_valid(*p
))
107 /* Check if there are duplicate assignments */
108 k
= strcspn(*p
, "=");
109 STRV_FOREACH(q
, p
+ 1)
110 if (strneq(*p
, *q
, k
) && (*q
)[k
] == '=')
117 bool strv_env_name_is_valid(char **l
) {
121 if (!env_name_is_valid(*p
))
124 if (strv_contains(p
+ 1, *p
))
131 bool strv_env_name_or_assignment_is_valid(char **l
) {
135 if (!env_assignment_is_valid(*p
) && !env_name_is_valid(*p
))
138 if (strv_contains(p
+ 1, *p
))
145 static int env_append(char **r
, char ***k
, char **a
) {
153 /* Expects the following arguments: 'r' shall point to the beginning of an strv we are going to append to, 'k'
154 * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
156 * This call adds every entry of 'a' to 'r', either overriding an existing matching entry, or appending to it.
158 * This call assumes 'r' has enough pre-allocated space to grow by all of 'a''s items. */
164 n
= strcspn(*a
, "=");
168 for (j
= r
; j
< *k
; j
++)
169 if (strneq(*j
, *a
, n
))
176 if (j
>= *k
) { /* Append to the end? */
181 free_and_replace(*j
, c
); /* Override existing item */
187 char** _strv_env_merge(char **first
, ...) {
188 _cleanup_strv_free_
char **merged
= NULL
;
192 /* Merges an arbitrary number of environment sets */
194 size_t n
= strv_length(first
);
200 l
= va_arg(ap
, char**);
201 if (l
== POINTER_MAX
)
208 k
= merged
= new(char*, n
+ 1);
213 if (env_append(merged
, &k
, first
) < 0)
220 l
= va_arg(ap
, char**);
221 if (l
== POINTER_MAX
)
224 if (env_append(merged
, &k
, l
) < 0) {
231 return TAKE_PTR(merged
);
234 static bool env_match(const char *t
, const char *pattern
) {
238 /* pattern a matches string a
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 */
248 if (streq(t
, pattern
))
251 if (!strchr(pattern
, '=')) {
252 size_t l
= strlen(pattern
);
254 return strneq(t
, pattern
, l
) && t
[l
] == '=';
260 static bool env_entry_has_name(const char *entry
, const char *name
) {
266 t
= startswith(entry
, name
);
273 char **strv_env_delete(char **x
, size_t n_lists
, ...) {
278 /* Deletes every entry from x that is mentioned in the other
288 va_start(ap
, n_lists
);
289 for (size_t v
= 0; v
< n_lists
; v
++) {
292 l
= va_arg(ap
, char**);
294 if (env_match(*k
, *j
))
319 char **strv_env_unset(char **l
, const char *p
) {
327 /* Drops every occurrence of the env var setting p in the
328 * string list. Edits in-place. */
330 for (f
= t
= l
; *f
; f
++) {
332 if (env_match(*f
, p
)) {
344 char **strv_env_unset_many(char **l
, ...) {
350 /* Like strv_env_unset() but applies many at once. Edits in-place. */
352 for (f
= t
= l
; *f
; f
++) {
359 while ((p
= va_arg(ap
, const char*))) {
360 if (env_match(*f
, p
)) {
380 int strv_env_replace_consume(char ***l
, char *p
) {
381 const char *t
, *name
;
387 /* Replace first occurrence of the env var or add a new one in the string list. Drop other
388 * occurrences. Edits in-place. Does not copy p and CONSUMES p EVEN ON FAILURE.
390 * p must be a valid key=value assignment. */
398 name
= strndupa_safe(p
, t
- p
);
401 if (env_entry_has_name(*f
, name
)) {
402 free_and_replace(*f
, p
);
403 strv_env_unset(f
+ 1, *f
);
407 /* We didn't find a match, we need to append p or create a new strv */
408 r
= strv_consume(l
, p
);
415 int strv_env_replace_strdup(char ***l
, const char *assignment
) {
416 /* Like strv_env_replace_consume(), but copies the argument. */
418 char *p
= strdup(assignment
);
422 return strv_env_replace_consume(l
, p
);
425 int strv_env_replace_strdup_passthrough(char ***l
, const char *assignment
) {
426 /* Like strv_env_replace_strdup(), but pulls the variable from the environment of
427 * the calling program, if a variable name without value is specified.
431 if (strchr(assignment
, '=')) {
432 if (!env_assignment_is_valid(assignment
))
435 p
= strdup(assignment
);
437 if (!env_name_is_valid(assignment
))
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
));
448 return strv_env_replace_consume(l
, p
);
451 int strv_env_assign(char ***l
, const char *key
, const char *value
) {
452 if (!env_name_is_valid(key
))
455 /* NULL removes assignment, "" creates an empty assignment. */
458 strv_env_unset(*l
, key
);
462 char *p
= strjoin(key
, "=", value
);
466 return strv_env_replace_consume(l
, p
);
469 char *strv_env_get_n(char **l
, const char *name
, size_t k
, unsigned flags
) {
477 STRV_FOREACH_BACKWARDS(i
, l
)
478 if (strneq(*i
, name
, k
) &&
482 if (flags
& REPLACE_ENV_USE_ENVIRONMENT
) {
485 t
= strndupa_safe(name
, k
);
492 char *strv_env_get(char **l
, const char *name
) {
495 return strv_env_get_n(l
, name
, strlen(name
), 0);
498 char *strv_env_pairs_get(char **l
, const char *name
) {
499 char **key
, **value
, *result
= NULL
;
503 STRV_FOREACH_PAIR(key
, value
, l
)
504 if (streq(*key
, name
))
510 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
516 bool duplicate
= false;
518 if (!env_assignment_is_valid(*p
)) {
519 if (invalid_callback
)
520 invalid_callback(*p
, userdata
);
525 n
= strcspn(*p
, "=");
526 STRV_FOREACH(q
, p
+ 1)
527 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
546 char *replace_env_n(const char *format
, size_t n
, char **env
, unsigned flags
) {
557 const char *e
, *word
= format
, *test_value
= NULL
; /* test_value is initialized to appease gcc */
559 _cleanup_free_
char *r
= NULL
;
560 size_t i
, len
= 0; /* len is initialized to appease gcc */
565 for (e
= format
, i
= 0; *e
&& i
< n
; e
++, i
++)
575 k
= strnappend(r
, word
, e
-word
-1);
579 free_and_replace(r
, k
);
584 } else if (*e
== '$') {
585 k
= strnappend(r
, word
, e
-word
);
589 free_and_replace(r
, k
);
594 } else if (flags
& REPLACE_ENV_ALLOW_BRACELESS
&& strchr(VALID_BASH_ENV_NAME_CHARS
, *e
)) {
595 k
= strnappend(r
, word
, e
-word
-1);
599 free_and_replace(r
, k
);
602 state
= VARIABLE_RAW
;
612 t
= strv_env_get_n(env
, word
+2, e
-word
-2, flags
);
614 if (!strextend(&r
, t
))
620 } else if (*e
== ':') {
621 if (flags
& REPLACE_ENV_ALLOW_EXTENDED
) {
625 /* Treat this as unsupported syntax, i.e. do no replacement */
632 state
= DEFAULT_VALUE
;
634 state
= ALTERNATE_VALUE
;
643 case DEFAULT_VALUE
: /* fall through */
644 case ALTERNATE_VALUE
:
645 assert(flags
& REPLACE_ENV_ALLOW_EXTENDED
);
658 _cleanup_free_
char *v
= NULL
;
660 t
= strv_env_get_n(env
, word
+2, len
, flags
);
662 if (t
&& state
== ALTERNATE_VALUE
)
663 t
= v
= replace_env_n(test_value
, e
-test_value
, env
, flags
);
664 else if (!t
&& state
== DEFAULT_VALUE
)
665 t
= v
= replace_env_n(test_value
, e
-test_value
, env
, flags
);
667 if (!strextend(&r
, t
))
676 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
678 if (!strchr(VALID_BASH_ENV_NAME_CHARS
, *e
)) {
681 t
= strv_env_get_n(env
, word
+1, e
-word
-1, flags
);
683 if (!strextend(&r
, t
))
693 if (state
== VARIABLE_RAW
) {
696 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
698 t
= strv_env_get_n(env
, word
+1, e
-word
-1, flags
);
699 return strjoin(r
, t
);
701 return strnappend(r
, word
, e
-word
);
704 char **replace_env_argv(char **argv
, char **env
) {
708 l
= strv_length(argv
);
710 ret
= new(char*, l
+1);
714 STRV_FOREACH(i
, argv
) {
716 /* If $FOO appears as single word, replace it by the split up variable */
717 if ((*i
)[0] == '$' && !IN_SET((*i
)[1], '{', '$')) {
719 char **w
, **m
= NULL
;
722 e
= strv_env_get(env
, *i
+1);
726 r
= strv_split_full(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_UNQUOTE
);
738 w
= reallocarray(ret
, l
+ 1, sizeof(char *));
748 memcpy(ret
+ k
, m
, q
* sizeof(char*));
756 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
757 ret
[k
] = replace_env(*i
, env
, 0);
769 int getenv_bool(const char *p
) {
776 return parse_boolean(e
);
779 int getenv_bool_secure(const char *p
) {
782 e
= secure_getenv(p
);
786 return parse_boolean(e
);
789 int set_unset_env(const char *name
, const char *value
, bool overwrite
) {
793 return RET_NERRNO(setenv(name
, value
, overwrite
));
795 return RET_NERRNO(unsetenv(name
));
798 int putenv_dup(const char *assignment
, bool override
) {
801 e
= strchr(assignment
, '=');
805 n
= strndupa_safe(assignment
, e
- assignment
);
807 /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
808 return RET_NERRNO(setenv(n
, e
+ 1, override
));
811 int setenv_systemd_exec_pid(bool update_only
) {
812 char str
[DECIMAL_STR_MAX(pid_t
)];
815 /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
817 e
= secure_getenv("SYSTEMD_EXEC_PID");
818 if (!e
&& update_only
)
821 if (streq_ptr(e
, "*"))
824 xsprintf(str
, PID_FMT
, getpid_cached());
826 if (setenv("SYSTEMD_EXEC_PID", str
, 1) < 0)
832 int getenv_path_list(const char *name
, char ***ret_paths
) {
833 _cleanup_strv_free_
char **l
= NULL
;
841 e
= secure_getenv(name
);
845 r
= strv_split_full(&l
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
847 return log_debug_errno(r
, "Failed to parse $%s: %m", name
);
850 if (!path_is_absolute(*p
))
851 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
852 "Path '%s' is not absolute, refusing.", *p
);
854 if (!path_is_normalized(*p
))
855 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
856 "Path '%s' is not normalized, refusing.", *p
);
858 if (path_equal(*p
, "/"))
859 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
860 "Path '%s' is the root fs, refusing.", *p
);
864 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
865 "No paths specified, refusing.");
867 *ret_paths
= TAKE_PTR(l
);
871 int getenv_steal_erase(const char *name
, char **ret
) {
872 _cleanup_(erase_and_freep
) char *a
= NULL
;
877 /* Reads an environment variable, makes a copy of it, erases its memory in the environment block and removes
878 * it from there. Usecase: reading passwords from the env block (which is a bad idea, but useful for
879 * testing, and given that people are likely going to misuse this, be thorough) */
896 if (unsetenv(name
) < 0)