Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <limits.h>
5 : : #include <stdarg.h>
6 : : #include <stdlib.h>
7 : : #include <string.h>
8 : : #include <unistd.h>
9 : :
10 : : #include "alloc-util.h"
11 : : #include "env-util.h"
12 : : #include "escape.h"
13 : : #include "extract-word.h"
14 : : #include "macro.h"
15 : : #include "parse-util.h"
16 : : #include "string-util.h"
17 : : #include "strv.h"
18 : : #include "utf8.h"
19 : :
20 : : #define VALID_CHARS_ENV_NAME \
21 : : DIGITS LETTERS \
22 : : "_"
23 : :
24 : 364 : static bool env_name_is_valid_n(const char *e, size_t n) {
25 : : const char *p;
26 : :
27 [ - + ]: 364 : if (!e)
28 : 0 : return false;
29 : :
30 [ + + ]: 364 : if (n <= 0)
31 : 16 : return false;
32 : :
33 [ + + + + ]: 348 : if (e[0] >= '0' && e[0] <= '9')
34 : 8 : return false;
35 : :
36 : : /* POSIX says the overall size of the environment block cannot
37 : : * be > ARG_MAX, an individual assignment hence cannot be
38 : : * either. Discounting the equal sign and trailing NUL this
39 : : * hence leaves ARG_MAX-2 as longest possible variable
40 : : * name. */
41 [ - + ]: 340 : if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
42 : 0 : return false;
43 : :
44 [ + + ]: 1668 : for (p = e; p < e + n; p++)
45 [ + + ]: 1396 : if (!strchr(VALID_CHARS_ENV_NAME, *p))
46 : 68 : return false;
47 : :
48 : 272 : return true;
49 : : }
50 : :
51 : 160 : bool env_name_is_valid(const char *e) {
52 [ + + ]: 160 : if (!e)
53 : 4 : return false;
54 : :
55 : 156 : return env_name_is_valid_n(e, strlen(e));
56 : : }
57 : :
58 : 172 : bool env_value_is_valid(const char *e) {
59 [ - + ]: 172 : if (!e)
60 : 0 : return false;
61 : :
62 [ - + ]: 172 : if (!utf8_is_valid(e))
63 : 0 : return false;
64 : :
65 : : /* bash allows tabs and newlines in environment variables, and so
66 : : * should we */
67 [ - + ]: 172 : if (string_has_cc(e, "\t\n"))
68 : 0 : return false;
69 : :
70 : : /* POSIX says the overall size of the environment block cannot
71 : : * be > ARG_MAX, an individual assignment hence cannot be
72 : : * either. Discounting the shortest possible variable name of
73 : : * length 1, the equal sign and trailing NUL this hence leaves
74 : : * ARG_MAX-3 as longest possible variable value. */
75 [ - + ]: 172 : if (strlen(e) > sc_arg_max() - 3)
76 : 0 : return false;
77 : :
78 : 172 : return true;
79 : : }
80 : :
81 : 228 : bool env_assignment_is_valid(const char *e) {
82 : : const char *eq;
83 : :
84 : 228 : eq = strchr(e, '=');
85 [ + + ]: 228 : if (!eq)
86 : 20 : return false;
87 : :
88 [ + + ]: 208 : if (!env_name_is_valid_n(e, eq - e))
89 : 56 : return false;
90 : :
91 [ - + ]: 152 : if (!env_value_is_valid(eq + 1))
92 : 0 : return false;
93 : :
94 : : /* POSIX says the overall size of the environment block cannot
95 : : * be > ARG_MAX, hence the individual variable assignments
96 : : * cannot be either, but let's leave room for one trailing NUL
97 : : * byte. */
98 [ - + ]: 152 : if (strlen(e) > sc_arg_max() - 1)
99 : 0 : return false;
100 : :
101 : 152 : return true;
102 : : }
103 : :
104 : 8 : bool strv_env_is_valid(char **e) {
105 : : char **p, **q;
106 : :
107 [ + - + + ]: 32 : STRV_FOREACH(p, e) {
108 : : size_t k;
109 : :
110 [ - + ]: 28 : if (!env_assignment_is_valid(*p))
111 : 0 : return false;
112 : :
113 : : /* Check if there are duplicate assignments */
114 : 28 : k = strcspn(*p, "=");
115 [ + - + + ]: 88 : STRV_FOREACH(q, p + 1)
116 [ + + + - ]: 64 : if (strneq(*p, *q, k) && (*q)[k] == '=')
117 : 4 : return false;
118 : : }
119 : :
120 : 4 : return true;
121 : : }
122 : :
123 : 0 : bool strv_env_name_is_valid(char **l) {
124 : : char **p;
125 : :
126 [ # # # # ]: 0 : STRV_FOREACH(p, l) {
127 [ # # ]: 0 : if (!env_name_is_valid(*p))
128 : 0 : return false;
129 : :
130 [ # # ]: 0 : if (strv_contains(p + 1, *p))
131 : 0 : return false;
132 : : }
133 : :
134 : 0 : return true;
135 : : }
136 : :
137 : 0 : bool strv_env_name_or_assignment_is_valid(char **l) {
138 : : char **p;
139 : :
140 [ # # # # ]: 0 : STRV_FOREACH(p, l) {
141 [ # # # # ]: 0 : if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
142 : 0 : return false;
143 : :
144 [ # # ]: 0 : if (strv_contains(p + 1, *p))
145 : 0 : return false;
146 : : }
147 : :
148 : 0 : return true;
149 : : }
150 : :
151 : 112 : static int env_append(char **r, char ***k, char **a) {
152 [ - + ]: 112 : assert(r);
153 [ - + ]: 112 : assert(k);
154 [ - + ]: 112 : assert(*k >= r);
155 : :
156 [ + + ]: 112 : if (!a)
157 : 24 : return 0;
158 : :
159 : : /* Expects the following arguments: 'r' shall point to the beginning of an strv we are going to append to, 'k'
160 : : * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
161 : : *
162 : : * This call adds every entry of 'a' to 'r', either overriding an existing matching entry, or appending to it.
163 : : *
164 : : * This call assumes 'r' has enough pre-allocated space to grow by all of 'a''s items. */
165 : :
166 [ + + ]: 3576 : for (; *a; a++) {
167 : : char **j, *c;
168 : : size_t n;
169 : :
170 : 3488 : n = strcspn(*a, "=");
171 [ + + ]: 3488 : if ((*a)[n] == '=')
172 : 3480 : n++;
173 : :
174 [ + + ]: 124572 : for (j = r; j < *k; j++)
175 [ + + ]: 121100 : if (strneq(*j, *a, n))
176 : 16 : break;
177 : :
178 : 3488 : c = strdup(*a);
179 [ - + ]: 3488 : if (!c)
180 : 0 : return -ENOMEM;
181 : :
182 [ + + ]: 3488 : if (j >= *k) { /* Append to the end? */
183 : 3472 : (*k)[0] = c;
184 : 3472 : (*k)[1] = NULL;
185 : 3472 : (*k)++;
186 : : } else
187 : 16 : free_and_replace(*j, c); /* Override existing item */
188 : : }
189 : :
190 : 88 : return 0;
191 : : }
192 : :
193 : 52 : char **strv_env_merge(size_t n_lists, ...) {
194 : 52 : _cleanup_strv_free_ char **ret = NULL;
195 : 52 : size_t n = 0, i;
196 : : char **l, **k;
197 : : va_list ap;
198 : :
199 : : /* Merges an arbitrary number of environment sets */
200 : :
201 : 52 : va_start(ap, n_lists);
202 [ + + ]: 156 : for (i = 0; i < n_lists; i++) {
203 : 104 : l = va_arg(ap, char**);
204 : 104 : n += strv_length(l);
205 : : }
206 : 52 : va_end(ap);
207 : :
208 : 52 : ret = new(char*, n+1);
209 [ - + ]: 52 : if (!ret)
210 : 0 : return NULL;
211 : :
212 : 52 : *ret = NULL;
213 : 52 : k = ret;
214 : :
215 : 52 : va_start(ap, n_lists);
216 [ + + ]: 156 : for (i = 0; i < n_lists; i++) {
217 : 104 : l = va_arg(ap, char**);
218 [ - + ]: 104 : if (env_append(ret, &k, l) < 0) {
219 : 0 : va_end(ap);
220 : 0 : return NULL;
221 : : }
222 : : }
223 : 52 : va_end(ap);
224 : :
225 : 52 : return TAKE_PTR(ret);
226 : : }
227 : :
228 : 63336 : static bool env_match(const char *t, const char *pattern) {
229 [ - + ]: 63336 : assert(t);
230 [ - + ]: 63336 : assert(pattern);
231 : :
232 : : /* pattern a matches string a
233 : : * a matches a=
234 : : * a matches a=b
235 : : * a= matches a=
236 : : * a=b matches a=b
237 : : * a= does not match a
238 : : * a=b does not match a=
239 : : * a=b does not match a
240 : : * a=b does not match a=c */
241 : :
242 [ + + ]: 63336 : if (streq(t, pattern))
243 : 4 : return true;
244 : :
245 [ + + ]: 63332 : if (!strchr(pattern, '=')) {
246 : 63096 : size_t l = strlen(pattern);
247 : :
248 [ + + + - ]: 63096 : return strneq(t, pattern, l) && t[l] == '=';
249 : : }
250 : :
251 : 236 : return false;
252 : : }
253 : :
254 : 1276 : static bool env_entry_has_name(const char *entry, const char *name) {
255 : : const char *t;
256 : :
257 [ - + ]: 1276 : assert(entry);
258 [ - + ]: 1276 : assert(name);
259 : :
260 : 1276 : t = startswith(entry, name);
261 [ + + ]: 1276 : if (!t)
262 : 1204 : return false;
263 : :
264 : 72 : return *t == '=';
265 : : }
266 : :
267 : 4 : char **strv_env_delete(char **x, size_t n_lists, ...) {
268 : 4 : size_t n, i = 0;
269 : : char **k, **r;
270 : : va_list ap;
271 : :
272 : : /* Deletes every entry from x that is mentioned in the other
273 : : * string lists */
274 : :
275 : 4 : n = strv_length(x);
276 : :
277 : 4 : r = new(char*, n+1);
278 [ - + ]: 4 : if (!r)
279 : 0 : return NULL;
280 : :
281 [ + - + + ]: 24 : STRV_FOREACH(k, x) {
282 : : size_t v;
283 : :
284 : 20 : va_start(ap, n_lists);
285 [ + + ]: 40 : for (v = 0; v < n_lists; v++) {
286 : : char **l, **j;
287 : :
288 : 32 : l = va_arg(ap, char**);
289 [ + - + + ]: 68 : STRV_FOREACH(j, l)
290 [ + + ]: 48 : if (env_match(*k, *j))
291 : 12 : goto skip;
292 : : }
293 : 8 : va_end(ap);
294 : :
295 : 8 : r[i] = strdup(*k);
296 [ - + ]: 8 : if (!r[i]) {
297 : 0 : strv_free(r);
298 : 0 : return NULL;
299 : : }
300 : :
301 : 8 : i++;
302 : 8 : continue;
303 : :
304 : 12 : skip:
305 : 12 : va_end(ap);
306 : : }
307 : :
308 : 4 : r[i] = NULL;
309 : :
310 [ - + ]: 4 : assert(i <= n);
311 : :
312 : 4 : return r;
313 : : }
314 : :
315 : 72 : char **strv_env_unset(char **l, const char *p) {
316 : :
317 : : char **f, **t;
318 : :
319 [ - + ]: 72 : if (!l)
320 : 0 : return NULL;
321 : :
322 [ - + ]: 72 : assert(p);
323 : :
324 : : /* Drops every occurrence of the env var setting p in the
325 : : * string list. Edits in-place. */
326 : :
327 [ + + ]: 320 : for (f = t = l; *f; f++) {
328 : :
329 [ + + ]: 248 : if (env_match(*f, p)) {
330 : 4 : free(*f);
331 : 4 : continue;
332 : : }
333 : :
334 : 244 : *(t++) = *f;
335 : : }
336 : :
337 : 72 : *t = NULL;
338 : 72 : return l;
339 : : }
340 : :
341 : 56 : char **strv_env_unset_many(char **l, ...) {
342 : : char **f, **t;
343 : :
344 [ - + ]: 56 : if (!l)
345 : 0 : return NULL;
346 : :
347 : : /* Like strv_env_unset() but applies many at once. Edits in-place. */
348 : :
349 [ + + ]: 3996 : for (f = t = l; *f; f++) {
350 : 3940 : bool found = false;
351 : : const char *p;
352 : : va_list ap;
353 : :
354 : 3940 : va_start(ap, l);
355 : :
356 [ + + ]: 66980 : while ((p = va_arg(ap, const char*))) {
357 [ - + ]: 63040 : if (env_match(*f, p)) {
358 : 0 : found = true;
359 : 0 : break;
360 : : }
361 : : }
362 : :
363 : 3940 : va_end(ap);
364 : :
365 [ - + ]: 3940 : if (found) {
366 : 0 : free(*f);
367 : 0 : continue;
368 : : }
369 : :
370 : 3940 : *(t++) = *f;
371 : : }
372 : :
373 : 56 : *t = NULL;
374 : 56 : return l;
375 : : }
376 : :
377 : 344 : int strv_env_replace(char ***l, char *p) {
378 : : const char *t, *name;
379 : : char **f;
380 : : int r;
381 : :
382 [ - + ]: 344 : assert(p);
383 : :
384 : : /* Replace first occurrence of the env var or add a new one in the string list. Drop other occurrences. Edits
385 : : * in-place. Does not copy p. p must be a valid key=value assignment.
386 : : */
387 : :
388 : 344 : t = strchr(p, '=');
389 [ - + ]: 344 : if (!t)
390 : 0 : return -EINVAL;
391 : :
392 : 344 : name = strndupa(p, t - p);
393 : :
394 [ + + + + ]: 1552 : STRV_FOREACH(f, *l)
395 [ + + ]: 1276 : if (env_entry_has_name(*f, name)) {
396 : 68 : free_and_replace(*f, p);
397 : 68 : strv_env_unset(f + 1, *f);
398 : 68 : return 0;
399 : : }
400 : :
401 : : /* We didn't find a match, we need to append p or create a new strv */
402 : 276 : r = strv_push(l, p);
403 [ - + ]: 276 : if (r < 0)
404 : 0 : return r;
405 : :
406 : 276 : return 1;
407 : : }
408 : :
409 : 4 : char **strv_env_set(char **x, const char *p) {
410 : 4 : _cleanup_strv_free_ char **ret = NULL;
411 : : size_t n, m;
412 : : char **k;
413 : :
414 : : /* Overrides the env var setting of p, returns a new copy */
415 : :
416 : 4 : n = strv_length(x);
417 : 4 : m = n + 2;
418 [ - + ]: 4 : if (m < n) /* overflow? */
419 : 0 : return NULL;
420 : :
421 : 4 : ret = new(char*, m);
422 [ - + ]: 4 : if (!ret)
423 : 0 : return NULL;
424 : :
425 : 4 : *ret = NULL;
426 : 4 : k = ret;
427 : :
428 [ - + ]: 4 : if (env_append(ret, &k, x) < 0)
429 : 0 : return NULL;
430 : :
431 [ - + ]: 4 : if (env_append(ret, &k, STRV_MAKE(p)) < 0)
432 : 0 : return NULL;
433 : :
434 : 4 : return TAKE_PTR(ret);
435 : : }
436 : :
437 : 380 : char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
438 : : char **i;
439 : :
440 [ - + ]: 380 : assert(name);
441 : :
442 [ - + ]: 380 : if (k <= 0)
443 : 0 : return NULL;
444 : :
445 [ + - + - : 1280 : STRV_FOREACH_BACKWARDS(i, l)
+ + ]
446 [ + + ]: 1208 : if (strneq(*i, name, k) &&
447 [ + + ]: 312 : (*i)[k] == '=')
448 : 308 : return *i + k + 1;
449 : :
450 [ + + ]: 72 : if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
451 : : const char *t;
452 : :
453 : 36 : t = strndupa(name, k);
454 : 36 : return getenv(t);
455 : : };
456 : :
457 : 36 : return NULL;
458 : : }
459 : :
460 : 52 : char *strv_env_get(char **l, const char *name) {
461 [ - + ]: 52 : assert(name);
462 : :
463 : 52 : return strv_env_get_n(l, name, strlen(name), 0);
464 : : }
465 : :
466 : 12 : char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
467 : : char **p, **q;
468 : 12 : int k = 0;
469 : :
470 [ + - + + ]: 152 : STRV_FOREACH(p, e) {
471 : : size_t n;
472 : 140 : bool duplicate = false;
473 : :
474 [ + + ]: 140 : if (!env_assignment_is_valid(*p)) {
475 [ - + ]: 40 : if (invalid_callback)
476 : 0 : invalid_callback(*p, userdata);
477 : 40 : free(*p);
478 : 40 : continue;
479 : : }
480 : :
481 : 100 : n = strcspn(*p, "=");
482 [ + - + + ]: 608 : STRV_FOREACH(q, p + 1)
483 [ + + + + ]: 516 : if (strneq(*p, *q, n) && (*q)[n] == '=') {
484 : 8 : duplicate = true;
485 : 8 : break;
486 : : }
487 : :
488 [ + + ]: 100 : if (duplicate) {
489 : 8 : free(*p);
490 : 8 : continue;
491 : : }
492 : :
493 : 92 : e[k++] = *p;
494 : : }
495 : :
496 [ + - ]: 12 : if (e)
497 : 12 : e[k] = NULL;
498 : :
499 : 12 : return e;
500 : : }
501 : :
502 : 260 : char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
503 : : enum {
504 : : WORD,
505 : : CURLY,
506 : : VARIABLE,
507 : : VARIABLE_RAW,
508 : : TEST,
509 : : DEFAULT_VALUE,
510 : : ALTERNATE_VALUE,
511 : 260 : } state = WORD;
512 : :
513 : 260 : const char *e, *word = format, *test_value;
514 : : char *k;
515 : 260 : _cleanup_free_ char *r = NULL;
516 : : size_t i, len;
517 : 260 : int nest = 0;
518 : :
519 [ - + ]: 260 : assert(format);
520 : :
521 [ + + + + ]: 3876 : for (e = format, i = 0; *e && i < n; e ++, i ++)
522 [ + + + + : 3616 : switch (state) {
+ + - ]
523 : :
524 : 1252 : case WORD:
525 [ + + ]: 1252 : if (*e == '$')
526 : 380 : state = CURLY;
527 : 1252 : break;
528 : :
529 : 380 : case CURLY:
530 [ + + ]: 380 : if (*e == '{') {
531 : 272 : k = strnappend(r, word, e-word-1);
532 [ - + ]: 272 : if (!k)
533 : 0 : return NULL;
534 : :
535 : 272 : free_and_replace(r, k);
536 : :
537 : 272 : word = e-1;
538 : 272 : state = VARIABLE;
539 : 272 : nest++;
540 [ + + ]: 108 : } else if (*e == '$') {
541 : 8 : k = strnappend(r, word, e-word);
542 [ - + ]: 8 : if (!k)
543 : 0 : return NULL;
544 : :
545 : 8 : free_and_replace(r, k);
546 : :
547 : 8 : word = e+1;
548 : 8 : state = WORD;
549 : :
550 [ + + + - ]: 100 : } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) {
551 : 60 : k = strnappend(r, word, e-word-1);
552 [ - + ]: 60 : if (!k)
553 : 0 : return NULL;
554 : :
555 : 60 : free_and_replace(r, k);
556 : :
557 : 60 : word = e-1;
558 : 60 : state = VARIABLE_RAW;
559 : :
560 : : } else
561 : 40 : state = WORD;
562 : 380 : break;
563 : :
564 : 1204 : case VARIABLE:
565 [ + + ]: 1204 : if (*e == '}') {
566 : : const char *t;
567 : :
568 : 164 : t = strv_env_get_n(env, word+2, e-word-2, flags);
569 : :
570 : 164 : k = strjoin(r, t);
571 [ - + ]: 164 : if (!k)
572 : 0 : return NULL;
573 : :
574 : 164 : free_and_replace(r, k);
575 : :
576 : 164 : word = e+1;
577 : 164 : state = WORD;
578 [ + + ]: 1040 : } else if (*e == ':') {
579 [ + + ]: 104 : if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
580 : : /* Treat this as unsupported syntax, i.e. do no replacement */
581 : 48 : state = WORD;
582 : : else {
583 : 56 : len = e-word-2;
584 : 56 : state = TEST;
585 : : }
586 : : }
587 : 1204 : break;
588 : :
589 : 56 : case TEST:
590 [ + + ]: 56 : if (*e == '-')
591 : 28 : state = DEFAULT_VALUE;
592 [ + - ]: 28 : else if (*e == '+')
593 : 28 : state = ALTERNATE_VALUE;
594 : : else {
595 : 0 : state = WORD;
596 : 0 : break;
597 : : }
598 : :
599 : 56 : test_value = e+1;
600 : 56 : break;
601 : :
602 : 544 : case DEFAULT_VALUE: /* fall through */
603 : : case ALTERNATE_VALUE:
604 [ - + ]: 544 : assert(flags & REPLACE_ENV_ALLOW_EXTENDED);
605 : :
606 [ + + ]: 544 : if (*e == '{') {
607 : 40 : nest++;
608 : 40 : break;
609 : : }
610 : :
611 [ + + ]: 504 : if (*e != '}')
612 : 408 : break;
613 : :
614 : 96 : nest--;
615 [ + + ]: 96 : if (nest == 0) {
616 : : const char *t;
617 [ + - ]: 56 : _cleanup_free_ char *v = NULL;
618 : :
619 : 56 : t = strv_env_get_n(env, word+2, len, flags);
620 : :
621 [ + + + + ]: 56 : if (t && state == ALTERNATE_VALUE)
622 : 12 : t = v = replace_env_n(test_value, e-test_value, env, flags);
623 [ + + + + ]: 44 : else if (!t && state == DEFAULT_VALUE)
624 : 12 : t = v = replace_env_n(test_value, e-test_value, env, flags);
625 : :
626 : 56 : k = strjoin(r, t);
627 [ - + ]: 56 : if (!k)
628 : 0 : return NULL;
629 : :
630 : 56 : free_and_replace(r, k);
631 : :
632 : 56 : word = e+1;
633 : 56 : state = WORD;
634 : : }
635 : 96 : break;
636 : :
637 : 180 : case VARIABLE_RAW:
638 [ - + ]: 180 : assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
639 : :
640 [ + + ]: 180 : if (!strchr(VALID_CHARS_ENV_NAME, *e)) {
641 : : const char *t;
642 : :
643 : 48 : t = strv_env_get_n(env, word+1, e-word-1, flags);
644 : :
645 : 48 : k = strjoin(r, t);
646 [ - + ]: 48 : if (!k)
647 : 0 : return NULL;
648 : :
649 : 48 : free_and_replace(r, k);
650 : :
651 : 48 : word = e--;
652 : 48 : i--;
653 : 48 : state = WORD;
654 : : }
655 : 180 : break;
656 : : }
657 : :
658 [ + + ]: 3876 : if (state == VARIABLE_RAW) {
659 : : const char *t;
660 : :
661 [ - + ]: 12 : assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
662 : :
663 : 12 : t = strv_env_get_n(env, word+1, e-word-1, flags);
664 : 12 : return strjoin(r, t);
665 : : } else
666 : 248 : return strnappend(r, word, e-word);
667 : : }
668 : :
669 : 4 : char **replace_env_argv(char **argv, char **env) {
670 : : char **ret, **i;
671 : 4 : size_t k = 0, l = 0;
672 : :
673 : 4 : l = strv_length(argv);
674 : :
675 : 4 : ret = new(char*, l+1);
676 [ - + ]: 4 : if (!ret)
677 : 0 : return NULL;
678 : :
679 [ + - + + ]: 72 : STRV_FOREACH(i, argv) {
680 : :
681 : : /* If $FOO appears as single word, replace it by the split up variable */
682 [ + + + + : 68 : if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
+ + ]
683 : : char *e;
684 : 8 : char **w, **m = NULL;
685 : : size_t q;
686 : :
687 : 8 : e = strv_env_get(env, *i+1);
688 [ + + ]: 8 : if (e) {
689 : : int r;
690 : :
691 : 4 : r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
692 [ - + ]: 4 : if (r < 0) {
693 : 0 : ret[k] = NULL;
694 : 0 : strv_free(ret);
695 : 0 : return NULL;
696 : : }
697 : : } else
698 : 4 : m = NULL;
699 : :
700 : 8 : q = strv_length(m);
701 : 8 : l = l + q - 1;
702 : :
703 : 8 : w = reallocarray(ret, l + 1, sizeof(char *));
704 [ - + ]: 8 : if (!w) {
705 : 0 : ret[k] = NULL;
706 : 0 : strv_free(ret);
707 : 0 : strv_free(m);
708 : 0 : return NULL;
709 : : }
710 : :
711 : 8 : ret = w;
712 [ + + ]: 8 : if (m) {
713 : 4 : memcpy(ret + k, m, q * sizeof(char*));
714 : 4 : free(m);
715 : : }
716 : :
717 : 8 : k += q;
718 : 8 : continue;
719 : : }
720 : :
721 : : /* If ${FOO} appears as part of a word, replace it by the variable as-is */
722 : 60 : ret[k] = replace_env(*i, env, 0);
723 [ - + ]: 60 : if (!ret[k]) {
724 : 0 : strv_free(ret);
725 : 0 : return NULL;
726 : : }
727 : 60 : k++;
728 : : }
729 : :
730 : 4 : ret[k] = NULL;
731 : 4 : return ret;
732 : : }
733 : :
734 : 1733 : int getenv_bool(const char *p) {
735 : : const char *e;
736 : :
737 : 1733 : e = getenv(p);
738 [ + + ]: 1733 : if (!e)
739 : 1725 : return -ENXIO;
740 : :
741 : 8 : return parse_boolean(e);
742 : : }
743 : :
744 : 1570 : int getenv_bool_secure(const char *p) {
745 : : const char *e;
746 : :
747 : 1570 : e = secure_getenv(p);
748 [ + - ]: 1570 : if (!e)
749 : 1570 : return -ENXIO;
750 : :
751 : 0 : return parse_boolean(e);
752 : : }
|