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>
33 #define VALID_CHARS_ENV_NAME \
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))
82 /* bash allows tabs in environment variables, and so should
84 if (string_has_cc(e, "\t"))
87 /* POSIX says the overall size of the environment block cannot
88 * be > ARG_MAX, an individual assignment hence cannot be
89 * either. Discounting the shortest possible variable name of
90 * length 1, the equal sign and trailing NUL this hence leaves
91 * ARG_MAX-3 as longest possible variable value. */
92 if (strlen(e) > ARG_MAX - 3)
98 bool env_assignment_is_valid(const char *e) {
105 if (!env_name_is_valid_n(e, eq - e))
108 if (!env_value_is_valid(eq + 1))
111 /* POSIX says the overall size of the environment block cannot
112 * be > ARG_MAX, hence the individual variable assignments
113 * cannot be either, but let's leave room for one trailing NUL
115 if (strlen(e) > ARG_MAX - 1)
121 bool strv_env_is_valid(char **e) {
127 if (!env_assignment_is_valid(*p))
130 /* Check if there are duplicate assginments */
131 k = strcspn(*p, "=");
132 STRV_FOREACH(q, p + 1)
133 if (strneq(*p, *q, k) && (*q)[k] == '=')
140 bool strv_env_name_or_assignment_is_valid(char **l) {
144 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
147 STRV_FOREACH(q, p + 1)
155 static int env_append(char **r, char ***k, char **a) {
162 /* Add the entries of a to *k unless they already exist in *r
163 * in which case they are overridden instead. This assumes
164 * there is enough space in the r array. */
170 n = strcspn(*a, "=");
175 for (j = r; j < *k; j++)
176 if (strneq(*j, *a, n))
192 char **strv_env_merge(unsigned n_lists, ...) {
198 /* Merges an arbitrary number of environment sets */
200 va_start(ap, n_lists);
201 for (i = 0; i < n_lists; i++) {
202 l = va_arg(ap, char**);
213 va_start(ap, n_lists);
214 for (i = 0; i < n_lists; i++) {
215 l = va_arg(ap, char**);
216 if (env_append(r, &k, l) < 0)
232 _pure_ static bool env_match(const char *t, const char *pattern) {
236 /* pattern a matches string a
241 * a= does not match a
242 * a=b does not match a=
243 * a=b does not match a
244 * a=b does not match a=c */
246 if (streq(t, pattern))
249 if (!strchr(pattern, '=')) {
250 size_t l = strlen(pattern);
252 return strneq(t, pattern, l) && t[l] == '=';
258 char **strv_env_delete(char **x, unsigned n_lists, ...) {
263 /* Deletes every entry from x that is mentioned in the other
275 va_start(ap, n_lists);
276 for (v = 0; v < n_lists; v++) {
279 l = va_arg(ap, char**);
281 if (env_match(*k, *j))
306 char **strv_env_unset(char **l, const char *p) {
315 /* Drops every occurrence of the env var setting p in the
316 * string list. Edits in-place. */
318 for (f = t = l; *f; f++) {
320 if (env_match(*f, p)) {
332 char **strv_env_unset_many(char **l, ...) {
339 /* Like strv_env_unset() but applies many at once. Edits in-place. */
341 for (f = t = l; *f; f++) {
348 while ((p = va_arg(ap, const char*))) {
349 if (env_match(*f, p)) {
369 char **strv_env_set(char **x, const char *p) {
372 char* m[2] = { (char*) p, NULL };
374 /* Overrides the env var setting of p, returns a new copy */
376 r = new(char*, strv_length(x)+2);
381 if (env_append(r, &k, x) < 0)
384 if (env_append(r, &k, m) < 0)
396 char *strv_env_get_n(char **l, const char *name, size_t k) {
405 if (strneq(*i, name, k) &&
412 char *strv_env_get(char **l, const char *name) {
415 return strv_env_get_n(l, name, strlen(name));
418 char **strv_env_clean_log(char **e, const char *unit_id, const char *message) {
424 bool duplicate = false;
426 if (!env_assignment_is_valid(*p)) {
428 log_unit_error(unit_id, "Ignoring invalid environment '%s': %s", *p, message);
433 n = strcspn(*p, "=");
434 STRV_FOREACH(q, p + 1)
435 if (strneq(*p, *q, n) && (*q)[n] == '=') {
454 char **strv_env_clean(char **e) {
455 return strv_env_clean_log(e, NULL, NULL);