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 #if 0 /// UNNEEDED by elogind
127 bool strv_env_is_valid(char **e) {
133 if (!env_assignment_is_valid(*p))
136 /* Check if there are duplicate assginments */
137 k = strcspn(*p, "=");
138 STRV_FOREACH(q, p + 1)
139 if (strneq(*p, *q, k) && (*q)[k] == '=')
146 bool strv_env_name_is_valid(char **l) {
150 if (!env_name_is_valid(*p))
153 STRV_FOREACH(q, p + 1)
161 bool strv_env_name_or_assignment_is_valid(char **l) {
165 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
168 STRV_FOREACH(q, p + 1)
176 static int env_append(char **r, char ***k, char **a) {
183 /* Add the entries of a to *k unless they already exist in *r
184 * in which case they are overridden instead. This assumes
185 * there is enough space in the r array. */
191 n = strcspn(*a, "=");
196 for (j = r; j < *k; j++)
197 if (strneq(*j, *a, n))
213 char **strv_env_merge(unsigned n_lists, ...) {
219 /* Merges an arbitrary number of environment sets */
221 va_start(ap, n_lists);
222 for (i = 0; i < n_lists; i++) {
223 l = va_arg(ap, char**);
234 va_start(ap, n_lists);
235 for (i = 0; i < n_lists; i++) {
236 l = va_arg(ap, char**);
237 if (env_append(r, &k, l) < 0)
253 static bool env_match(const char *t, const char *pattern) {
257 /* pattern a matches string a
262 * a= does not match a
263 * a=b does not match a=
264 * a=b does not match a
265 * a=b does not match a=c */
267 if (streq(t, pattern))
270 if (!strchr(pattern, '=')) {
271 size_t l = strlen(pattern);
273 return strneq(t, pattern, l) && t[l] == '=';
279 static bool env_entry_has_name(const char *entry, const char *name) {
285 t = startswith(entry, name);
292 char **strv_env_delete(char **x, unsigned n_lists, ...) {
297 /* Deletes every entry from x that is mentioned in the other
309 va_start(ap, n_lists);
310 for (v = 0; v < n_lists; v++) {
313 l = va_arg(ap, char**);
315 if (env_match(*k, *j))
340 char **strv_env_unset(char **l, const char *p) {
349 /* Drops every occurrence of the env var setting p in the
350 * string list. Edits in-place. */
352 for (f = t = l; *f; f++) {
354 if (env_match(*f, p)) {
366 char **strv_env_unset_many(char **l, ...) {
373 /* Like strv_env_unset() but applies many at once. Edits in-place. */
375 for (f = t = l; *f; f++) {
382 while ((p = va_arg(ap, const char*))) {
383 if (env_match(*f, p)) {
403 int strv_env_replace(char ***l, char *p) {
405 const char *t, *name;
409 /* Replace first occurrence of the env var or add a new one in the
410 * string list. Drop other occurences. Edits in-place. Does not copy p.
411 * p must be a valid key=value assignment.
417 name = strndupa(p, t - p);
419 for (f = *l; f && *f; f++)
420 if (env_entry_has_name(*f, name)) {
421 free_and_replace(*f, p);
422 strv_env_unset(f + 1, *f);
426 /* We didn't find a match, we need to append p or create a new strv */
427 if (strv_push(l, p) < 0)
432 char **strv_env_set(char **x, const char *p) {
435 char* m[2] = { (char*) p, NULL };
437 /* Overrides the env var setting of p, returns a new copy */
439 r = new(char*, strv_length(x)+2);
444 if (env_append(r, &k, x) < 0)
447 if (env_append(r, &k, m) < 0)
459 char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
467 STRV_FOREACH_BACKWARDS(i, l)
468 if (strneq(*i, name, k) &&
472 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
475 t = strndupa(name, k);
482 char *strv_env_get(char **l, const char *name) {
485 return strv_env_get_n(l, name, strlen(name), 0);
488 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
494 bool duplicate = false;
496 if (!env_assignment_is_valid(*p)) {
497 if (invalid_callback)
498 invalid_callback(*p, userdata);
503 n = strcspn(*p, "=");
504 STRV_FOREACH(q, p + 1)
505 if (strneq(*p, *q, n) && (*q)[n] == '=') {
524 char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
535 const char *e, *word = format, *test_value;
537 _cleanup_free_ char *r = NULL;
543 for (e = format, i = 0; *e && i < n; e ++, i ++) {
554 k = strnappend(r, word, e-word-1);
564 } else if (*e == '$') {
565 k = strnappend(r, word, e-word);
575 } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
576 k = strnappend(r, word, e-word-1);
584 state = VARIABLE_RAW;
594 t = strv_env_get_n(env, word+2, e-word-2, flags);
605 } else if (*e == ':') {
606 if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
607 /* Treat this as unsupported syntax, i.e. do no replacement */
618 state = DEFAULT_VALUE;
620 state = ALTERNATE_VALUE;
629 case DEFAULT_VALUE: /* fall through */
630 case ALTERNATE_VALUE:
631 assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
644 _cleanup_free_ char *v = NULL;
646 t = strv_env_get_n(env, word+2, len, flags);
648 if (t && state == ALTERNATE_VALUE)
649 t = v = replace_env_n(test_value, e-test_value, env, flags);
650 else if (!t && state == DEFAULT_VALUE)
651 t = v = replace_env_n(test_value, e-test_value, env, flags);
666 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
668 if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
671 t = strv_env_get_n(env, word+1, e-word-1, flags);
688 if (state == VARIABLE_RAW) {
691 assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
693 t = strv_env_get_n(env, word+1, e-word-1, flags);
694 return strappend(r, t);
696 return strnappend(r, word, e-word);
699 char **replace_env_argv(char **argv, char **env) {
701 unsigned k = 0, l = 0;
703 l = strv_length(argv);
705 ret = new(char*, l+1);
709 STRV_FOREACH(i, argv) {
711 /* If $FOO appears as single word, replace it by the split up variable */
712 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
714 char **w, **m = NULL;
717 e = strv_env_get(env, *i+1);
721 r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES);
733 w = realloc(ret, sizeof(char*) * (l+1));
743 memcpy(ret + k, m, q * sizeof(char*));
751 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
752 ret[k] = replace_env(*i, env, 0);
764 int getenv_bool(const char *p) {
771 return parse_boolean(e);
774 int getenv_bool_secure(const char *p) {
777 e = secure_getenv(p);
781 return parse_boolean(e);
784 int serialize_environment(FILE *f, char **environment) {
787 STRV_FOREACH(e, environment) {
788 _cleanup_free_ char *ce;
794 fprintf(f, "env=%s\n", ce);
797 /* caller should call ferror() */
802 int deserialize_environment(char ***environment, const char *line) {
809 assert(startswith(line, "env="));
810 r = cunescape(line + 4, 0, &uce);
814 return strv_env_replace(environment, uce);