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>
31 #define VALID_CHARS_ENV_NAME \
33 "abcdefghijklmnopqrstuvwxyz" \
34 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
38 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
41 static bool env_name_is_valid_n(const char *e, size_t n) {
50 if (e[0] >= '0' && e[0] <= '9')
53 /* POSIX says the overall size of the environment block cannot
54 * be > ARG_MAX, an individual assignment hence cannot be
55 * either. Discounting the equal sign and trailing NUL this
56 * hence leaves ARG_MAX-2 as longest possible variable
61 for (p = e; p < e + n; p++)
62 if (!strchr(VALID_CHARS_ENV_NAME, *p))
68 bool env_name_is_valid(const char *e) {
72 return env_name_is_valid_n(e, strlen(e));
75 bool env_value_is_valid(const char *e) {
79 if (!utf8_is_valid(e))
85 /* POSIX says the overall size of the environment block cannot
86 * be > ARG_MAX, an individual assignment hence cannot be
87 * either. Discounting the shortest possible variable name of
88 * length 1, the equal sign and trailing NUL this hence leaves
89 * ARG_MAX-3 as longest possible variable value. */
90 if (strlen(e) > ARG_MAX - 3)
96 bool env_assignment_is_valid(const char *e) {
103 if (!env_name_is_valid_n(e, eq - e))
106 if (!env_value_is_valid(eq + 1))
109 /* POSIX says the overall size of the environment block cannot
110 * be > ARG_MAX, hence the individual variable assignments
111 * cannot be either, but let's leave room for one trailing NUL
113 if (strlen(e) > ARG_MAX - 1)
119 bool strv_env_is_valid(char **e) {
125 if (!env_assignment_is_valid(*p))
128 /* Check if there are duplicate assginments */
129 k = strcspn(*p, "=");
130 STRV_FOREACH(q, p + 1)
131 if (strneq(*p, *q, k) && (*q)[k] == '=')
138 bool strv_env_name_or_assignment_is_valid(char **l) {
142 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
145 STRV_FOREACH(q, p + 1)
153 static int env_append(char **r, char ***k, char **a) {
160 /* Add the entries of a to *k unless they already exist in *r
161 * in which case they are overridden instead. This assumes
162 * there is enough space in the r array. */
168 n = strcspn(*a, "=");
173 for (j = r; j < *k; j++)
174 if (strneq(*j, *a, n))
190 char **strv_env_merge(unsigned n_lists, ...) {
196 /* Merges an arbitrary number of environment sets */
198 va_start(ap, n_lists);
199 for (i = 0; i < n_lists; i++) {
200 l = va_arg(ap, char**);
211 va_start(ap, n_lists);
212 for (i = 0; i < n_lists; i++) {
213 l = va_arg(ap, char**);
214 if (env_append(r, &k, l) < 0)
230 _pure_ static bool env_match(const char *t, const char *pattern) {
234 /* pattern a matches string a
239 * a= does not match a
240 * a=b does not match a=
241 * a=b does not match a
242 * a=b does not match a=c */
244 if (streq(t, pattern))
247 if (!strchr(pattern, '=')) {
248 size_t l = strlen(pattern);
250 return strneq(t, pattern, l) && t[l] == '=';
256 char **strv_env_delete(char **x, unsigned n_lists, ...) {
261 /* Deletes every entry from x that is mentioned in the other
273 va_start(ap, n_lists);
274 for (v = 0; v < n_lists; v++) {
277 l = va_arg(ap, char**);
279 if (env_match(*k, *j))
304 char **strv_env_unset(char **l, const char *p) {
313 /* Drops every occurrence of the env var setting p in the
314 * string list. edits in-place. */
316 for (f = t = l; *f; f++) {
318 if (env_match(*f, p)) {
330 char **strv_env_set(char **x, const char *p) {
333 char* m[2] = { (char*) p, NULL };
335 /* Overrides the env var setting of p, returns a new copy */
337 r = new(char*, strv_length(x)+2);
342 if (env_append(r, &k, x) < 0)
345 if (env_append(r, &k, m) < 0)
357 char *strv_env_get_n(char **l, const char *name, size_t k) {
366 if (strneq(*i, name, k) &&
373 char *strv_env_get(char **l, const char *name) {
376 return strv_env_get_n(l, name, strlen(name));
379 char **strv_env_clean_log(char **e, const char *message) {
385 bool duplicate = false;
387 if (!env_assignment_is_valid(*p)) {
389 log_error("Ignoring invalid environment '%s': %s", *p, message);
394 n = strcspn(*p, "=");
395 STRV_FOREACH(q, p + 1)
396 if (strneq(*p, *q, n) && (*q)[n] == '=') {
413 char **strv_env_clean(char **e) {
414 return strv_env_clean_log(e, NULL);