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