]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/env-util.c
man: document ARM root partition types
[thirdparty/systemd.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 }