chiark / gitweb /
bus: properly shift cgroup data returned from kdbus by the container's root before...
[elogind.git] / src / shared / env-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <limits.h>
23 #include <sys/param.h>
24 #include <unistd.h>
25
26 #include "strv.h"
27 #include "utf8.h"
28 #include "util.h"
29 #include "env-util.h"
30 #include "def.h"
31
32 #define VALID_CHARS_ENV_NAME                    \
33         DIGITS LETTERS                          \
34         "_"
35
36 #ifndef ARG_MAX
37 #define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
38 #endif
39
40 static bool env_name_is_valid_n(const char *e, size_t n) {
41         const char *p;
42
43         if (!e)
44                 return false;
45
46         if (n <= 0)
47                 return false;
48
49         if (e[0] >= '0' && e[0] <= '9')
50                 return false;
51
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
56          * name. */
57         if (n > ARG_MAX - 2)
58                 return false;
59
60         for (p = e; p < e + n; p++)
61                 if (!strchr(VALID_CHARS_ENV_NAME, *p))
62                         return false;
63
64         return true;
65 }
66
67 bool env_name_is_valid(const char *e) {
68         if (!e)
69                 return false;
70
71         return env_name_is_valid_n(e, strlen(e));
72 }
73
74 bool env_value_is_valid(const char *e) {
75         if (!e)
76                 return false;
77
78         if (!utf8_is_valid(e))
79                 return false;
80
81         if (string_has_cc(e))
82                 return false;
83
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)
90                 return false;
91
92         return true;
93 }
94
95 bool env_assignment_is_valid(const char *e) {
96         const char *eq;
97
98         eq = strchr(e, '=');
99         if (!eq)
100                 return false;
101
102         if (!env_name_is_valid_n(e, eq - e))
103                 return false;
104
105         if (!env_value_is_valid(eq + 1))
106                 return false;
107
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
111          * byte. */
112         if (strlen(e) > ARG_MAX - 1)
113                 return false;
114
115         return true;
116 }
117
118 bool strv_env_is_valid(char **e) {
119         char **p, **q;
120
121         STRV_FOREACH(p, e) {
122                 size_t k;
123
124                 if (!env_assignment_is_valid(*p))
125                         return false;
126
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] == '=')
131                                 return false;
132         }
133
134         return true;
135 }
136
137 bool strv_env_name_or_assignment_is_valid(char **l) {
138         char **p, **q;
139
140         STRV_FOREACH(p, l) {
141                 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
142                         return false;
143
144                 STRV_FOREACH(q, p + 1)
145                         if (streq(*p, *q))
146                                 return false;
147         }
148
149         return true;
150 }
151
152 static int env_append(char **r, char ***k, char **a) {
153         assert(r);
154         assert(k);
155
156         if (!a)
157                 return 0;
158
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. */
162
163         for (; *a; a++) {
164                 char **j;
165                 size_t n;
166
167                 n = strcspn(*a, "=");
168
169                 if ((*a)[n] == '=')
170                         n++;
171
172                 for (j = r; j < *k; j++)
173                         if (strneq(*j, *a, n))
174                                 break;
175
176                 if (j >= *k)
177                         (*k)++;
178                 else
179                         free(*j);
180
181                 *j = strdup(*a);
182                 if (!*j)
183                         return -ENOMEM;
184         }
185
186         return 0;
187 }
188
189 char **strv_env_merge(unsigned n_lists, ...) {
190         size_t n = 0;
191         char **l, **k, **r;
192         va_list ap;
193         unsigned i;
194
195         /* Merges an arbitrary number of environment sets */
196
197         va_start(ap, n_lists);
198         for (i = 0; i < n_lists; i++) {
199                 l = va_arg(ap, char**);
200                 n += strv_length(l);
201         }
202         va_end(ap);
203
204         r = new(char*, n+1);
205         if (!r)
206                 return NULL;
207
208         k = r;
209
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)
214                         goto fail;
215         }
216         va_end(ap);
217
218         *k = NULL;
219
220         return r;
221
222 fail:
223         va_end(ap);
224         strv_free(r);
225
226         return NULL;
227 }
228
229 _pure_ static bool env_match(const char *t, const char *pattern) {
230         assert(t);
231         assert(pattern);
232
233         /* pattern a matches string a
234          *         a matches a=
235          *         a matches a=b
236          *         a= matches a=
237          *         a=b matches a=b
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 */
242
243         if (streq(t, pattern))
244                 return true;
245
246         if (!strchr(pattern, '=')) {
247                 size_t l = strlen(pattern);
248
249                 return strneq(t, pattern, l) && t[l] == '=';
250         }
251
252         return false;
253 }
254
255 char **strv_env_delete(char **x, unsigned n_lists, ...) {
256         size_t n, i = 0;
257         char **k, **r;
258         va_list ap;
259
260         /* Deletes every entry from x that is mentioned in the other
261          * string lists */
262
263         n = strv_length(x);
264
265         r = new(char*, n+1);
266         if (!r)
267                 return NULL;
268
269         STRV_FOREACH(k, x) {
270                 unsigned v;
271
272                 va_start(ap, n_lists);
273                 for (v = 0; v < n_lists; v++) {
274                         char **l, **j;
275
276                         l = va_arg(ap, char**);
277                         STRV_FOREACH(j, l)
278                                 if (env_match(*k, *j))
279                                         goto skip;
280                 }
281                 va_end(ap);
282
283                 r[i] = strdup(*k);
284                 if (!r[i]) {
285                         strv_free(r);
286                         return NULL;
287                 }
288
289                 i++;
290                 continue;
291
292         skip:
293                 va_end(ap);
294         }
295
296         r[i] = NULL;
297
298         assert(i <= n);
299
300         return r;
301 }
302
303 char **strv_env_unset(char **l, const char *p) {
304
305         char **f, **t;
306
307         if (!l)
308                 return NULL;
309
310         assert(p);
311
312         /* Drops every occurrence of the env var setting p in the
313          * string list. edits in-place. */
314
315         for (f = t = l; *f; f++) {
316
317                 if (env_match(*f, p)) {
318                         free(*f);
319                         continue;
320                 }
321
322                 *(t++) = *f;
323         }
324
325         *t = NULL;
326         return l;
327 }
328
329 char **strv_env_set(char **x, const char *p) {
330
331         char **k, **r;
332         char* m[2] = { (char*) p, NULL };
333
334         /* Overrides the env var setting of p, returns a new copy */
335
336         r = new(char*, strv_length(x)+2);
337         if (!r)
338                 return NULL;
339
340         k = r;
341         if (env_append(r, &k, x) < 0)
342                 goto fail;
343
344         if (env_append(r, &k, m) < 0)
345                 goto fail;
346
347         *k = NULL;
348
349         return r;
350
351 fail:
352         strv_free(r);
353         return NULL;
354 }
355
356 char *strv_env_get_n(char **l, const char *name, size_t k) {
357         char **i;
358
359         assert(name);
360
361         if (k <= 0)
362                 return NULL;
363
364         STRV_FOREACH(i, l)
365                 if (strneq(*i, name, k) &&
366                     (*i)[k] == '=')
367                         return *i + k + 1;
368
369         return NULL;
370 }
371
372 char *strv_env_get(char **l, const char *name) {
373         assert(name);
374
375         return strv_env_get_n(l, name, strlen(name));
376 }
377
378 char **strv_env_clean_log(char **e, const char *message) {
379         char **p, **q;
380         int k = 0;
381
382         STRV_FOREACH(p, e) {
383                 size_t n;
384                 bool duplicate = false;
385
386                 if (!env_assignment_is_valid(*p)) {
387                         if (message)
388                                 log_error("Ignoring invalid environment '%s': %s", *p, message);
389                         free(*p);
390                         continue;
391                 }
392
393                 n = strcspn(*p, "=");
394                 STRV_FOREACH(q, p + 1)
395                         if (strneq(*p, *q, n) && (*q)[n] == '=') {
396                                 duplicate = true;
397                                 break;
398                         }
399
400                 if (duplicate) {
401                         free(*p);
402                         continue;
403                 }
404
405                 e[k++] = *p;
406         }
407
408         if (e)
409                 e[k] = NULL;
410
411         return e;
412 }
413
414 char **strv_env_clean(char **e) {
415         return strv_env_clean_log(e, NULL);
416 }