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' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
28 | static 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 | |
55 | bool_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 | |
62 | bool_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 | |
85 | bool_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 | |
108 | bool_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 | |
127 | bool_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 | |
142 | bool_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 | |
157 | static 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 | |
194 | char **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 | |
227 | fail: |
228 | va_end(ap)__builtin_va_end(ap); |
229 | strv_free(r); |
230 | |
231 | return NULL((void*)0); |
232 | } |
233 | |
234 | static 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 | |
260 | static 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 | |
273 | char **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 | |
321 | char **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 | |
347 | char **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 | |
384 | int 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 | |
413 | char **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 | |
437 | char *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 | |
460 | char *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 | |
466 | char **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 | |
502 | 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 | } 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 | |
669 | char **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 | |
734 | int 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 | |
744 | int 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 | |
754 | int 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 | |
772 | int 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 | } |