chiark / gitweb /
remove unused variable
[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_unset_many(char **l, ...) {
330
331         char **f, **t;
332
333         if (!l)
334                 return NULL;
335
336         /* Like strv_env_unset() but applies many at once. Edits in-place. */
337
338         for (f = t = l; *f; f++) {
339                 bool found = false;
340                 const char *p;
341                 va_list ap;
342
343                 va_start(ap, l);
344
345                 while ((p = va_arg(ap, const char*))) {
346                         if (env_match(*f, p)) {
347                                 found = true;
348                                 break;
349                         }
350                 }
351
352                 va_end(ap);
353
354                 if (found) {
355                         free(*f);
356                         continue;
357                 }
358
359                 *(t++) = *f;
360         }
361
362         *t = NULL;
363         return l;
364 }
365
366 char **strv_env_set(char **x, const char *p) {
367
368         char **k, **r;
369         char* m[2] = { (char*) p, NULL };
370
371         /* Overrides the env var setting of p, returns a new copy */
372
373         r = new(char*, strv_length(x)+2);
374         if (!r)
375                 return NULL;
376
377         k = r;
378         if (env_append(r, &k, x) < 0)
379                 goto fail;
380
381         if (env_append(r, &k, m) < 0)
382                 goto fail;
383
384         *k = NULL;
385
386         return r;
387
388 fail:
389         strv_free(r);
390         return NULL;
391 }
392
393 char *strv_env_get_n(char **l, const char *name, size_t k) {
394         char **i;
395
396         assert(name);
397
398         if (k <= 0)
399                 return NULL;
400
401         STRV_FOREACH(i, l)
402                 if (strneq(*i, name, k) &&
403                     (*i)[k] == '=')
404                         return *i + k + 1;
405
406         return NULL;
407 }
408
409 char *strv_env_get(char **l, const char *name) {
410         assert(name);
411
412         return strv_env_get_n(l, name, strlen(name));
413 }
414
415 char **strv_env_clean_log(char **e, const char *message) {
416         char **p, **q;
417         int k = 0;
418
419         STRV_FOREACH(p, e) {
420                 size_t n;
421                 bool duplicate = false;
422
423                 if (!env_assignment_is_valid(*p)) {
424                         if (message)
425                                 log_error("Ignoring invalid environment '%s': %s", *p, message);
426                         free(*p);
427                         continue;
428                 }
429
430                 n = strcspn(*p, "=");
431                 STRV_FOREACH(q, p + 1)
432                         if (strneq(*p, *q, n) && (*q)[n] == '=') {
433                                 duplicate = true;
434                                 break;
435                         }
436
437                 if (duplicate) {
438                         free(*p);
439                         continue;
440                 }
441
442                 e[k++] = *p;
443         }
444
445         if (e)
446                 e[k] = NULL;
447
448         return e;
449 }
450
451 char **strv_env_clean(char **e) {
452         return strv_env_clean_log(e, NULL);
453 }