]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/env-util.c
Introduce sc_arg_max() helper
[thirdparty/systemd.git] / src / basic / env-util.c
index 105fa7973d2cb8e340f8c73ff73dbad1dc50c985..896eec58356a0673ec7feb1a951e0b0839123bea 100644 (file)
@@ -1,9 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2012 Lennart Poettering
-***/
 
 #include <errno.h>
 #include <limits.h>
         DIGITS LETTERS                          \
         "_"
 
-#ifndef ARG_MAX
-#define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX))
-#endif
-
 static bool env_name_is_valid_n(const char *e, size_t n) {
         const char *p;
 
@@ -47,7 +38,7 @@ static bool env_name_is_valid_n(const char *e, size_t n) {
          * either. Discounting the equal sign and trailing NUL this
          * hence leaves ARG_MAX-2 as longest possible variable
          * name. */
-        if (n > ARG_MAX - 2)
+        if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
                 return false;
 
         for (p = e; p < e + n; p++)
@@ -81,7 +72,7 @@ bool env_value_is_valid(const char *e) {
          * either. Discounting the shortest possible variable name of
          * length 1, the equal sign and trailing NUL this hence leaves
          * ARG_MAX-3 as longest possible variable value. */
-        if (strlen(e) > ARG_MAX - 3)
+        if (strlen(e) > sc_arg_max() - 3)
                 return false;
 
         return true;
@@ -104,7 +95,7 @@ bool env_assignment_is_valid(const char *e) {
          * be > ARG_MAX, hence the individual variable assignments
          * cannot be either, but let's leave room for one trailing NUL
          * byte. */
-        if (strlen(e) > ARG_MAX - 1)
+        if (strlen(e) > sc_arg_max() - 1)
                 return false;
 
         return true;
@@ -119,7 +110,7 @@ bool strv_env_is_valid(char **e) {
                 if (!env_assignment_is_valid(*p))
                         return false;
 
-                /* Check if there are duplicate assginments */
+                /* Check if there are duplicate assignments */
                 k = strcspn(*p, "=");
                 STRV_FOREACH(q, p + 1)
                         if (strneq(*p, *q, k) && (*q)[k] == '=')
@@ -130,30 +121,28 @@ bool strv_env_is_valid(char **e) {
 }
 
 bool strv_env_name_is_valid(char **l) {
-        char **p, **q;
+        char **p;
 
         STRV_FOREACH(p, l) {
                 if (!env_name_is_valid(*p))
                         return false;
 
-                STRV_FOREACH(q, p + 1)
-                        if (streq(*p, *q))
-                                return false;
+                if (strv_contains(p + 1, *p))
+                        return false;
         }
 
         return true;
 }
 
 bool strv_env_name_or_assignment_is_valid(char **l) {
-        char **p, **q;
+        char **p;
 
         STRV_FOREACH(p, l) {
                 if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p))
                         return false;
 
-                STRV_FOREACH(q, p + 1)
-                        if (streq(*p, *q))
-                                return false;
+                if (strv_contains(p + 1, *p))
+                        return false;
         }
 
         return true;
@@ -162,20 +151,23 @@ bool strv_env_name_or_assignment_is_valid(char **l) {
 static int env_append(char **r, char ***k, char **a) {
         assert(r);
         assert(k);
+        assert(*k >= r);
 
         if (!a)
                 return 0;
 
-        /* Add the entries of a to *k unless they already exist in *r
-         * in which case they are overridden instead. This assumes
-         * there is enough space in the r array. */
+        /* Expects the following arguments: 'r' shall point to the beginning of an strv we are going to append to, 'k'
+         * to a pointer pointing to the NULL entry at the end of the same array. 'a' shall point to another strv.
+         *
+         * This call adds every entry of 'a' to 'r', either overriding an existing matching entry, or appending to it.
+         *
+         * This call assumes 'r' has enough pre-allocated space to grow by all of 'a''s items. */
 
         for (; *a; a++) {
-                char **j;
+                char **j, *c;
                 size_t n;
 
                 n = strcspn(*a, "=");
-
                 if ((*a)[n] == '=')
                         n++;
 
@@ -183,24 +175,26 @@ static int env_append(char **r, char ***k, char **a) {
                         if (strneq(*j, *a, n))
                                 break;
 
-                if (j >= *k)
-                        (*k)++;
-                else
-                        free(*j);
-
-                *j = strdup(*a);
-                if (!*j)
+                c = strdup(*a);
+                if (!c)
                         return -ENOMEM;
+
+                if (j >= *k) { /* Append to the end? */
+                        (*k)[0] = c;
+                        (*k)[1] = NULL;
+                        (*k)++;
+                } else
+                        free_and_replace(*j, c); /* Override existing item */
         }
 
         return 0;
 }
 
-char **strv_env_merge(unsigned n_lists, ...) {
-        size_t n = 0;
-        char **l, **k, **r;
+char **strv_env_merge(size_t n_lists, ...) {
+        _cleanup_strv_free_ char **ret = NULL;
+        size_t n = 0, i;
+        char **l, **k;
         va_list ap;
-        unsigned i;
 
         /* Merges an arbitrary number of environment sets */
 
@@ -211,29 +205,24 @@ char **strv_env_merge(unsigned n_lists, ...) {
         }
         va_end(ap);
 
-        r = new(char*, n+1);
-        if (!r)
+        ret = new(char*, n+1);
+        if (!ret)
                 return NULL;
 
-        k = r;
+        *ret = NULL;
+        k = ret;
 
         va_start(ap, n_lists);
         for (i = 0; i < n_lists; i++) {
                 l = va_arg(ap, char**);
-                if (env_append(r, &k, l) < 0)
-                        goto fail;
+                if (env_append(ret, &k, l) < 0) {
+                        va_end(ap);
+                        return NULL;
+                }
         }
         va_end(ap);
 
-        *k = NULL;
-
-        return r;
-
-fail:
-        va_end(ap);
-        strv_free(r);
-
-        return NULL;
+        return TAKE_PTR(ret);
 }
 
 static bool env_match(const char *t, const char *pattern) {
@@ -275,7 +264,7 @@ static bool env_entry_has_name(const char *entry, const char *name) {
         return *t == '=';
 }
 
-char **strv_env_delete(char **x, unsigned n_lists, ...) {
+char **strv_env_delete(char **x, size_t n_lists, ...) {
         size_t n, i = 0;
         char **k, **r;
         va_list ap;
@@ -290,7 +279,7 @@ char **strv_env_delete(char **x, unsigned n_lists, ...) {
                 return NULL;
 
         STRV_FOREACH(k, x) {
-                unsigned v;
+                size_t v;
 
                 va_start(ap, n_lists);
                 for (v = 0; v < n_lists; v++) {
@@ -350,7 +339,6 @@ char **strv_env_unset(char **l, const char *p) {
 }
 
 char **strv_env_unset_many(char **l, ...) {
-
         char **f, **t;
 
         if (!l)
@@ -387,22 +375,23 @@ char **strv_env_unset_many(char **l, ...) {
 }
 
 int strv_env_replace(char ***l, char *p) {
-        char **f;
         const char *t, *name;
+        char **f;
+        int r;
 
         assert(p);
 
-        /* Replace first occurrence of the env var or add a new one in the
-         * string list. Drop other occurences. Edits in-place. Does not copy p.
-         * p must be a valid key=value assignment.
+        /* Replace first occurrence of the env var or add a new one in the string list. Drop other occurrences. Edits
+         * in-place. Does not copy p.  p must be a valid key=value assignment.
          */
 
         t = strchr(p, '=');
-        assert(t);
+        if (!t)
+                return -EINVAL;
 
         name = strndupa(p, t - p);
 
-        for (f = *l; f && *f; f++)
+        STRV_FOREACH(f, *l)
                 if (env_entry_has_name(*f, name)) {
                         free_and_replace(*f, p);
                         strv_env_unset(f + 1, *f);
@@ -410,36 +399,39 @@ int strv_env_replace(char ***l, char *p) {
                 }
 
         /* We didn't find a match, we need to append p or create a new strv */
-        if (strv_push(l, p) < 0)
-                return -ENOMEM;
+        r = strv_push(l, p);
+        if (r < 0)
+                return r;
+
         return 1;
 }
 
 char **strv_env_set(char **x, const char *p) {
-
-        char **k, **r;
-        char* m[2] = { (char*) p, NULL };
+        _cleanup_strv_free_ char **ret = NULL;
+        size_t n, m;
+        char **k;
 
         /* Overrides the env var setting of p, returns a new copy */
 
-        r = new(char*, strv_length(x)+2);
-        if (!r)
+        n = strv_length(x);
+        m = n + 2;
+        if (m < n) /* overflow? */
                 return NULL;
 
-        k = r;
-        if (env_append(r, &k, x) < 0)
-                goto fail;
+        ret = new(char*, m);
+        if (!ret)
+                return NULL;
 
-        if (env_append(r, &k, m) < 0)
-                goto fail;
+        *ret = NULL;
+        k = ret;
 
-        *k = NULL;
+        if (env_append(ret, &k, x) < 0)
+                return NULL;
 
-        return r;
+        if (env_append(ret, &k, STRV_MAKE(p)) < 0)
+                return NULL;
 
-fail:
-        strv_free(r);
-        return NULL;
+        return TAKE_PTR(ret);
 }
 
 char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
@@ -676,7 +668,7 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
 
 char **replace_env_argv(char **argv, char **env) {
         char **ret, **i;
-        unsigned k = 0, l = 0;
+        size_t k = 0, l = 0;
 
         l = strv_length(argv);
 
@@ -690,7 +682,7 @@ char **replace_env_argv(char **argv, char **env) {
                 if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
                         char *e;
                         char **w, **m = NULL;
-                        unsigned q;
+                        size_t q;
 
                         e = strv_env_get(env, *i+1);
                         if (e) {
@@ -758,36 +750,3 @@ int getenv_bool_secure(const char *p) {
 
         return parse_boolean(e);
 }
-
-int serialize_environment(FILE *f, char **environment) {
-        char **e;
-
-        STRV_FOREACH(e, environment) {
-                _cleanup_free_ char *ce;
-
-                ce = cescape(*e);
-                if (!ce)
-                        return -ENOMEM;
-
-                fprintf(f, "env=%s\n", ce);
-        }
-
-        /* caller should call ferror() */
-
-        return 0;
-}
-
-int deserialize_environment(char ***environment, const char *line) {
-        char *uce;
-        int r;
-
-        assert(line);
-        assert(environment);
-
-        assert(startswith(line, "env="));
-        r = cunescape(line + 4, 0, &uce);
-        if (r < 0)
-                return r;
-
-        return strv_env_replace(environment, uce);
-}