]>
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/>.
29 #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 _pure_
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 char **strv_env_delete(char **x
, unsigned n_lists
, ...) {
283 /* Deletes every entry from x that is mentioned in the other
295 va_start(ap
, n_lists
);
296 for (v
= 0; v
< n_lists
; v
++) {
299 l
= va_arg(ap
, char**);
301 if (env_match(*k
, *j
))
326 char **strv_env_unset(char **l
, const char *p
) {
335 /* Drops every occurrence of the env var setting p in the
336 * string list. Edits in-place. */
338 for (f
= t
= l
; *f
; f
++) {
340 if (env_match(*f
, p
)) {
352 char **strv_env_unset_many(char **l
, ...) {
359 /* Like strv_env_unset() but applies many at once. Edits in-place. */
361 for (f
= t
= l
; *f
; f
++) {
368 while ((p
= va_arg(ap
, const char*))) {
369 if (env_match(*f
, p
)) {
389 char **strv_env_set(char **x
, const char *p
) {
392 char* m
[2] = { (char*) p
, NULL
};
394 /* Overrides the env var setting of p, returns a new copy */
396 r
= new(char*, strv_length(x
)+2);
401 if (env_append(r
, &k
, x
) < 0)
404 if (env_append(r
, &k
, m
) < 0)
416 char *strv_env_get_n(char **l
, const char *name
, size_t k
) {
425 if (strneq(*i
, name
, k
) &&
432 char *strv_env_get(char **l
, const char *name
) {
435 return strv_env_get_n(l
, name
, strlen(name
));
438 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
444 bool duplicate
= false;
446 if (!env_assignment_is_valid(*p
)) {
447 if (invalid_callback
)
448 invalid_callback(*p
, userdata
);
453 n
= strcspn(*p
, "=");
454 STRV_FOREACH(q
, p
+ 1)
455 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
474 char *replace_env(const char *format
, char **env
) {
481 const char *e
, *word
= format
;
486 for (e
= format
; *e
; e
++) {
497 k
= strnappend(r
, word
, e
-word
-1);
507 } else if (*e
== '$') {
508 k
= strnappend(r
, word
, e
-word
);
525 t
= strempty(strv_env_get_n(env
, word
+2, e
-word
-2));
541 k
= strnappend(r
, word
, e
-word
);
553 char **replace_env_argv(char **argv
, char **env
) {
555 unsigned k
= 0, l
= 0;
557 l
= strv_length(argv
);
559 ret
= new(char*, l
+1);
563 STRV_FOREACH(i
, argv
) {
565 /* If $FOO appears as single word, replace it by the split up variable */
566 if ((*i
)[0] == '$' && (*i
)[1] != '{' && (*i
)[1] != '$') {
568 char **w
, **m
= NULL
;
571 e
= strv_env_get(env
, *i
+1);
575 r
= strv_split_extract(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_QUOTES
);
587 w
= realloc(ret
, sizeof(char*) * (l
+1));
597 memcpy(ret
+ k
, m
, q
* sizeof(char*));
605 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
606 ret
[k
] = replace_env(*i
, env
);
618 int getenv_bool(const char *p
) {
625 return parse_boolean(e
);