1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Lennart Poettering
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.
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.
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/>.
28 #include "alloc-util.h"
31 #include "extract-word.h"
33 #include "parse-util.h"
34 #include "string-util.h"
38 #define VALID_CHARS_ENV_NAME \
43 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
46 static bool env_name_is_valid_n(const char *e
, size_t n
) {
55 if (e
[0] >= '0' && e
[0] <= '9')
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
66 for (p
= e
; p
< e
+ n
; p
++)
67 if (!strchr(VALID_CHARS_ENV_NAME
, *p
))
73 bool env_name_is_valid(const char *e
) {
77 return env_name_is_valid_n(e
, strlen(e
));
80 bool env_value_is_valid(const char *e
) {
84 if (!utf8_is_valid(e
))
87 /* bash allows tabs in environment variables, and so should
89 if (string_has_cc(e
, "\t"))
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)
103 bool env_assignment_is_valid(const char *e
) {
110 if (!env_name_is_valid_n(e
, eq
- e
))
113 if (!env_value_is_valid(eq
+ 1))
116 /* POSIX says the overall size of the environment block cannot
117 * be > ARG_MAX, hence the individual variable assignments
118 * cannot be either, but let's leave room for one trailing NUL
120 if (strlen(e
) > ARG_MAX
- 1)
126 bool strv_env_is_valid(char **e
) {
132 if (!env_assignment_is_valid(*p
))
135 /* Check if there are duplicate assginments */
136 k
= strcspn(*p
, "=");
137 STRV_FOREACH(q
, p
+ 1)
138 if (strneq(*p
, *q
, k
) && (*q
)[k
] == '=')
145 bool strv_env_name_is_valid(char **l
) {
149 if (!env_name_is_valid(*p
))
152 STRV_FOREACH(q
, p
+ 1)
160 bool strv_env_name_or_assignment_is_valid(char **l
) {
164 if (!env_assignment_is_valid(*p
) && !env_name_is_valid(*p
))
167 STRV_FOREACH(q
, p
+ 1)
175 static int env_append(char **r
, char ***k
, char **a
) {
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. */
190 n
= strcspn(*a
, "=");
195 for (j
= r
; j
< *k
; j
++)
196 if (strneq(*j
, *a
, n
))
212 char **strv_env_merge(unsigned n_lists
, ...) {
218 /* Merges an arbitrary number of environment sets */
220 va_start(ap
, n_lists
);
221 for (i
= 0; i
< n_lists
; i
++) {
222 l
= va_arg(ap
, char**);
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)
252 static bool env_match(const char *t
, const char *pattern
) {
256 /* pattern a matches string a
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 */
266 if (streq(t
, pattern
))
269 if (!strchr(pattern
, '=')) {
270 size_t l
= strlen(pattern
);
272 return strneq(t
, pattern
, l
) && t
[l
] == '=';
278 static bool env_entry_has_name(const char *entry
, const char *name
) {
284 t
= startswith(entry
, name
);
291 char **strv_env_delete(char **x
, unsigned n_lists
, ...) {
296 /* Deletes every entry from x that is mentioned in the other
308 va_start(ap
, n_lists
);
309 for (v
= 0; v
< n_lists
; v
++) {
312 l
= va_arg(ap
, char**);
314 if (env_match(*k
, *j
))
339 char **strv_env_unset(char **l
, const char *p
) {
348 /* Drops every occurrence of the env var setting p in the
349 * string list. Edits in-place. */
351 for (f
= t
= l
; *f
; f
++) {
353 if (env_match(*f
, p
)) {
365 char **strv_env_unset_many(char **l
, ...) {
372 /* Like strv_env_unset() but applies many at once. Edits in-place. */
374 for (f
= t
= l
; *f
; f
++) {
381 while ((p
= va_arg(ap
, const char*))) {
382 if (env_match(*f
, p
)) {
402 int strv_env_replace(char ***l
, char *p
) {
404 const char *t
, *name
;
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.
410 * p must be a valid key=value assignment.
416 name
= strndupa(p
, t
- p
);
418 for (f
= *l
; f
&& *f
; f
++)
419 if (env_entry_has_name(*f
, name
)) {
420 free_and_replace(*f
, p
);
421 strv_env_unset(f
+ 1, *f
);
425 /* We didn't find a match, we need to append p or create a new strv */
426 if (strv_push(l
, p
) < 0)
431 char **strv_env_set(char **x
, const char *p
) {
434 char* m
[2] = { (char*) p
, NULL
};
436 /* Overrides the env var setting of p, returns a new copy */
438 r
= new(char*, strv_length(x
)+2);
443 if (env_append(r
, &k
, x
) < 0)
446 if (env_append(r
, &k
, m
) < 0)
458 char *strv_env_get_n(char **l
, const char *name
, size_t k
, unsigned flags
) {
466 STRV_FOREACH_BACKWARDS(i
, l
)
467 if (strneq(*i
, name
, k
) &&
471 if (flags
& REPLACE_ENV_USE_ENVIRONMENT
) {
474 t
= strndupa(name
, k
);
481 char *strv_env_get(char **l
, const char *name
) {
484 return strv_env_get_n(l
, name
, strlen(name
), 0);
487 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
493 bool duplicate
= false;
495 if (!env_assignment_is_valid(*p
)) {
496 if (invalid_callback
)
497 invalid_callback(*p
, userdata
);
502 n
= strcspn(*p
, "=");
503 STRV_FOREACH(q
, p
+ 1)
504 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
523 char *replace_env_n(const char *format
, size_t n
, char **env
, unsigned flags
) {
534 const char *e
, *word
= format
, *test_value
;
536 _cleanup_free_
char *r
= NULL
;
542 for (e
= format
, i
= 0; *e
&& i
< n
; e
++, i
++) {
553 k
= strnappend(r
, word
, e
-word
-1);
563 } else if (*e
== '$') {
564 k
= strnappend(r
, word
, e
-word
);
574 } else if (flags
& REPLACE_ENV_ALLOW_BRACELESS
&& strchr(VALID_CHARS_ENV_NAME
, *e
)) {
575 k
= strnappend(r
, word
, e
-word
-1);
583 state
= VARIABLE_RAW
;
593 t
= strv_env_get_n(env
, word
+2, e
-word
-2, flags
);
604 } else if (*e
== ':') {
605 if (!(flags
& REPLACE_ENV_ALLOW_EXTENDED
))
606 /* Treat this as unsupported syntax, i.e. do no replacement */
617 state
= DEFAULT_VALUE
;
619 state
= ALTERNATE_VALUE
;
628 case DEFAULT_VALUE
: /* fall through */
629 case ALTERNATE_VALUE
:
630 assert(flags
& REPLACE_ENV_ALLOW_EXTENDED
);
643 _cleanup_free_
char *v
= NULL
;
645 t
= strv_env_get_n(env
, word
+2, len
, flags
);
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
);
665 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
667 if (!strchr(VALID_CHARS_ENV_NAME
, *e
)) {
670 t
= strv_env_get_n(env
, word
+1, e
-word
-1, flags
);
687 if (state
== VARIABLE_RAW
) {
690 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
692 t
= strv_env_get_n(env
, word
+1, e
-word
-1, flags
);
693 return strappend(r
, t
);
695 return strnappend(r
, word
, e
-word
);
698 char **replace_env_argv(char **argv
, char **env
) {
700 unsigned k
= 0, l
= 0;
702 l
= strv_length(argv
);
704 ret
= new(char*, l
+1);
708 STRV_FOREACH(i
, argv
) {
710 /* If $FOO appears as single word, replace it by the split up variable */
711 if ((*i
)[0] == '$' && !IN_SET((*i
)[1], '{', '$')) {
713 char **w
, **m
= NULL
;
716 e
= strv_env_get(env
, *i
+1);
720 r
= strv_split_extract(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_QUOTES
);
732 w
= realloc(ret
, sizeof(char*) * (l
+1));
742 memcpy(ret
+ k
, m
, q
* sizeof(char*));
750 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
751 ret
[k
] = replace_env(*i
, env
, 0);
763 int getenv_bool(const char *p
) {
770 return parse_boolean(e
);
773 int getenv_bool_secure(const char *p
) {
776 e
= secure_getenv(p
);
780 return parse_boolean(e
);
783 int serialize_environment(FILE *f
, char **environment
) {
786 STRV_FOREACH(e
, environment
) {
787 _cleanup_free_
char *ce
;
793 fprintf(f
, "env=%s\n", ce
);
796 /* caller should call ferror() */
801 int deserialize_environment(char ***environment
, const char *line
) {
808 assert(startswith(line
, "env="));
809 r
= cunescape(line
+ 4, 0, &uce
);
813 return strv_env_replace(environment
, uce
);