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))
84 /* POSIX says the overall size of the environment block cannot
85 * be > ARG_MAX, an individual assignment hence cannot be
86 * either. Discounting the shortest possible variable name of
87 * length 1, the equal sign and trailing NUL this hence leaves
88 * ARG_MAX-3 as longest possible variable value. */
89 if (strlen(e) > ARG_MAX - 3)
95 bool env_assignment_is_valid(const char *e) {
102 if (!env_name_is_valid_n(e, eq - e))
105 if (!env_value_is_valid(eq + 1))
108 /* POSIX says the overall size of the environment block cannot
109 * be > ARG_MAX, hence the individual variable assignments
110 * cannot be either, but let's leave room for one trailing NUL
112 if (strlen(e) > ARG_MAX - 1)
118 bool strv_env_is_valid(char **e) {
124 if (!env_assignment_is_valid(*p))
127 /* Check if there are duplicate assginments */
128 k = strcspn(*p, "=");
129 STRV_FOREACH(q, p + 1)
130 if (strneq(*p, *q, k) && (*q)[k] == '=')
137 bool strv_env_name_or_assignment_is_valid(char **l) {
141 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
144 STRV_FOREACH(q, p + 1)
152 static int env_append(char **r, char ***k, char **a) {
159 /* Add the entries of a to *k unless they already exist in *r
160 * in which case they are overridden instead. This assumes
161 * there is enough space in the r array. */
167 n = strcspn(*a, "=");
172 for (j = r; j < *k; j++)
173 if (strneq(*j, *a, n))
189 char **strv_env_merge(unsigned n_lists, ...) {
195 /* Merges an arbitrary number of environment sets */
197 va_start(ap, n_lists);
198 for (i = 0; i < n_lists; i++) {
199 l = va_arg(ap, char**);
210 va_start(ap, n_lists);
211 for (i = 0; i < n_lists; i++) {
212 l = va_arg(ap, char**);
213 if (env_append(r, &k, l) < 0)
229 _pure_ static bool env_match(const char *t, const char *pattern) {
233 /* pattern a matches string a
238 * a= does not match a
239 * a=b does not match a=
240 * a=b does not match a
241 * a=b does not match a=c */
243 if (streq(t, pattern))
246 if (!strchr(pattern, '=')) {
247 size_t l = strlen(pattern);
249 return strneq(t, pattern, l) && t[l] == '=';
255 char **strv_env_delete(char **x, unsigned n_lists, ...) {
260 /* Deletes every entry from x that is mentioned in the other
272 va_start(ap, n_lists);
273 for (v = 0; v < n_lists; v++) {
276 l = va_arg(ap, char**);
278 if (env_match(*k, *j))
303 char **strv_env_unset(char **l, const char *p) {
312 /* Drops every occurrence of the env var setting p in the
313 * string list. Edits in-place. */
315 for (f = t = l; *f; f++) {
317 if (env_match(*f, p)) {
329 char **strv_env_unset_many(char **l, ...) {
336 /* Like strv_env_unset() but applies many at once. Edits in-place. */
338 for (f = t = l; *f; f++) {
345 while ((p = va_arg(ap, const char*))) {
346 if (env_match(*f, p)) {
366 char **strv_env_set(char **x, const char *p) {
369 char* m[2] = { (char*) p, NULL };
371 /* Overrides the env var setting of p, returns a new copy */
373 r = new(char*, strv_length(x)+2);
378 if (env_append(r, &k, x) < 0)
381 if (env_append(r, &k, m) < 0)
393 char *strv_env_get_n(char **l, const char *name, size_t k) {
402 if (strneq(*i, name, k) &&
409 char *strv_env_get(char **l, const char *name) {
412 return strv_env_get_n(l, name, strlen(name));
415 char **strv_env_clean_log(char **e, const char *message) {
421 bool duplicate = false;
423 if (!env_assignment_is_valid(*p)) {
425 log_error("Ignoring invalid environment '%s': %s", *p, message);
430 n = strcspn(*p, "=");
431 STRV_FOREACH(q, p + 1)
432 if (strneq(*p, *q, n) && (*q)[n] == '=') {
451 char **strv_env_clean(char **e) {
452 return strv_env_clean_log(e, NULL);