2 This file is part of systemd.
4 Copyright 2012 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "alloc-util.h"
30 #include "extract-word.h"
32 #include "parse-util.h"
33 #include "string-util.h"
37 #define VALID_CHARS_ENV_NAME \
42 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
45 static bool env_name_is_valid_n(const char *e
, size_t n
) {
54 if (e
[0] >= '0' && e
[0] <= '9')
57 /* POSIX says the overall size of the environment block cannot
58 * be > ARG_MAX, an individual assignment hence cannot be
59 * either. Discounting the equal sign and trailing NUL this
60 * hence leaves ARG_MAX-2 as longest possible variable
65 for (p
= e
; p
< e
+ n
; p
++)
66 if (!strchr(VALID_CHARS_ENV_NAME
, *p
))
72 bool env_name_is_valid(const char *e
) {
76 return env_name_is_valid_n(e
, strlen(e
));
79 bool env_value_is_valid(const char *e
) {
83 if (!utf8_is_valid(e
))
86 /* bash allows tabs in environment variables, and so should
88 if (string_has_cc(e
, "\t"))
91 /* POSIX says the overall size of the environment block cannot
92 * be > ARG_MAX, an individual assignment hence cannot be
93 * either. Discounting the shortest possible variable name of
94 * length 1, the equal sign and trailing NUL this hence leaves
95 * ARG_MAX-3 as longest possible variable value. */
96 if (strlen(e
) > ARG_MAX
- 3)
102 bool env_assignment_is_valid(const char *e
) {
109 if (!env_name_is_valid_n(e
, eq
- e
))
112 if (!env_value_is_valid(eq
+ 1))
115 /* POSIX says the overall size of the environment block cannot
116 * be > ARG_MAX, hence the individual variable assignments
117 * cannot be either, but let's leave room for one trailing NUL
119 if (strlen(e
) > ARG_MAX
- 1)
125 bool strv_env_is_valid(char **e
) {
131 if (!env_assignment_is_valid(*p
))
134 /* Check if there are duplicate assginments */
135 k
= strcspn(*p
, "=");
136 STRV_FOREACH(q
, p
+ 1)
137 if (strneq(*p
, *q
, k
) && (*q
)[k
] == '=')
144 bool strv_env_name_is_valid(char **l
) {
148 if (!env_name_is_valid(*p
))
151 STRV_FOREACH(q
, p
+ 1)
159 bool strv_env_name_or_assignment_is_valid(char **l
) {
163 if (!env_assignment_is_valid(*p
) && !env_name_is_valid(*p
))
166 STRV_FOREACH(q
, p
+ 1)
174 static int env_append(char **r
, char ***k
, char **a
) {
181 /* Add the entries of a to *k unless they already exist in *r
182 * in which case they are overridden instead. This assumes
183 * there is enough space in the r array. */
189 n
= strcspn(*a
, "=");
194 for (j
= r
; j
< *k
; j
++)
195 if (strneq(*j
, *a
, n
))
211 char **strv_env_merge(unsigned n_lists
, ...) {
217 /* Merges an arbitrary number of environment sets */
219 va_start(ap
, n_lists
);
220 for (i
= 0; i
< n_lists
; i
++) {
221 l
= va_arg(ap
, char**);
232 va_start(ap
, n_lists
);
233 for (i
= 0; i
< n_lists
; i
++) {
234 l
= va_arg(ap
, char**);
235 if (env_append(r
, &k
, l
) < 0)
251 static bool env_match(const char *t
, const char *pattern
) {
255 /* pattern a matches string a
260 * a= does not match a
261 * a=b does not match a=
262 * a=b does not match a
263 * a=b does not match a=c */
265 if (streq(t
, pattern
))
268 if (!strchr(pattern
, '=')) {
269 size_t l
= strlen(pattern
);
271 return strneq(t
, pattern
, l
) && t
[l
] == '=';
277 static bool env_entry_has_name(const char *entry
, const char *name
) {
283 t
= startswith(entry
, name
);
290 char **strv_env_delete(char **x
, unsigned n_lists
, ...) {
295 /* Deletes every entry from x that is mentioned in the other
307 va_start(ap
, n_lists
);
308 for (v
= 0; v
< n_lists
; v
++) {
311 l
= va_arg(ap
, char**);
313 if (env_match(*k
, *j
))
338 char **strv_env_unset(char **l
, const char *p
) {
347 /* Drops every occurrence of the env var setting p in the
348 * string list. Edits in-place. */
350 for (f
= t
= l
; *f
; f
++) {
352 if (env_match(*f
, p
)) {
364 char **strv_env_unset_many(char **l
, ...) {
371 /* Like strv_env_unset() but applies many at once. Edits in-place. */
373 for (f
= t
= l
; *f
; f
++) {
380 while ((p
= va_arg(ap
, const char*))) {
381 if (env_match(*f
, p
)) {
401 int strv_env_replace(char ***l
, char *p
) {
403 const char *t
, *name
;
407 /* Replace first occurrence of the env var or add a new one in the
408 * string list. Drop other occurences. Edits in-place. Does not copy p.
409 * p must be a valid key=value assignment.
415 name
= strndupa(p
, t
- p
);
417 for (f
= *l
; f
&& *f
; f
++)
418 if (env_entry_has_name(*f
, name
)) {
419 free_and_replace(*f
, p
);
420 strv_env_unset(f
+ 1, *f
);
424 /* We didn't find a match, we need to append p or create a new strv */
425 if (strv_push(l
, p
) < 0)
430 char **strv_env_set(char **x
, const char *p
) {
433 char* m
[2] = { (char*) p
, NULL
};
435 /* Overrides the env var setting of p, returns a new copy */
437 r
= new(char*, strv_length(x
)+2);
442 if (env_append(r
, &k
, x
) < 0)
445 if (env_append(r
, &k
, m
) < 0)
457 char *strv_env_get_n(char **l
, const char *name
, size_t k
, unsigned flags
) {
465 STRV_FOREACH_BACKWARDS(i
, l
)
466 if (strneq(*i
, name
, k
) &&
470 if (flags
& REPLACE_ENV_USE_ENVIRONMENT
) {
473 t
= strndupa(name
, k
);
480 char *strv_env_get(char **l
, const char *name
) {
483 return strv_env_get_n(l
, name
, strlen(name
), 0);
486 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
492 bool duplicate
= false;
494 if (!env_assignment_is_valid(*p
)) {
495 if (invalid_callback
)
496 invalid_callback(*p
, userdata
);
501 n
= strcspn(*p
, "=");
502 STRV_FOREACH(q
, p
+ 1)
503 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
522 char *replace_env_n(const char *format
, size_t n
, char **env
, unsigned flags
) {
533 const char *e
, *word
= format
, *test_value
;
535 _cleanup_free_
char *r
= NULL
;
541 for (e
= format
, i
= 0; *e
&& i
< n
; e
++, i
++) {
552 k
= strnappend(r
, word
, e
-word
-1);
562 } else if (*e
== '$') {
563 k
= strnappend(r
, word
, e
-word
);
573 } else if (flags
& REPLACE_ENV_ALLOW_BRACELESS
&& strchr(VALID_CHARS_ENV_NAME
, *e
)) {
574 k
= strnappend(r
, word
, e
-word
-1);
582 state
= VARIABLE_RAW
;
592 t
= strv_env_get_n(env
, word
+2, e
-word
-2, flags
);
603 } else if (*e
== ':') {
604 if (!(flags
& REPLACE_ENV_ALLOW_EXTENDED
))
605 /* Treat this as unsupported syntax, i.e. do no replacement */
616 state
= DEFAULT_VALUE
;
618 state
= ALTERNATE_VALUE
;
627 case DEFAULT_VALUE
: /* fall through */
628 case ALTERNATE_VALUE
:
629 assert(flags
& REPLACE_ENV_ALLOW_EXTENDED
);
642 _cleanup_free_
char *v
= NULL
;
644 t
= strv_env_get_n(env
, word
+2, len
, flags
);
646 if (t
&& state
== ALTERNATE_VALUE
)
647 t
= v
= replace_env_n(test_value
, e
-test_value
, env
, flags
);
648 else if (!t
&& state
== DEFAULT_VALUE
)
649 t
= v
= replace_env_n(test_value
, e
-test_value
, env
, flags
);
664 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
666 if (!strchr(VALID_CHARS_ENV_NAME
, *e
)) {
669 t
= strv_env_get_n(env
, word
+1, e
-word
-1, flags
);
686 if (state
== VARIABLE_RAW
) {
689 assert(flags
& REPLACE_ENV_ALLOW_BRACELESS
);
691 t
= strv_env_get_n(env
, word
+1, e
-word
-1, flags
);
692 return strappend(r
, t
);
694 return strnappend(r
, word
, e
-word
);
697 char **replace_env_argv(char **argv
, char **env
) {
699 unsigned k
= 0, l
= 0;
701 l
= strv_length(argv
);
703 ret
= new(char*, l
+1);
707 STRV_FOREACH(i
, argv
) {
709 /* If $FOO appears as single word, replace it by the split up variable */
710 if ((*i
)[0] == '$' && !IN_SET((*i
)[1], '{', '$')) {
712 char **w
, **m
= NULL
;
715 e
= strv_env_get(env
, *i
+1);
719 r
= strv_split_extract(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_QUOTES
);
731 w
= realloc(ret
, sizeof(char*) * (l
+1));
741 memcpy(ret
+ k
, m
, q
* sizeof(char*));
749 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
750 ret
[k
] = replace_env(*i
, env
, 0);
762 int getenv_bool(const char *p
) {
769 return parse_boolean(e
);
772 int getenv_bool_secure(const char *p
) {
775 e
= secure_getenv(p
);
779 return parse_boolean(e
);
782 int serialize_environment(FILE *f
, char **environment
) {
785 STRV_FOREACH(e
, environment
) {
786 _cleanup_free_
char *ce
;
792 fprintf(f
, "env=%s\n", ce
);
795 /* caller should call ferror() */
800 int deserialize_environment(char ***environment
, const char *line
) {
807 assert(startswith(line
, "env="));
808 r
= cunescape(line
+ 4, UNESCAPE_RELAX
, &uce
);
812 if (!env_assignment_is_valid(uce
)) {
817 return strv_env_replace(environment
, uce
);