1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "alloc-util.h"
8 #include "errno-util.h"
9 #include "extract-word.h"
10 #include "format-util.h"
12 #include "parse-util.h"
13 #include "path-util.h"
14 #include "process-util.h"
15 #include "string-util.h"
17 #include "syslog-util.h"
20 /* We follow bash for the character set. Different shells have different rules. */
21 #define VALID_BASH_ENV_NAME_CHARS \
25 size_t sc_arg_max(void) {
26 long l
= sysconf(_SC_ARG_MAX
);
31 static bool env_name_is_valid_n(const char *e
, size_t n
) {
41 if (ascii_isdigit(e
[0]))
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. */
47 if (_unlikely_(n
> sc_arg_max() - 2))
50 for (const char *p
= e
; p
< e
+ n
; p
++)
51 if (!strchr(VALID_BASH_ENV_NAME_CHARS
, *p
))
57 bool env_name_is_valid(const char *e
) {
58 return env_name_is_valid_n(e
, SIZE_MAX
);
61 bool env_value_is_valid(const char *e
) {
65 if (!utf8_is_valid(e
))
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! */
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. */
75 if (_unlikely_(strlen(e
) > sc_arg_max() - 3))
81 bool env_assignment_is_valid(const char *e
) {
90 if (!env_name_is_valid_n(e
, eq
- e
))
93 if (!env_value_is_valid(eq
+ 1))
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. */
98 if (_unlikely_(strlen(e
) > sc_arg_max() - 1))
104 bool strv_env_is_valid(char * const *e
) {
108 if (!env_assignment_is_valid(*p
))
111 /* Check if there are duplicate assignments */
112 k
= strcspn(*p
, "=");
113 STRV_FOREACH(q
, p
+ 1)
114 if (strneq(*p
, *q
, k
) && (*q
)[k
] == '=')
121 bool strv_env_name_is_valid(char * const *l
) {
123 if (!env_name_is_valid(*p
))
126 if (strv_contains(p
+ 1, *p
))
133 bool strv_env_name_or_assignment_is_valid(char * const *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 **e
, char ***k
, char **a
) {
153 /* Expects the following arguments: 'e' 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 'e', either overriding an existing matching entry, or appending to it.
158 * This call assumes 'e' has enough pre-allocated space to grow by all of 'a''s items. */
164 n
= strcspn(*a
, "=");
168 for (j
= e
; 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 t
= startswith(t
, pattern
);
254 return t
&& *t
== '=';
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
, ...) {
275 _cleanup_strv_free_
char **t
= NULL
;
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
))
317 char** strv_env_unset(char **l
, const char *p
) {
323 /* Drops every occurrence of the env var setting p in the
324 * string list. Edits in-place. */
327 for (f
= t
= l
; *f
; f
++) {
328 if (env_match(*f
, p
)) {
340 char** strv_env_unset_many_internal(char **l
, ...) {
344 /* Like strv_env_unset() but applies many at once. Edits in-place. */
347 for (f
= t
= l
; *f
; f
++) {
354 while ((p
= va_arg(ap
, const char*)))
355 if (env_match(*f
, p
)) {
374 int strv_env_replace_consume(char ***l
, char *p
) {
375 const char *t
, *name
;
381 /* Replace first occurrence of the env var or add a new one in the string list. Drop other
382 * occurrences. Edits in-place. Does not copy p and CONSUMES p EVEN ON FAILURE.
384 * p must be a valid key=value assignment. */
392 name
= strndupa_safe(p
, t
- p
);
395 if (env_entry_has_name(*f
, name
)) {
396 free_and_replace(*f
, p
);
397 strv_env_unset(f
+ 1, *f
);
401 /* We didn't find a match, we need to append p or create a new strv */
402 r
= strv_consume(l
, p
);
409 int strv_env_replace_strdup(char ***l
, const char *assignment
) {
410 /* Like strv_env_replace_consume(), but copies the argument. */
415 char *p
= strdup(assignment
);
419 return strv_env_replace_consume(l
, p
);
422 int strv_env_replace_strdup_passthrough(char ***l
, const char *assignment
) {
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. */
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
) {
454 if (!env_name_is_valid(key
))
457 /* NULL removes assignment, "" creates an empty assignment. */
460 strv_env_unset(*l
, key
);
464 char *p
= strjoin(key
, "=", value
);
468 return strv_env_replace_consume(l
, p
);
471 int strv_env_assignf(char ***l
, const char *key
, const char *valuef
, ...) {
477 if (!env_name_is_valid(key
))
481 strv_env_unset(*l
, key
);
485 _cleanup_free_
char *value
= NULL
;
487 va_start(ap
, valuef
);
488 r
= vasprintf(&value
, valuef
, ap
);
493 char *p
= strjoin(key
, "=", value
);
497 return strv_env_replace_consume(l
, p
);
500 int _strv_env_assign_many(char ***l
, ...) {
508 const char *key
, *value
;
510 key
= va_arg(ap
, const char *);
514 if (!env_name_is_valid(key
)) {
519 value
= va_arg(ap
, const char *);
521 strv_env_unset(*l
, key
);
525 char *p
= strjoin(key
, "=", value
);
531 r
= strv_env_replace_consume(l
, p
);
542 char* strv_env_get_n(char * const *l
, const char *name
, size_t k
, ReplaceEnvFlags flags
) {
550 STRV_FOREACH_BACKWARDS(i
, l
)
551 if (strneq(*i
, name
, k
) && (*i
)[k
] == '=')
552 return (char*) *i
+ k
+ 1;
554 if (flags
& REPLACE_ENV_USE_ENVIRONMENT
) {
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)
561 t
= strndupa_safe(name
, k
);
562 return secure_getenv(t
);
568 char* strv_env_pairs_get(char **l
, const char *name
) {
573 STRV_FOREACH_PAIR(key
, value
, l
)
574 if (streq(*key
, name
))
580 int strv_env_get_merged(char **l
, char ***ret
) {
581 _cleanup_strv_free_
char **v
= NULL
;
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" } */
592 STRV_FOREACH_PAIR(key
, value
, l
) {
595 s
= strjoin(*key
, "=", *value
);
599 r
= strv_consume_with_size(&v
, &n
, s
);
608 char** strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
613 bool duplicate
= false;
615 if (!env_assignment_is_valid(*p
)) {
616 if (invalid_callback
)
617 invalid_callback(*p
, userdata
);
622 n
= strcspn(*p
, "=");
623 STRV_FOREACH(q
, p
+ 1)
624 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
643 static int strv_extend_with_length(char ***l
, const char *s
, size_t n
) {
650 return strv_consume(l
, c
);
653 static int strv_env_get_n_validated(
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 */
665 assert(l
== 0 || name
);
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
);
676 e
= NULL
; /* Resolve invalid variable names the same way as unset ones */
679 r
= strv_extend_with_length(bad_variables
, name
, l
);
689 int replace_env_full(
693 ReplaceEnvFlags flags
,
695 char ***ret_unset_variables
,
696 char ***ret_bad_variables
) {
708 _cleanup_strv_free_
char **unset_variables
= NULL
, **bad_variables
= NULL
;
709 const char *e
, *word
= format
, *test_value
= NULL
; /* test_value is initialized to appease gcc */
710 _cleanup_free_
char *s
= NULL
;
712 size_t i
, len
= 0; /* len is initialized to appease gcc */
717 if (length
== SIZE_MAX
)
718 length
= strlen(format
);
720 pu
= ret_unset_variables
? &unset_variables
: NULL
;
721 pb
= ret_bad_variables
? &bad_variables
: NULL
;
723 for (e
= format
, i
= 0; *e
&& i
< length
; e
++, i
++)
733 if (!strextendn(&s
, word
, e
-word
-1))
740 } else if (*e
== '$') {
741 if (!strextendn(&s
, word
, e
-word
))
747 } else if (FLAGS_SET(flags
, REPLACE_ENV_ALLOW_BRACELESS
) && strchr(VALID_BASH_ENV_NAME_CHARS
, *e
)) {
748 if (!strextendn(&s
, word
, e
-word
-1))
752 state
= VARIABLE_RAW
;
762 r
= strv_env_get_n_validated(env
, word
+2, e
-word
-2, flags
, &t
, pu
, pb
);
766 if (!strextend(&s
, t
))
772 } else if (*e
== ':') {
773 if (flags
& REPLACE_ENV_ALLOW_EXTENDED
) {
777 /* Treat this as unsupported syntax, i.e. do no replacement */
784 state
= DEFAULT_VALUE
;
786 state
= ALTERNATE_VALUE
;
795 case DEFAULT_VALUE
: /* fall through */
796 case ALTERNATE_VALUE
:
797 assert(flags
& REPLACE_ENV_ALLOW_EXTENDED
);
809 _cleanup_strv_free_
char **u
= NULL
, **b
= NULL
;
810 _cleanup_free_
char *v
= NULL
;
813 r
= strv_env_get_n_validated(env
, word
+2, len
, flags
, &t
, pu
, pb
);
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
);
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
);
831 r
= strv_extend_strv_consume(&unset_variables
, TAKE_PTR(u
), /* filter_duplicates= */ true);
834 r
= strv_extend_strv_consume(&bad_variables
, TAKE_PTR(b
), /* filter_duplicates= */ true);
838 if (!strextend(&s
, t
))
847 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
849 if (!strchr(VALID_BASH_ENV_NAME_CHARS
, *e
)) {
852 r
= strv_env_get_n_validated(env
, word
+1, e
-word
-1, flags
, &t
, &unset_variables
, &bad_variables
);
856 if (!strextend(&s
, t
))
866 if (state
== VARIABLE_RAW
) {
869 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
871 r
= strv_env_get_n_validated(env
, word
+1, e
-word
-1, flags
, &t
, &unset_variables
, &bad_variables
);
875 if (!strextend(&s
, t
))
878 } else if (!strextendn(&s
, word
, e
-word
))
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
);
892 int replace_env_argv(
896 char ***ret_unset_variables
,
897 char ***ret_bad_variables
) {
899 _cleanup_strv_free_
char **n
= NULL
, **unset_variables
= NULL
, **bad_variables
= NULL
;
903 assert(!strv_isempty(argv
));
906 l
= strv_length(argv
);
912 STRV_FOREACH(i
, argv
) {
913 const char *word
= *i
;
915 /* If $FOO appears as single word, replace it by the split up variable */
916 if (word
[0] == '$' && !IN_SET(word
[1], '{', '$')) {
917 _cleanup_strv_free_
char **m
= NULL
;
918 const char *name
= word
+ 1;
922 if (env_name_is_valid(name
)) {
923 e
= strv_env_get(env
, name
);
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
);
930 } else if (ret_bad_variables
)
931 r
= strv_extend(&bad_variables
, name
);
940 w
= reallocarray(n
, l
+ 1, sizeof(char*));
946 memcpy(n
+ k
, m
, (q
+ 1) * sizeof(char*));
954 _cleanup_strv_free_
char **u
= NULL
, **b
= NULL
;
956 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
957 r
= replace_env_full(
959 /* length= */ SIZE_MAX
,
963 ret_unset_variables
? &u
: NULL
,
964 ret_bad_variables
? &b
: NULL
);
969 r
= strv_extend_strv_consume(&unset_variables
, TAKE_PTR(u
), /* filter_duplicates= */ true);
973 r
= strv_extend_strv_consume(&bad_variables
, TAKE_PTR(b
), /* filter_duplicates= */ true);
978 if (ret_unset_variables
) {
979 strv_sort_uniq(unset_variables
);
980 *ret_unset_variables
= TAKE_PTR(unset_variables
);
982 if (ret_bad_variables
) {
983 strv_sort_uniq(bad_variables
);
984 *ret_bad_variables
= TAKE_PTR(bad_variables
);
991 int getenv_bool(const char *p
) {
998 return parse_boolean(e
);
1001 int secure_getenv_bool(const char *p
) {
1004 e
= secure_getenv(p
);
1008 return parse_boolean(e
);
1011 int secure_getenv_uint64(const char *p
, uint64_t *ret
) {
1016 e
= secure_getenv(p
);
1020 return safe_atou64(e
, ret
);
1023 int set_unset_env(const char *name
, const char *value
, bool overwrite
) {
1027 return RET_NERRNO(setenv(name
, value
, overwrite
));
1029 return RET_NERRNO(unsetenv(name
));
1032 int putenv_dup(const char *assignment
, bool override
) {
1035 e
= strchr(assignment
, '=');
1039 n
= strndupa_safe(assignment
, e
- assignment
);
1041 /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
1042 return RET_NERRNO(setenv(n
, e
+ 1, override
));
1045 int setenv_systemd_exec_pid(bool update_only
) {
1049 /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
1051 e
= secure_getenv("SYSTEMD_EXEC_PID");
1052 if (!e
&& update_only
)
1055 if (streq_ptr(e
, "*"))
1058 r
= setenvf("SYSTEMD_EXEC_PID", /* overwrite= */ 1, PID_FMT
, getpid_cached());
1065 int setenv_systemd_log_level(void) {
1066 _cleanup_free_
char *val
= NULL
;
1069 r
= log_level_to_string_alloc(log_get_max_level(), &val
);
1073 return RET_NERRNO(setenv("SYSTEMD_LOG_LEVEL", val
, /* overwrite= */ true));
1076 int getenv_path_list(const char *name
, char ***ret_paths
) {
1077 _cleanup_strv_free_
char **l
= NULL
;
1084 e
= secure_getenv(name
);
1088 r
= strv_split_full(&l
, e
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
1090 return log_debug_errno(r
, "Failed to parse $%s: %m", name
);
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
);
1097 if (!path_is_normalized(*p
))
1098 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
1099 "Path '%s' is not normalized, refusing.", *p
);
1101 if (path_equal(*p
, "/"))
1102 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
1103 "Path '%s' is the root fs, refusing.", *p
);
1106 if (strv_isempty(l
))
1107 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
1108 "No paths specified, refusing.");
1110 *ret_paths
= TAKE_PTR(l
);
1114 int getenv_steal_erase(const char *name
, char **ret
) {
1115 _cleanup_(erase_and_freep
) char *a
= NULL
;
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) */
1124 e
= secure_getenv(name
);
1139 if (unsetenv(name
) < 0)
1148 int setenvf(const char *name
, bool overwrite
, const char *valuef
, ...) {
1149 _cleanup_free_
char *value
= NULL
;
1156 return RET_NERRNO(unsetenv(name
));
1158 va_start(ap
, valuef
);
1159 r
= vasprintf(&value
, valuef
, ap
);
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
))
1170 return RET_NERRNO(setenv(name
, value
, overwrite
));