Bug Summary

File:build-scan/../src/basic/env-util.c
Warning:line 622, column 45
Although the value stored to 'v' is used in the enclosing expression, the value is never actually read from 'v'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name env-util.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I src/basic/libbasic.a.p -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I . -I .. -I /usr/include/blkid -I /usr/include/libmount -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility default -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/basic/env-util.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).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"0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"
\
21 DIGITS"0123456789" LETTERS"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
22 "_"
23
24#ifndef ARG_MAX((size_t) sysconf(_SC_ARG_MAX))
25#define ARG_MAX((size_t) sysconf(_SC_ARG_MAX)) ((size_t) sysconf(_SC_ARG_MAX_SC_ARG_MAX))
26#endif
27
28static bool_Bool env_name_is_valid_n(const char *e, size_t n) {
29 const char *p;
30
31 if (!e)
32 return false0;
33
34 if (n <= 0)
35 return false0;
36
37 if (e[0] >= '0' && e[0] <= '9')
38 return false0;
39
40 /* POSIX says the overall size of the environment block cannot
41 * be > ARG_MAX, an individual assignment hence cannot be
42 * either. Discounting the equal sign and trailing NUL this
43 * hence leaves ARG_MAX-2 as longest possible variable
44 * name. */
45 if (n > ARG_MAX((size_t) sysconf(_SC_ARG_MAX)) - 2)
46 return false0;
47
48 for (p = e; p < e + n; p++)
49 if (!strchr(VALID_CHARS_ENV_NAME"0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"
, *p))
50 return false0;
51
52 return true1;
53}
54
55bool_Bool env_name_is_valid(const char *e) {
56 if (!e)
57 return false0;
58
59 return env_name_is_valid_n(e, strlen(e));
60}
61
62bool_Bool env_value_is_valid(const char *e) {
63 if (!e)
64 return false0;
65
66 if (!utf8_is_valid(e))
67 return false0;
68
69 /* bash allows tabs and newlines in environment variables, and so
70 * should we */
71 if (string_has_cc(e, "\t\n"))
72 return false0;
73
74 /* POSIX says the overall size of the environment block cannot
75 * be > ARG_MAX, an individual assignment hence cannot be
76 * either. Discounting the shortest possible variable name of
77 * length 1, the equal sign and trailing NUL this hence leaves
78 * ARG_MAX-3 as longest possible variable value. */
79 if (strlen(e) > ARG_MAX((size_t) sysconf(_SC_ARG_MAX)) - 3)
80 return false0;
81
82 return true1;
83}
84
85bool_Bool env_assignment_is_valid(const char *e) {
86 const char *eq;
87
88 eq = strchr(e, '=');
89 if (!eq)
90 return false0;
91
92 if (!env_name_is_valid_n(e, eq - e))
93 return false0;
94
95 if (!env_value_is_valid(eq + 1))
96 return false0;
97
98 /* POSIX says the overall size of the environment block cannot
99 * be > ARG_MAX, hence the individual variable assignments
100 * cannot be either, but let's leave room for one trailing NUL
101 * byte. */
102 if (strlen(e) > ARG_MAX((size_t) sysconf(_SC_ARG_MAX)) - 1)
103 return false0;
104
105 return true1;
106}
107
108bool_Bool strv_env_is_valid(char **e) {
109 char **p, **q;
110
111 STRV_FOREACH(p, e)for ((p) = (e); (p) && *(p); (p)++) {
112 size_t k;
113
114 if (!env_assignment_is_valid(*p))
115 return false0;
116
117 /* Check if there are duplicate assginments */
118 k = strcspn(*p, "=");
119 STRV_FOREACH(q, p + 1)for ((q) = (p + 1); (q) && *(q); (q)++)
120 if (strneq(*p, *q, k)(strncmp((*p), (*q), (k)) == 0) && (*q)[k] == '=')
121 return false0;
122 }
123
124 return true1;
125}
126
127bool_Bool strv_env_name_is_valid(char **l) {
128 char **p, **q;
129
130 STRV_FOREACH(p, l)for ((p) = (l); (p) && *(p); (p)++) {
131 if (!env_name_is_valid(*p))
132 return false0;
133
134 STRV_FOREACH(q, p + 1)for ((q) = (p + 1); (q) && *(q); (q)++)
135 if (streq(*p, *q)(strcmp((*p),(*q)) == 0))
136 return false0;
137 }
138
139 return true1;
140}
141
142bool_Bool strv_env_name_or_assignment_is_valid(char **l) {
143 char **p, **q;
144
145 STRV_FOREACH(p, l)for ((p) = (l); (p) && *(p); (p)++) {
146 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
147 return false0;
148
149 STRV_FOREACH(q, p + 1)for ((q) = (p + 1); (q) && *(q); (q)++)
150 if (streq(*p, *q)(strcmp((*p),(*q)) == 0))
151 return false0;
152 }
153
154 return true1;
155}
156
157static int env_append(char **r, char ***k, char **a) {
158 assert(r)do { if ((__builtin_expect(!!(!(r)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("r"), "../src/basic/env-util.c", 158, __PRETTY_FUNCTION__
); } while (0)
;
159 assert(k)do { if ((__builtin_expect(!!(!(k)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("k"), "../src/basic/env-util.c", 159, __PRETTY_FUNCTION__
); } while (0)
;
160
161 if (!a)
162 return 0;
163
164 /* Add the entries of a to *k unless they already exist in *r
165 * in which case they are overridden instead. This assumes
166 * there is enough space in the r array. */
167
168 for (; *a; a++) {
169 char **j;
170 size_t n;
171
172 n = strcspn(*a, "=");
173
174 if ((*a)[n] == '=')
175 n++;
176
177 for (j = r; j < *k; j++)
178 if (strneq(*j, *a, n)(strncmp((*j), (*a), (n)) == 0))
179 break;
180
181 if (j >= *k)
182 (*k)++;
183 else
184 free(*j);
185
186 *j = strdup(*a);
187 if (!*j)
188 return -ENOMEM12;
189 }
190
191 return 0;
192}
193
194char **strv_env_merge(size_t n_lists, ...) {
195 size_t n = 0;
196 char **l, **k, **r;
197 va_list ap;
198 size_t i;
199
200 /* Merges an arbitrary number of environment sets */
201
202 va_start(ap, n_lists)__builtin_va_start(ap, n_lists);
203 for (i = 0; i < n_lists; i++) {
204 l = va_arg(ap, char**)__builtin_va_arg(ap, char**);
205 n += strv_length(l);
206 }
207 va_end(ap)__builtin_va_end(ap);
208
209 r = new(char*, n+1)((char**) malloc_multiply(sizeof(char*), (n+1)));
210 if (!r)
211 return NULL((void*)0);
212
213 k = r;
214
215 va_start(ap, n_lists)__builtin_va_start(ap, n_lists);
216 for (i = 0; i < n_lists; i++) {
217 l = va_arg(ap, char**)__builtin_va_arg(ap, char**);
218 if (env_append(r, &k, l) < 0)
219 goto fail;
220 }
221 va_end(ap)__builtin_va_end(ap);
222
223 *k = NULL((void*)0);
224
225 return r;
226
227fail:
228 va_end(ap)__builtin_va_end(ap);
229 strv_free(r);
230
231 return NULL((void*)0);
232}
233
234static bool_Bool env_match(const char *t, const char *pattern) {
235 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/basic/env-util.c", 235, __PRETTY_FUNCTION__
); } while (0)
;
236 assert(pattern)do { if ((__builtin_expect(!!(!(pattern)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("pattern"), "../src/basic/env-util.c", 236
, __PRETTY_FUNCTION__); } while (0)
;
237
238 /* pattern a matches string a
239 * a matches a=
240 * a matches a=b
241 * a= matches a=
242 * a=b matches a=b
243 * a= does not match a
244 * a=b does not match a=
245 * a=b does not match a
246 * a=b does not match a=c */
247
248 if (streq(t, pattern)(strcmp((t),(pattern)) == 0))
249 return true1;
250
251 if (!strchr(pattern, '=')) {
252 size_t l = strlen(pattern);
253
254 return strneq(t, pattern, l)(strncmp((t), (pattern), (l)) == 0) && t[l] == '=';
255 }
256
257 return false0;
258}
259
260static bool_Bool env_entry_has_name(const char *entry, const char *name) {
261 const char *t;
262
263 assert(entry)do { if ((__builtin_expect(!!(!(entry)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("entry"), "../src/basic/env-util.c", 263
, __PRETTY_FUNCTION__); } while (0)
;
264 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/env-util.c", 264,
__PRETTY_FUNCTION__); } while (0)
;
265
266 t = startswith(entry, name);
267 if (!t)
268 return false0;
269
270 return *t == '=';
271}
272
273char **strv_env_delete(char **x, size_t n_lists, ...) {
274 size_t n, i = 0;
275 char **k, **r;
276 va_list ap;
277
278 /* Deletes every entry from x that is mentioned in the other
279 * string lists */
280
281 n = strv_length(x);
282
283 r = new(char*, n+1)((char**) malloc_multiply(sizeof(char*), (n+1)));
284 if (!r)
285 return NULL((void*)0);
286
287 STRV_FOREACH(k, x)for ((k) = (x); (k) && *(k); (k)++) {
288 size_t v;
289
290 va_start(ap, n_lists)__builtin_va_start(ap, n_lists);
291 for (v = 0; v < n_lists; v++) {
292 char **l, **j;
293
294 l = va_arg(ap, char**)__builtin_va_arg(ap, char**);
295 STRV_FOREACH(j, l)for ((j) = (l); (j) && *(j); (j)++)
296 if (env_match(*k, *j))
297 goto skip;
298 }
299 va_end(ap)__builtin_va_end(ap);
300
301 r[i] = strdup(*k);
302 if (!r[i]) {
303 strv_free(r);
304 return NULL((void*)0);
305 }
306
307 i++;
308 continue;
309
310 skip:
311 va_end(ap)__builtin_va_end(ap);
312 }
313
314 r[i] = NULL((void*)0);
315
316 assert(i <= n)do { if ((__builtin_expect(!!(!(i <= n)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("i <= n"), "../src/basic/env-util.c",
316, __PRETTY_FUNCTION__); } while (0)
;
317
318 return r;
319}
320
321char **strv_env_unset(char **l, const char *p) {
322
323 char **f, **t;
324
325 if (!l)
326 return NULL((void*)0);
327
328 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/env-util.c", 328, __PRETTY_FUNCTION__
); } while (0)
;
329
330 /* Drops every occurrence of the env var setting p in the
331 * string list. Edits in-place. */
332
333 for (f = t = l; *f; f++) {
334
335 if (env_match(*f, p)) {
336 free(*f);
337 continue;
338 }
339
340 *(t++) = *f;
341 }
342
343 *t = NULL((void*)0);
344 return l;
345}
346
347char **strv_env_unset_many(char **l, ...) {
348
349 char **f, **t;
350
351 if (!l)
352 return NULL((void*)0);
353
354 /* Like strv_env_unset() but applies many at once. Edits in-place. */
355
356 for (f = t = l; *f; f++) {
357 bool_Bool found = false0;
358 const char *p;
359 va_list ap;
360
361 va_start(ap, l)__builtin_va_start(ap, l);
362
363 while ((p = va_arg(ap, const char*)__builtin_va_arg(ap, const char*))) {
364 if (env_match(*f, p)) {
365 found = true1;
366 break;
367 }
368 }
369
370 va_end(ap)__builtin_va_end(ap);
371
372 if (found) {
373 free(*f);
374 continue;
375 }
376
377 *(t++) = *f;
378 }
379
380 *t = NULL((void*)0);
381 return l;
382}
383
384int strv_env_replace(char ***l, char *p) {
385 char **f;
386 const char *t, *name;
387
388 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/basic/env-util.c", 388, __PRETTY_FUNCTION__
); } while (0)
;
389
390 /* Replace first occurrence of the env var or add a new one in the
391 * string list. Drop other occurences. Edits in-place. Does not copy p.
392 * p must be a valid key=value assignment.
393 */
394
395 t = strchr(p, '=');
396 assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("t"), "../src/basic/env-util.c", 396, __PRETTY_FUNCTION__
); } while (0)
;
397
398 name = strndupa(p, t - p)(__extension__ ({ const char *__old = (p); size_t __len = strnlen
(__old, (t - p)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
399
400 for (f = *l; f && *f; f++)
401 if (env_entry_has_name(*f, name)) {
402 free_and_replace(*f, p)({ free(*f); (*f) = (p); (p) = ((void*)0); 0; });
403 strv_env_unset(f + 1, *f);
404 return 0;
405 }
406
407 /* We didn't find a match, we need to append p or create a new strv */
408 if (strv_push(l, p) < 0)
409 return -ENOMEM12;
410 return 1;
411}
412
413char **strv_env_set(char **x, const char *p) {
414
415 char **k;
416 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **r = NULL((void*)0);
417 char* m[2] = { (char*) p, NULL((void*)0) };
418
419 /* Overrides the env var setting of p, returns a new copy */
420
421 r = new(char*, strv_length(x)+2)((char**) malloc_multiply(sizeof(char*), (strv_length(x)+2)));
422 if (!r)
423 return NULL((void*)0);
424
425 k = r;
426 if (env_append(r, &k, x) < 0)
427 return NULL((void*)0);
428
429 if (env_append(r, &k, m) < 0)
430 return NULL((void*)0);
431
432 *k = NULL((void*)0);
433
434 return TAKE_PTR(r)({ typeof(r) _ptr_ = (r); (r) = ((void*)0); _ptr_; });
435}
436
437char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
438 char **i;
439
440 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/env-util.c", 440,
__PRETTY_FUNCTION__); } while (0)
;
441
442 if (k <= 0)
443 return NULL((void*)0);
444
445 STRV_FOREACH_BACKWARDS(i, l)for (i = ({ char **_l = l; _l ? _l + strv_length(_l) - 1U : (
(void*)0); }); (l) && ((i) >= (l)); (i)--)
446 if (strneq(*i, name, k)(strncmp((*i), (name), (k)) == 0) &&
447 (*i)[k] == '=')
448 return *i + k + 1;
449
450 if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
451 const char *t;
452
453 t = strndupa(name, k)(__extension__ ({ const char *__old = (name); size_t __len = strnlen
(__old, (k)); char *__new = (char *) __builtin_alloca (__len
+ 1); __new[__len] = '\0'; (char *) memcpy (__new, __old, __len
); }))
;
454 return getenv(t);
455 };
456
457 return NULL((void*)0);
458}
459
460char *strv_env_get(char **l, const char *name) {
461 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/basic/env-util.c", 461,
__PRETTY_FUNCTION__); } while (0)
;
462
463 return strv_env_get_n(l, name, strlen(name), 0);
464}
465
466char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) {
467 char **p, **q;
468 int k = 0;
469
470 STRV_FOREACH(p, e)for ((p) = (e); (p) && *(p); (p)++) {
471 size_t n;
472 bool_Bool duplicate = false0;
473
474 if (!env_assignment_is_valid(*p)) {
475 if (invalid_callback)
476 invalid_callback(*p, userdata);
477 free(*p);
478 continue;
479 }
480
481 n = strcspn(*p, "=");
482 STRV_FOREACH(q, p + 1)for ((q) = (p + 1); (q) && *(q); (q)++)
483 if (strneq(*p, *q, n)(strncmp((*p), (*q), (n)) == 0) && (*q)[n] == '=') {
484 duplicate = true1;
485 break;
486 }
487
488 if (duplicate) {
489 free(*p);
490 continue;
491 }
492
493 e[k++] = *p;
494 }
495
496 if (e)
497 e[k] = NULL((void*)0);
498
499 return e;
500}
501
502char *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 } state = WORD;
512
513 const char *e, *word = format, *test_value;
514 char *k;
515 _cleanup_free___attribute__((cleanup(freep))) char *r = NULL((void*)0);
516 size_t i, len;
517 int nest = 0;
518
519 assert(format)do { if ((__builtin_expect(!!(!(format)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("format"), "../src/basic/env-util.c", 519
, __PRETTY_FUNCTION__); } while (0)
;
520
521 for (e = format, i = 0; *e && i < n; e ++, i ++)
522 switch (state) {
523
524 case WORD:
525 if (*e == '$')
526 state = CURLY;
527 break;
528
529 case CURLY:
530 if (*e == '{') {
531 k = strnappend(r, word, e-word-1);
532 if (!k)
533 return NULL((void*)0);
534
535 free_and_replace(r, k)({ free(r); (r) = (k); (k) = ((void*)0); 0; });
536
537 word = e-1;
538 state = VARIABLE;
539 nest++;
540 } else if (*e == '$') {
541 k = strnappend(r, word, e-word);
542 if (!k)
543 return NULL((void*)0);
544
545 free_and_replace(r, k)({ free(r); (r) = (k); (k) = ((void*)0); 0; });
546
547 word = e+1;
548 state = WORD;
549
550 } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME"0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"
, *e)) {
551 k = strnappend(r, word, e-word-1);
552 if (!k)
553 return NULL((void*)0);
554
555 free_and_replace(r, k)({ free(r); (r) = (k); (k) = ((void*)0); 0; });
556
557 word = e-1;
558 state = VARIABLE_RAW;
559
560 } else
561 state = WORD;
562 break;
563
564 case VARIABLE:
565 if (*e == '}') {
566 const char *t;
567
568 t = strv_env_get_n(env, word+2, e-word-2, flags);
569
570 k = strappend(r, t);
571 if (!k)
572 return NULL((void*)0);
573
574 free_and_replace(r, k)({ free(r); (r) = (k); (k) = ((void*)0); 0; });
575
576 word = e+1;
577 state = WORD;
578 } else if (*e == ':') {
579 if (!(flags & REPLACE_ENV_ALLOW_EXTENDED))
580 /* Treat this as unsupported syntax, i.e. do no replacement */
581 state = WORD;
582 else {
583 len = e-word-2;
584 state = TEST;
585 }
586 }
587 break;
588
589 case TEST:
590 if (*e == '-')
591 state = DEFAULT_VALUE;
592 else if (*e == '+')
593 state = ALTERNATE_VALUE;
594 else {
595 state = WORD;
596 break;
597 }
598
599 test_value = e+1;
600 break;
601
602 case DEFAULT_VALUE: /* fall through */
603 case ALTERNATE_VALUE:
604 assert(flags & REPLACE_ENV_ALLOW_EXTENDED)do { if ((__builtin_expect(!!(!(flags & REPLACE_ENV_ALLOW_EXTENDED
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("flags & REPLACE_ENV_ALLOW_EXTENDED"
), "../src/basic/env-util.c", 604, __PRETTY_FUNCTION__); } while
(0)
;
605
606 if (*e == '{') {
607 nest++;
608 break;
609 }
610
611 if (*e != '}')
612 break;
613
614 nest--;
615 if (nest == 0) {
616 const char *t;
617 _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0);
618
619 t = strv_env_get_n(env, word+2, len, flags);
620
621 if (t && state == ALTERNATE_VALUE)
622 t = v = replace_env_n(test_value, e-test_value, env, flags);
Although the value stored to 'v' is used in the enclosing expression, the value is never actually read from 'v'
623 else if (!t && state == DEFAULT_VALUE)
624 t = v = replace_env_n(test_value, e-test_value, env, flags);
625
626 k = strappend(r, t);
627 if (!k)
628 return NULL((void*)0);
629
630 free_and_replace(r, k)({ free(r); (r) = (k); (k) = ((void*)0); 0; });
631
632 word = e+1;
633 state = WORD;
634 }
635 break;
636
637 case VARIABLE_RAW:
638 assert(flags & REPLACE_ENV_ALLOW_BRACELESS)do { if ((__builtin_expect(!!(!(flags & REPLACE_ENV_ALLOW_BRACELESS
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("flags & REPLACE_ENV_ALLOW_BRACELESS"
), "../src/basic/env-util.c", 638, __PRETTY_FUNCTION__); } while
(0)
;
639
640 if (!strchr(VALID_CHARS_ENV_NAME"0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"_"
, *e)) {
641 const char *t;
642
643 t = strv_env_get_n(env, word+1, e-word-1, flags);
644
645 k = strappend(r, t);
646 if (!k)
647 return NULL((void*)0);
648
649 free_and_replace(r, k)({ free(r); (r) = (k); (k) = ((void*)0); 0; });
650
651 word = e--;
652 i--;
653 state = WORD;
654 }
655 break;
656 }
657
658 if (state == VARIABLE_RAW) {
659 const char *t;
660
661 assert(flags & REPLACE_ENV_ALLOW_BRACELESS)do { if ((__builtin_expect(!!(!(flags & REPLACE_ENV_ALLOW_BRACELESS
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("flags & REPLACE_ENV_ALLOW_BRACELESS"
), "../src/basic/env-util.c", 661, __PRETTY_FUNCTION__); } while
(0)
;
662
663 t = strv_env_get_n(env, word+1, e-word-1, flags);
664 return strappend(r, t);
665 } else
666 return strnappend(r, word, e-word);
667}
668
669char **replace_env_argv(char **argv, char **env) {
670 char **ret, **i;
671 size_t k = 0, l = 0;
672
673 l = strv_length(argv);
674
675 ret = new(char*, l+1)((char**) malloc_multiply(sizeof(char*), (l+1)));
676 if (!ret)
677 return NULL((void*)0);
678
679 STRV_FOREACH(i, argv)for ((i) = (argv); (i) && *(i); (i)++) {
680
681 /* If $FOO appears as single word, replace it by the split up variable */
682 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){'{', '$'})/sizeof(int)]; switch((*i)[1])
{ case '{': case '$': _found = 1; break; default: break; } _found
; })
) {
683 char *e;
684 char **w, **m = NULL((void*)0);
685 size_t q;
686
687 e = strv_env_get(env, *i+1);
688 if (e) {
689 int r;
690
691 r = strv_split_extract(&m, e, WHITESPACE" \t\n\r", EXTRACT_RELAX|EXTRACT_QUOTES);
692 if (r < 0) {
693 ret[k] = NULL((void*)0);
694 strv_free(ret);
695 return NULL((void*)0);
696 }
697 } else
698 m = NULL((void*)0);
699
700 q = strv_length(m);
701 l = l + q - 1;
702
703 w = reallocarray(ret, l + 1, sizeof(char *));
704 if (!w) {
705 ret[k] = NULL((void*)0);
706 strv_free(ret);
707 strv_free(m);
708 return NULL((void*)0);
709 }
710
711 ret = w;
712 if (m) {
713 memcpy(ret + k, m, q * sizeof(char*));
714 free(m);
715 }
716
717 k += q;
718 continue;
719 }
720
721 /* If ${FOO} appears as part of a word, replace it by the variable as-is */
722 ret[k] = replace_env(*i, env, 0);
723 if (!ret[k]) {
724 strv_free(ret);
725 return NULL((void*)0);
726 }
727 k++;
728 }
729
730 ret[k] = NULL((void*)0);
731 return ret;
732}
733
734int getenv_bool(const char *p) {
735 const char *e;
736
737 e = getenv(p);
738 if (!e)
739 return -ENXIO6;
740
741 return parse_boolean(e);
742}
743
744int getenv_bool_secure(const char *p) {
745 const char *e;
746
747 e = secure_getenv(p);
748 if (!e)
749 return -ENXIO6;
750
751 return parse_boolean(e);
752}
753
754int serialize_environment(FILE *f, char **environment) {
755 char **e;
756
757 STRV_FOREACH(e, environment)for ((e) = (environment); (e) && *(e); (e)++) {
758 _cleanup_free___attribute__((cleanup(freep))) char *ce;
759
760 ce = cescape(*e);
761 if (!ce)
762 return -ENOMEM12;
763
764 fprintf(f, "env=%s\n", ce);
765 }
766
767 /* caller should call ferror() */
768
769 return 0;
770}
771
772int deserialize_environment(char ***environment, const char *line) {
773 char *uce;
774 int r;
775
776 assert(line)do { if ((__builtin_expect(!!(!(line)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("line"), "../src/basic/env-util.c", 776,
__PRETTY_FUNCTION__); } while (0)
;
777 assert(environment)do { if ((__builtin_expect(!!(!(environment)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("environment"), "../src/basic/env-util.c"
, 777, __PRETTY_FUNCTION__); } while (0)
;
778
779 assert(startswith(line, "env="))do { if ((__builtin_expect(!!(!(startswith(line, "env="))),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("startswith(line, \"env=\")"
), "../src/basic/env-util.c", 779, __PRETTY_FUNCTION__); } while
(0)
;
780 r = cunescape(line + 4, 0, &uce);
781 if (r < 0)
782 return r;
783
784 return strv_env_replace(environment, uce);
785}