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/>.
23 #include <sys/param.h>
32 #define VALID_CHARS_ENV_NAME \
37 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
40 static bool env_name_is_valid_n(const char *e, size_t n) {
49 if (e[0] >= '0' && e[0] <= '9')
52 /* POSIX says the overall size of the environment block cannot
53 * be > ARG_MAX, an individual assignment hence cannot be
54 * either. Discounting the equal sign and trailing NUL this
55 * hence leaves ARG_MAX-2 as longest possible variable
60 for (p = e; p < e + n; p++)
61 if (!strchr(VALID_CHARS_ENV_NAME, *p))
67 bool env_name_is_valid(const char *e) {
71 return env_name_is_valid_n(e, strlen(e));
74 bool env_value_is_valid(const char *e) {
78 if (!utf8_is_valid(e))
81 /* bash allows tabs in environment variables, and so should
83 if (string_has_cc(e, "\t"))
86 /* POSIX says the overall size of the environment block cannot
87 * be > ARG_MAX, an individual assignment hence cannot be
88 * either. Discounting the shortest possible variable name of
89 * length 1, the equal sign and trailing NUL this hence leaves
90 * ARG_MAX-3 as longest possible variable value. */
91 if (strlen(e) > ARG_MAX - 3)
97 bool env_assignment_is_valid(const char *e) {
104 if (!env_name_is_valid_n(e, eq - e))
107 if (!env_value_is_valid(eq + 1))
110 /* POSIX says the overall size of the environment block cannot
111 * be > ARG_MAX, hence the individual variable assignments
112 * cannot be either, but let's leave room for one trailing NUL
114 if (strlen(e) > ARG_MAX - 1)
120 bool strv_env_is_valid(char **e) {
126 if (!env_assignment_is_valid(*p))
129 /* Check if there are duplicate assginments */
130 k = strcspn(*p, "=");
131 STRV_FOREACH(q, p + 1)
132 if (strneq(*p, *q, k) && (*q)[k] == '=')
139 bool strv_env_name_or_assignment_is_valid(char **l) {
143 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
146 STRV_FOREACH(q, p + 1)
154 static int env_append(char **r, char ***k, char **a) {
161 /* Add the entries of a to *k unless they already exist in *r
162 * in which case they are overridden instead. This assumes
163 * there is enough space in the r array. */
169 n = strcspn(*a, "=");
174 for (j = r; j < *k; j++)
175 if (strneq(*j, *a, n))
191 char **strv_env_merge(unsigned n_lists, ...) {
197 /* Merges an arbitrary number of environment sets */
199 va_start(ap, n_lists);
200 for (i = 0; i < n_lists; i++) {
201 l = va_arg(ap, char**);
212 va_start(ap, n_lists);
213 for (i = 0; i < n_lists; i++) {
214 l = va_arg(ap, char**);
215 if (env_append(r, &k, l) < 0)
231 _pure_ static bool env_match(const char *t, const char *pattern) {
235 /* pattern a matches string a
240 * a= does not match a
241 * a=b does not match a=
242 * a=b does not match a
243 * a=b does not match a=c */
245 if (streq(t, pattern))
248 if (!strchr(pattern, '=')) {
249 size_t l = strlen(pattern);
251 return strneq(t, pattern, l) && t[l] == '=';
257 char **strv_env_delete(char **x, unsigned n_lists, ...) {
262 /* Deletes every entry from x that is mentioned in the other
274 va_start(ap, n_lists);
275 for (v = 0; v < n_lists; v++) {
278 l = va_arg(ap, char**);
280 if (env_match(*k, *j))
305 char **strv_env_unset(char **l, const char *p) {
314 /* Drops every occurrence of the env var setting p in the
315 * string list. Edits in-place. */
317 for (f = t = l; *f; f++) {
319 if (env_match(*f, p)) {
331 char **strv_env_unset_many(char **l, ...) {
338 /* Like strv_env_unset() but applies many at once. Edits in-place. */
340 for (f = t = l; *f; f++) {
347 while ((p = va_arg(ap, const char*))) {
348 if (env_match(*f, p)) {
368 char **strv_env_set(char **x, const char *p) {
371 char* m[2] = { (char*) p, NULL };
373 /* Overrides the env var setting of p, returns a new copy */
375 r = new(char*, strv_length(x)+2);
380 if (env_append(r, &k, x) < 0)
383 if (env_append(r, &k, m) < 0)
395 char *strv_env_get_n(char **l, const char *name, size_t k) {
404 if (strneq(*i, name, k) &&
411 char *strv_env_get(char **l, const char *name) {
414 return strv_env_get_n(l, name, strlen(name));
417 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
423 bool duplicate = false;
425 if (!env_assignment_is_valid(*p)) {
426 if (invalid_callback)
427 invalid_callback(*p, userdata);
432 n = strcspn(*p, "=");
433 STRV_FOREACH(q, p + 1)
434 if (strneq(*p, *q, n) && (*q)[n] == '=') {