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