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