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/>.
31 #define VALID_CHARS_ENV_NAME \
36 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
39 static bool env_name_is_valid_n(const char *e, size_t n) {
48 if (e[0] >= '0' && e[0] <= '9')
51 /* POSIX says the overall size of the environment block cannot
52 * be > ARG_MAX, an individual assignment hence cannot be
53 * either. Discounting the equal sign and trailing NUL this
54 * hence leaves ARG_MAX-2 as longest possible variable
59 for (p = e; p < e + n; p++)
60 if (!strchr(VALID_CHARS_ENV_NAME, *p))
66 bool env_name_is_valid(const char *e) {
70 return env_name_is_valid_n(e, strlen(e));
73 bool env_value_is_valid(const char *e) {
77 if (!utf8_is_valid(e))
80 /* bash allows tabs in environment variables, and so should
82 if (string_has_cc(e, "\t"))
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_unset_many(char **l, ...) {
337 /* Like strv_env_unset() but applies many at once. Edits in-place. */
339 for (f = t = l; *f; f++) {
346 while ((p = va_arg(ap, const char*))) {
347 if (env_match(*f, p)) {
367 char **strv_env_set(char **x, const char *p) {
370 char* m[2] = { (char*) p, NULL };
372 /* Overrides the env var setting of p, returns a new copy */
374 r = new(char*, strv_length(x)+2);
379 if (env_append(r, &k, x) < 0)
382 if (env_append(r, &k, m) < 0)
394 char *strv_env_get_n(char **l, const char *name, size_t k) {
403 if (strneq(*i, name, k) &&
410 char *strv_env_get(char **l, const char *name) {
413 return strv_env_get_n(l, name, strlen(name));
416 char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
422 bool duplicate = false;
424 if (!env_assignment_is_valid(*p)) {
425 if (invalid_callback)
426 invalid_callback(*p, userdata);
431 n = strcspn(*p, "=");
432 STRV_FOREACH(q, p + 1)
433 if (strneq(*p, *q, n) && (*q)[n] == '=') {