]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/env-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
28 #include "parse-util.h"
29 #include "string-util.h"
34 #define VALID_CHARS_ENV_NAME \
39 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
42 static bool env_name_is_valid_n(const char *e
, size_t n
) {
51 if (e
[0] >= '0' && e
[0] <= '9')
54 /* POSIX says the overall size of the environment block cannot
55 * be > ARG_MAX, an individual assignment hence cannot be
56 * either. Discounting the equal sign and trailing NUL this
57 * hence leaves ARG_MAX-2 as longest possible variable
62 for (p
= e
; p
< e
+ n
; p
++)
63 if (!strchr(VALID_CHARS_ENV_NAME
, *p
))
69 bool env_name_is_valid(const char *e
) {
73 return env_name_is_valid_n(e
, strlen(e
));
76 bool env_value_is_valid(const char *e
) {
80 if (!utf8_is_valid(e
))
83 /* bash allows tabs in environment variables, and so should
85 if (string_has_cc(e
, "\t"))
88 /* POSIX says the overall size of the environment block cannot
89 * be > ARG_MAX, an individual assignment hence cannot be
90 * either. Discounting the shortest possible variable name of
91 * length 1, the equal sign and trailing NUL this hence leaves
92 * ARG_MAX-3 as longest possible variable value. */
93 if (strlen(e
) > ARG_MAX
- 3)
99 bool env_assignment_is_valid(const char *e
) {
106 if (!env_name_is_valid_n(e
, eq
- e
))
109 if (!env_value_is_valid(eq
+ 1))
112 /* POSIX says the overall size of the environment block cannot
113 * be > ARG_MAX, hence the individual variable assignments
114 * cannot be either, but let's leave room for one trailing NUL
116 if (strlen(e
) > ARG_MAX
- 1)
122 bool strv_env_is_valid(char **e
) {
128 if (!env_assignment_is_valid(*p
))
131 /* Check if there are duplicate assginments */
132 k
= strcspn(*p
, "=");
133 STRV_FOREACH(q
, p
+ 1)
134 if (strneq(*p
, *q
, k
) && (*q
)[k
] == '=')
141 bool strv_env_name_or_assignment_is_valid(char **l
) {
145 if (!env_assignment_is_valid(*p
) && !env_name_is_valid(*p
))
148 STRV_FOREACH(q
, p
+ 1)
156 static int env_append(char **r
, char ***k
, char **a
) {
163 /* Add the entries of a to *k unless they already exist in *r
164 * in which case they are overridden instead. This assumes
165 * there is enough space in the r array. */
171 n
= strcspn(*a
, "=");
176 for (j
= r
; j
< *k
; j
++)
177 if (strneq(*j
, *a
, n
))
193 char **strv_env_merge(unsigned n_lists
, ...) {
199 /* Merges an arbitrary number of environment sets */
201 va_start(ap
, n_lists
);
202 for (i
= 0; i
< n_lists
; i
++) {
203 l
= va_arg(ap
, char**);
214 va_start(ap
, n_lists
);
215 for (i
= 0; i
< n_lists
; i
++) {
216 l
= va_arg(ap
, char**);
217 if (env_append(r
, &k
, l
) < 0)
233 _pure_
static bool env_match(const char *t
, const char *pattern
) {
237 /* pattern a matches string a
242 * a= does not match a
243 * a=b does not match a=
244 * a=b does not match a
245 * a=b does not match a=c */
247 if (streq(t
, pattern
))
250 if (!strchr(pattern
, '=')) {
251 size_t l
= strlen(pattern
);
253 return strneq(t
, pattern
, l
) && t
[l
] == '=';
259 char **strv_env_delete(char **x
, unsigned n_lists
, ...) {
264 /* Deletes every entry from x that is mentioned in the other
276 va_start(ap
, n_lists
);
277 for (v
= 0; v
< n_lists
; v
++) {
280 l
= va_arg(ap
, char**);
282 if (env_match(*k
, *j
))
307 char **strv_env_unset(char **l
, const char *p
) {
316 /* Drops every occurrence of the env var setting p in the
317 * string list. Edits in-place. */
319 for (f
= t
= l
; *f
; f
++) {
321 if (env_match(*f
, p
)) {
333 char **strv_env_unset_many(char **l
, ...) {
340 /* Like strv_env_unset() but applies many at once. Edits in-place. */
342 for (f
= t
= l
; *f
; f
++) {
349 while ((p
= va_arg(ap
, const char*))) {
350 if (env_match(*f
, p
)) {
370 char **strv_env_set(char **x
, const char *p
) {
373 char* m
[2] = { (char*) p
, NULL
};
375 /* Overrides the env var setting of p, returns a new copy */
377 r
= new(char*, strv_length(x
)+2);
382 if (env_append(r
, &k
, x
) < 0)
385 if (env_append(r
, &k
, m
) < 0)
397 char *strv_env_get_n(char **l
, const char *name
, size_t k
) {
406 if (strneq(*i
, name
, k
) &&
413 char *strv_env_get(char **l
, const char *name
) {
416 return strv_env_get_n(l
, name
, strlen(name
));
419 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
425 bool duplicate
= false;
427 if (!env_assignment_is_valid(*p
)) {
428 if (invalid_callback
)
429 invalid_callback(*p
, userdata
);
434 n
= strcspn(*p
, "=");
435 STRV_FOREACH(q
, p
+ 1)
436 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
455 char *replace_env(const char *format
, char **env
) {
462 const char *e
, *word
= format
;
467 for (e
= format
; *e
; e
++) {
478 k
= strnappend(r
, word
, e
-word
-1);
488 } else if (*e
== '$') {
489 k
= strnappend(r
, word
, e
-word
);
506 t
= strempty(strv_env_get_n(env
, word
+2, e
-word
-2));
522 k
= strnappend(r
, word
, e
-word
);
534 char **replace_env_argv(char **argv
, char **env
) {
536 unsigned k
= 0, l
= 0;
538 l
= strv_length(argv
);
540 ret
= new(char*, l
+1);
544 STRV_FOREACH(i
, argv
) {
546 /* If $FOO appears as single word, replace it by the split up variable */
547 if ((*i
)[0] == '$' && (*i
)[1] != '{' && (*i
)[1] != '$') {
549 char **w
, **m
= NULL
;
552 e
= strv_env_get(env
, *i
+1);
556 r
= strv_split_extract(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_QUOTES
);
568 w
= realloc(ret
, sizeof(char*) * (l
+1));
578 memcpy(ret
+ k
, m
, q
* sizeof(char*));
586 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
587 ret
[k
] = replace_env(*i
, env
);
599 int getenv_bool(const char *p
) {
606 return parse_boolean(e
);