This source file includes following definitions.
- env_name_is_valid_n
- env_name_is_valid
- env_value_is_valid
- env_assignment_is_valid
- strv_env_is_valid
- strv_env_name_or_assignment_is_valid
- env_append
- strv_env_merge
- env_match
- strv_env_delete
- strv_env_unset
- strv_env_unset_many
- strv_env_set
- strv_env_get_n
- strv_env_get
- strv_env_clean_log
- strv_env_clean
#include <limits.h>
#include <sys/param.h>
#include <unistd.h>
#include "strv.h"
#include "utf8.h"
#include "util.h"
#include "env-util.h"
#include "def.h"
#include "unit.h"
#define VALID_CHARS_ENV_NAME \
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;
if (!e)
return false;
if (n <= 0)
return false;
if (e[0] >= '0' && e[0] <= '9')
return false;
if (n > ARG_MAX - 2)
return false;
for (p = e; p < e + n; p++)
if (!strchr(VALID_CHARS_ENV_NAME, *p))
return false;
return true;
}
bool env_name_is_valid(const char *e) {
if (!e)
return false;
return env_name_is_valid_n(e, strlen(e));
}
bool env_value_is_valid(const char *e) {
if (!e)
return false;
if (!utf8_is_valid(e))
return false;
if (string_has_cc(e, "\t"))
return false;
if (strlen(e) > ARG_MAX - 3)
return false;
return true;
}
bool env_assignment_is_valid(const char *e) {
const char *eq;
eq = strchr(e, '=');
if (!eq)
return false;
if (!env_name_is_valid_n(e, eq - e))
return false;
if (!env_value_is_valid(eq + 1))
return false;
if (strlen(e) > ARG_MAX - 1)
return false;
return true;
}
bool strv_env_is_valid(char **e) {
char **p, **q;
STRV_FOREACH(p, e) {
size_t k;
if (!env_assignment_is_valid(*p))
return false;
k = strcspn(*p, "=");
STRV_FOREACH(q, p + 1)
if (strneq(*p, *q, k) && (*q)[k] == '=')
return false;
}
return true;
}
bool strv_env_name_or_assignment_is_valid(char **l) {
char **p, **q;
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;
}
return true;
}
static int env_append(char **r, char ***k, char **a) {
assert(r);
assert(k);
if (!a)
return 0;
for (; *a; a++) {
char **j;
size_t n;
n = strcspn(*a, "=");
if ((*a)[n] == '=')
n++;
for (j = r; j < *k; j++)
if (strneq(*j, *a, n))
break;
if (j >= *k)
(*k)++;
else
free(*j);
*j = strdup(*a);
if (!*j)
return -ENOMEM;
}
return 0;
}
char **strv_env_merge(unsigned n_lists, ...) {
size_t n = 0;
char **l, **k, **r;
va_list ap;
unsigned i;
va_start(ap, n_lists);
for (i = 0; i < n_lists; i++) {
l = va_arg(ap, char**);
n += strv_length(l);
}
va_end(ap);
r = new(char*, n+1);
if (!r)
return NULL;
k = r;
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;
}
va_end(ap);
*k = NULL;
return r;
fail:
va_end(ap);
strv_free(r);
return NULL;
}
_pure_ static bool env_match(const char *t, const char *pattern) {
assert(t);
assert(pattern);
if (streq(t, pattern))
return true;
if (!strchr(pattern, '=')) {
size_t l = strlen(pattern);
return strneq(t, pattern, l) && t[l] == '=';
}
return false;
}
char **strv_env_delete(char **x, unsigned n_lists, ...) {
size_t n, i = 0;
char **k, **r;
va_list ap;
n = strv_length(x);
r = new(char*, n+1);
if (!r)
return NULL;
STRV_FOREACH(k, x) {
unsigned v;
va_start(ap, n_lists);
for (v = 0; v < n_lists; v++) {
char **l, **j;
l = va_arg(ap, char**);
STRV_FOREACH(j, l)
if (env_match(*k, *j))
goto skip;
}
va_end(ap);
r[i] = strdup(*k);
if (!r[i]) {
strv_free(r);
return NULL;
}
i++;
continue;
skip:
va_end(ap);
}
r[i] = NULL;
assert(i <= n);
return r;
}
char **strv_env_unset(char **l, const char *p) {
char **f, **t;
if (!l)
return NULL;
assert(p);
for (f = t = l; *f; f++) {
if (env_match(*f, p)) {
free(*f);
continue;
}
*(t++) = *f;
}
*t = NULL;
return l;
}
char **strv_env_unset_many(char **l, ...) {
char **f, **t;
if (!l)
return NULL;
for (f = t = l; *f; f++) {
bool found = false;
const char *p;
va_list ap;
va_start(ap, l);
while ((p = va_arg(ap, const char*))) {
if (env_match(*f, p)) {
found = true;
break;
}
}
va_end(ap);
if (found) {
free(*f);
continue;
}
*(t++) = *f;
}
*t = NULL;
return l;
}
char **strv_env_set(char **x, const char *p) {
char **k, **r;
char* m[2] = { (char*) p, NULL };
r = new(char*, strv_length(x)+2);
if (!r)
return NULL;
k = r;
if (env_append(r, &k, x) < 0)
goto fail;
if (env_append(r, &k, m) < 0)
goto fail;
*k = NULL;
return r;
fail:
strv_free(r);
return NULL;
}
char *strv_env_get_n(char **l, const char *name, size_t k) {
char **i;
assert(name);
if (k <= 0)
return NULL;
STRV_FOREACH(i, l)
if (strneq(*i, name, k) &&
(*i)[k] == '=')
return *i + k + 1;
return NULL;
}
char *strv_env_get(char **l, const char *name) {
assert(name);
return strv_env_get_n(l, name, strlen(name));
}
char **strv_env_clean_log(char **e, const char *unit_id, const char *message) {
char **p, **q;
int k = 0;
STRV_FOREACH(p, e) {
size_t n;
bool duplicate = false;
if (!env_assignment_is_valid(*p)) {
if (message)
log_error_unit(unit_id, "Ignoring invalid environment '%s': %s", *p, message);
free(*p);
continue;
}
n = strcspn(*p, "=");
STRV_FOREACH(q, p + 1)
if (strneq(*p, *q, n) && (*q)[n] == '=') {
duplicate = true;
break;
}
if (duplicate) {
free(*p);
continue;
}
e[k++] = *p;
}
if (e)
e[k] = NULL;
return e;
}
char **strv_env_clean(char **e) {
return strv_env_clean_log(e, NULL, NULL);
}