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 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 (strncmp(*p, *q, k) == 0 && (*q)[k] == '=')
138 static int env_append(char **r, char ***k, char **a) {
145 /* Add the entries of a to *k unless they already exist in *r
146 * in which case they are overridden instead. This assumes
147 * there is enough space in the r array. */
153 n = strcspn(*a, "=");
158 for (j = r; j < *k; j++)
159 if (strncmp(*j, *a, n) == 0)
175 char **strv_env_merge(unsigned n_lists, ...) {
181 /* Merges an arbitrary number of environment sets */
183 va_start(ap, n_lists);
184 for (i = 0; i < n_lists; i++) {
185 l = va_arg(ap, char**);
196 va_start(ap, n_lists);
197 for (i = 0; i < n_lists; i++) {
198 l = va_arg(ap, char**);
199 if (env_append(r, &k, l) < 0)
215 static bool env_match(const char *t, const char *pattern) {
219 /* pattern a matches string a
224 * a= does not match a
225 * a=b does not match a=
226 * a=b does not match a
227 * a=b does not match a=c */
229 if (streq(t, pattern))
232 if (!strchr(pattern, '=')) {
233 size_t l = strlen(pattern);
235 return strncmp(t, pattern, l) == 0 && t[l] == '=';
241 char **strv_env_delete(char **x, unsigned n_lists, ...) {
246 /* Deletes every entry from x that is mentioned in the other
258 va_start(ap, n_lists);
259 for (v = 0; v < n_lists; v++) {
262 l = va_arg(ap, char**);
264 if (env_match(*k, *j))
289 char **strv_env_unset(char **l, const char *p) {
298 /* Drops every occurrence of the env var setting p in the
299 * string list. edits in-place. */
301 for (f = t = l; *f; f++) {
303 if (env_match(*f, p)) {
315 char **strv_env_set(char **x, const char *p) {
318 char* m[2] = { (char*) p, NULL };
320 /* Overrides the env var setting of p, returns a new copy */
322 r = new(char*, strv_length(x)+2);
327 if (env_append(r, &k, x) < 0)
330 if (env_append(r, &k, m) < 0)
342 char *strv_env_get_n(char **l, const char *name, size_t k) {
351 if (strncmp(*i, name, k) == 0 &&
358 char *strv_env_get(char **l, const char *name) {
361 return strv_env_get_n(l, name, strlen(name));
364 char **strv_env_clean(char **e) {
370 bool duplicate = false;
372 if (!env_assignment_is_valid(*p)) {
377 n = strcspn(*p, "=");
378 STRV_FOREACH(q, p + 1)
379 if (strncmp(*p, *q, n) == 0 && (*q)[n] == '=') {