]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/env-util.c
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"
29 #include "extract-word.h"
31 #include "parse-util.h"
32 #include "string-util.h"
36 #define VALID_CHARS_ENV_NAME \
41 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
44 static bool env_name_is_valid_n(const char *e
, size_t n
) {
53 if (e
[0] >= '0' && e
[0] <= '9')
56 /* POSIX says the overall size of the environment block cannot
57 * be > ARG_MAX, an individual assignment hence cannot be
58 * either. Discounting the equal sign and trailing NUL this
59 * hence leaves ARG_MAX-2 as longest possible variable
64 for (p
= e
; p
< e
+ n
; p
++)
65 if (!strchr(VALID_CHARS_ENV_NAME
, *p
))
71 bool env_name_is_valid(const char *e
) {
75 return env_name_is_valid_n(e
, strlen(e
));
78 bool env_value_is_valid(const char *e
) {
82 if (!utf8_is_valid(e
))
85 /* bash allows tabs in environment variables, and so should
87 if (string_has_cc(e
, "\t"))
90 /* POSIX says the overall size of the environment block cannot
91 * be > ARG_MAX, an individual assignment hence cannot be
92 * either. Discounting the shortest possible variable name of
93 * length 1, the equal sign and trailing NUL this hence leaves
94 * ARG_MAX-3 as longest possible variable value. */
95 if (strlen(e
) > ARG_MAX
- 3)
101 bool env_assignment_is_valid(const char *e
) {
108 if (!env_name_is_valid_n(e
, eq
- e
))
111 if (!env_value_is_valid(eq
+ 1))
114 /* POSIX says the overall size of the environment block cannot
115 * be > ARG_MAX, hence the individual variable assignments
116 * cannot be either, but let's leave room for one trailing NUL
118 if (strlen(e
) > ARG_MAX
- 1)
124 bool strv_env_is_valid(char **e
) {
130 if (!env_assignment_is_valid(*p
))
133 /* Check if there are duplicate assginments */
134 k
= strcspn(*p
, "=");
135 STRV_FOREACH(q
, p
+ 1)
136 if (strneq(*p
, *q
, k
) && (*q
)[k
] == '=')
143 bool strv_env_name_is_valid(char **l
) {
147 if (!env_name_is_valid(*p
))
150 STRV_FOREACH(q
, p
+ 1)
158 bool strv_env_name_or_assignment_is_valid(char **l
) {
162 if (!env_assignment_is_valid(*p
) && !env_name_is_valid(*p
))
165 STRV_FOREACH(q
, p
+ 1)
173 static int env_append(char **r
, char ***k
, char **a
) {
180 /* Add the entries of a to *k unless they already exist in *r
181 * in which case they are overridden instead. This assumes
182 * there is enough space in the r array. */
188 n
= strcspn(*a
, "=");
193 for (j
= r
; j
< *k
; j
++)
194 if (strneq(*j
, *a
, n
))
210 char **strv_env_merge(unsigned n_lists
, ...) {
216 /* Merges an arbitrary number of environment sets */
218 va_start(ap
, n_lists
);
219 for (i
= 0; i
< n_lists
; i
++) {
220 l
= va_arg(ap
, char**);
231 va_start(ap
, n_lists
);
232 for (i
= 0; i
< n_lists
; i
++) {
233 l
= va_arg(ap
, char**);
234 if (env_append(r
, &k
, l
) < 0)
250 _pure_
static bool env_match(const char *t
, const char *pattern
) {
254 /* pattern a matches string a
259 * a= does not match a
260 * a=b does not match a=
261 * a=b does not match a
262 * a=b does not match a=c */
264 if (streq(t
, pattern
))
267 if (!strchr(pattern
, '=')) {
268 size_t l
= strlen(pattern
);
270 return strneq(t
, pattern
, l
) && t
[l
] == '=';
276 char **strv_env_delete(char **x
, unsigned n_lists
, ...) {
281 /* Deletes every entry from x that is mentioned in the other
293 va_start(ap
, n_lists
);
294 for (v
= 0; v
< n_lists
; v
++) {
297 l
= va_arg(ap
, char**);
299 if (env_match(*k
, *j
))
324 char **strv_env_unset(char **l
, const char *p
) {
333 /* Drops every occurrence of the env var setting p in the
334 * string list. Edits in-place. */
336 for (f
= t
= l
; *f
; f
++) {
338 if (env_match(*f
, p
)) {
350 char **strv_env_unset_many(char **l
, ...) {
357 /* Like strv_env_unset() but applies many at once. Edits in-place. */
359 for (f
= t
= l
; *f
; f
++) {
366 while ((p
= va_arg(ap
, const char*))) {
367 if (env_match(*f
, p
)) {
387 char **strv_env_set(char **x
, const char *p
) {
390 char* m
[2] = { (char*) p
, NULL
};
392 /* Overrides the env var setting of p, returns a new copy */
394 r
= new(char*, strv_length(x
)+2);
399 if (env_append(r
, &k
, x
) < 0)
402 if (env_append(r
, &k
, m
) < 0)
414 char *strv_env_get_n(char **l
, const char *name
, size_t k
) {
423 if (strneq(*i
, name
, k
) &&
430 char *strv_env_get(char **l
, const char *name
) {
433 return strv_env_get_n(l
, name
, strlen(name
));
436 char **strv_env_clean_with_callback(char **e
, void (*invalid_callback
)(const char *p
, void *userdata
), void *userdata
) {
442 bool duplicate
= false;
444 if (!env_assignment_is_valid(*p
)) {
445 if (invalid_callback
)
446 invalid_callback(*p
, userdata
);
451 n
= strcspn(*p
, "=");
452 STRV_FOREACH(q
, p
+ 1)
453 if (strneq(*p
, *q
, n
) && (*q
)[n
] == '=') {
472 char *replace_env(const char *format
, char **env
) {
479 const char *e
, *word
= format
;
484 for (e
= format
; *e
; e
++) {
495 k
= strnappend(r
, word
, e
-word
-1);
505 } else if (*e
== '$') {
506 k
= strnappend(r
, word
, e
-word
);
523 t
= strempty(strv_env_get_n(env
, word
+2, e
-word
-2));
539 k
= strnappend(r
, word
, e
-word
);
550 char **replace_env_argv(char **argv
, char **env
) {
552 unsigned k
= 0, l
= 0;
554 l
= strv_length(argv
);
556 ret
= new(char*, l
+1);
560 STRV_FOREACH(i
, argv
) {
562 /* If $FOO appears as single word, replace it by the split up variable */
563 if ((*i
)[0] == '$' && (*i
)[1] != '{' && (*i
)[1] != '$') {
565 char **w
, **m
= NULL
;
568 e
= strv_env_get(env
, *i
+1);
572 r
= strv_split_extract(&m
, e
, WHITESPACE
, EXTRACT_RELAX
|EXTRACT_QUOTES
);
584 w
= realloc(ret
, sizeof(char*) * (l
+1));
594 memcpy(ret
+ k
, m
, q
* sizeof(char*));
602 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
603 ret
[k
] = replace_env(*i
, env
);
615 int getenv_bool(const char *p
) {
622 return parse_boolean(e
);