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);