]>
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_is_valid(char **l
) {
145 if (!env_name_is_valid(*p
))
148 STRV_FOREACH(q
, p
+ 1)
156 bool strv_env_name_or_assignment_is_valid(char **l
) {
160 if (!env_assignment_is_valid(*p
) && !env_name_is_valid(*p
))
163 STRV_FOREACH(q
, p
+ 1)
171 static int env_append(char **r
, char ***k
, char **a
) {
178 /* Add the entries of a to *k unless they already exist in *r
179 * in which case they are overridden instead. This assumes
180 * there is enough space in the r array. */
186 n
= strcspn(*a
, "=");
191 for (j
= r
; j
< *k
; j
++)
192 if (strneq(*j
, *a
, n
))
208 char **strv_env_merge(unsigned n_lists
, ...) {
214 /* Merges an arbitrary number of environment sets */
216 va_start(ap
, n_lists
);
217 for (i
= 0; i
< n_lists
; i
++) {
218 l
= va_arg(ap
, char**);
229 va_start(ap
, n_lists
);
230 for (i
= 0; i
< n_lists
; i
++) {
231 l
= va_arg(ap
, char**);
232 if (env_append(r
, &k
, l
) < 0)
248 _pure_
static bool env_match(const char *t
, const char *pattern
) {
252 /* pattern a matches string a
257 * a= does not match a
258 * a=b does not match a=
259 * a=b does not match a
260 * a=b does not match a=c */
262 if (streq(t
, pattern
))
265 if (!strchr(pattern
, '=')) {
266 size_t l
= strlen(pattern
);
268 return strneq(t
, pattern
, l
) && t
[l
] == '=';
274 char **strv_env_delete(char **x
, unsigned n_lists
, ...) {
279 /* Deletes every entry from x that is mentioned in the other
291 va_start(ap
, n_lists
);
292 for (v
= 0; v
< n_lists
; v
++) {
295 l
= va_arg(ap
, char**);
297 if (env_match(*k
, *j
))
322 char **strv_env_unset(char **l
, const char *p
) {
331 /* Drops every occurrence of the env var setting p in the
332 * string list. Edits in-place. */
334 for (f
= t
= l
; *f
; f
++) {
336 if (env_match(*f
, p
)) {
348 char **strv_env_unset_many(char **l
, ...) {
355 /* Like strv_env_unset() but applies many at once. Edits in-place. */
357 for (f
= t
= l
; *f
; f
++) {
364 while ((p
= va_arg(ap
, const char*))) {
365 if (env_match(*f
, p
)) {
385 char **strv_env_set(char **x
, const char *p
) {
388 char* m
[2] = { (char*) p
, NULL
};
390 /* Overrides the env var setting of p, returns a new copy */
392 r
= new(char*, strv_length(x
)+2);
397 if (env_append(r
, &k
, x
) < 0)
400 if (env_append(r
, &k
, m
) < 0)
412 char *strv_env_get_n(char **l
, const char *name
, size_t k
) {
421 if (strneq(*i
, name
, k
) &&
428 char *strv_env_get(char **l
, const char *name
) {
431 return strv_env_get_n(l
, name
, strlen(name
));
434 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
440 bool duplicate
= false;
442 if (!env_assignment_is_valid(*p
)) {
443 if (invalid_callback
)
444 invalid_callback(*p
, userdata
);
449 n
= strcspn(*p
, "=");
450 STRV_FOREACH(q
, p
+ 1)
451 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
470 char *replace_env(const char *format
, char **env
) {
477 const char *e
, *word
= format
;
482 for (e
= format
; *e
; e
++) {
493 k
= strnappend(r
, word
, e
-word
-1);
503 } else if (*e
== '$') {
504 k
= strnappend(r
, word
, e
-word
);
521 t
= strempty(strv_env_get_n(env
, word
+2, e
-word
-2));
537 k
= strnappend(r
, word
, e
-word
);
549 char **replace_env_argv(char **argv
, char **env
) {
551 unsigned k
= 0, l
= 0;
553 l
= strv_length(argv
);
555 ret
= new(char*, l
+1);
559 STRV_FOREACH(i
, argv
) {
561 /* If $FOO appears as single word, replace it by the split up variable */
562 if ((*i
)[0] == '$' && (*i
)[1] != '{' && (*i
)[1] != '$') {
564 char **w
, **m
= NULL
;
567 e
= strv_env_get(env
, *i
+1);
571 r
= strv_split_extract(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_QUOTES
);
583 w
= realloc(ret
, sizeof(char*) * (l
+1));
593 memcpy(ret
+ k
, m
, q
* sizeof(char*));
601 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
602 ret
[k
] = replace_env(*i
, env
);
614 int getenv_bool(const char *p
) {
621 return parse_boolean(e
);