LCOV - code coverage report
Current view: top level - basic - env-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 325 388 83.8 %
Date: 2019-08-22 15:41:25 Functions: 21 23 91.3 %

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

Generated by: LCOV version 1.14