mirror of
https://github.com/systemd/systemd
synced 2024-09-15 22:30:22 +00:00
Merge pull request #20419 from keszybz/setenv-no-value
Allow --setenv=FOO in various programs
This commit is contained in:
commit
a0c5a3f0c0
|
@ -288,12 +288,16 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--setenv=</option><replaceable>VARIABLE</replaceable>=<replaceable>VALUE</replaceable></term>
|
||||
<term><option>--setenv=</option><replaceable>VARIABLE</replaceable>[=<replaceable>VALUE</replaceable>]</term>
|
||||
|
||||
<listitem><para>Takes an environment variable assignment to set for all user processes. Note that a
|
||||
number of other settings also result in environment variables to be set for the user, including
|
||||
<option>--email=</option>, <option>--timezone=</option> and <option>--language=</option>. May be used
|
||||
multiple times to set multiple environment variables.</para></listitem>
|
||||
<listitem><para>Takes an environment variable assignment to set for all user processes. May be used
|
||||
multiple times to set multiple environment variables. When <literal>=</literal> and
|
||||
<replaceable>VALUE</replaceable> are omitted, the value of the variable with the same name in the
|
||||
program environment will be used.</para>
|
||||
|
||||
<para>Note that a number of other settings also result in environment variables to be set for the
|
||||
user, including <option>--email=</option>, <option>--timezone=</option> and
|
||||
<option>--language=</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -712,14 +712,16 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<term><option>-E <replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||
|
||||
<listitem><para>When used with the <command>shell</command> command, sets an environment
|
||||
variable to pass to the executed shell. Takes an environment variable name and value,
|
||||
separated by <literal>=</literal>. This switch may be used multiple times to set multiple
|
||||
environment variables. Note that this switch is not supported for the
|
||||
<command>login</command> command (see below).</para></listitem>
|
||||
<listitem><para>When used with the <command>shell</command> command, sets an environment variable for
|
||||
the executed shell. This option may be used more than once to set multiple variables. When
|
||||
<literal>=</literal> and <replaceable>VALUE</replaceable> are omitted, the value of the variable with
|
||||
the same name in the program environment will be used.</para>
|
||||
|
||||
<para>Note that this option is not supported for the <command>login</command> command.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -527,14 +527,14 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<term><option>-E <replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||
|
||||
<listitem><para>Specifies an environment variable assignment
|
||||
to pass to the init process in the container, in the format
|
||||
<literal>NAME=VALUE</literal>. This may be used to override
|
||||
the default variables or to set additional variables. This
|
||||
parameter may be used more than once.</para></listitem>
|
||||
<listitem><para>Specifies an environment variable to pass to the init process in the container. This
|
||||
may be used to override the default variables or to set additional variables. It may be used more
|
||||
than once to set multiple variables. When <literal>=</literal> and <replaceable>VALUE</replaceable>
|
||||
are omitted, the value of the variable with the same name in the program environment will be used.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -239,11 +239,15 @@
|
|||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<term><option>-E <replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||
<term><option>--setenv=<replaceable>NAME</replaceable>[=<replaceable>VALUE</replaceable>]</option></term>
|
||||
|
||||
<listitem><para>Runs the service process with the specified environment variable set.
|
||||
Also see <varname>Environment=</varname> in
|
||||
<listitem><para>Runs the service process with the specified environment variable set. This parameter
|
||||
may be used more than once to set multiple variables. When <literal>=</literal> and
|
||||
<replaceable>VALUE</replaceable> are omitted, the value of the variable with the same name in the
|
||||
program environment will be used.</para>
|
||||
|
||||
<para>Also see <varname>Environment=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "sd-daemon.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "env-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
|
@ -121,11 +122,9 @@ static int open_sockets(int *epoll_fd, bool accept) {
|
|||
return count;
|
||||
}
|
||||
|
||||
static int exec_process(const char *name, char **argv, char **env, int start_fd, size_t n_fds) {
|
||||
static int exec_process(const char *name, char **argv, int start_fd, size_t n_fds) {
|
||||
_cleanup_strv_free_ char **envp = NULL;
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
size_t n_env = 0, length;
|
||||
const char *tocopy;
|
||||
const char *var;
|
||||
char **s;
|
||||
int r;
|
||||
|
||||
|
@ -133,55 +132,16 @@ static int exec_process(const char *name, char **argv, char **env, int start_fd,
|
|||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--inetd only supported for single file descriptors.");
|
||||
|
||||
length = strv_length(arg_setenv);
|
||||
|
||||
/* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */
|
||||
envp = new0(char *, length + 8);
|
||||
if (!envp)
|
||||
return log_oom();
|
||||
|
||||
STRV_FOREACH(s, arg_setenv) {
|
||||
|
||||
if (strchr(*s, '=')) {
|
||||
char *k;
|
||||
|
||||
k = strdup(*s);
|
||||
if (!k)
|
||||
return log_oom();
|
||||
|
||||
envp[n_env++] = k;
|
||||
} else {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
const char *n;
|
||||
|
||||
p = strjoin(*s, "=");
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
n = strv_find_prefix(env, p);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
envp[n_env] = strdup(n);
|
||||
if (!envp[n_env])
|
||||
return log_oom();
|
||||
|
||||
n_env++;
|
||||
}
|
||||
}
|
||||
|
||||
FOREACH_STRING(tocopy, "TERM=", "PATH=", "USER=", "HOME=") {
|
||||
FOREACH_STRING(var, "TERM", "PATH", "USER", "HOME") {
|
||||
const char *n;
|
||||
|
||||
n = strv_find_prefix(env, tocopy);
|
||||
n = strv_find_prefix(environ, var);
|
||||
if (!n)
|
||||
continue;
|
||||
|
||||
envp[n_env] = strdup(n);
|
||||
if (!envp[n_env])
|
||||
return log_oom();
|
||||
|
||||
n_env++;
|
||||
r = strv_extend(&envp, n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (arg_inetd) {
|
||||
|
@ -201,16 +161,17 @@ static int exec_process(const char *name, char **argv, char **env, int start_fd,
|
|||
safe_close(start_fd);
|
||||
}
|
||||
|
||||
if (asprintf((char **) (envp + n_env++), "LISTEN_FDS=%zu", n_fds) < 0)
|
||||
return log_oom();
|
||||
r = strv_extendf(&envp, "LISTEN_FDS=%zu", n_fds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (asprintf((char **) (envp + n_env++), "LISTEN_PID=" PID_FMT, getpid_cached()) < 0)
|
||||
return log_oom();
|
||||
r = strv_extendf(&envp, "LISTEN_PID=" PID_FMT, getpid_cached());
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_fdnames) {
|
||||
_cleanup_free_ char *names = NULL;
|
||||
size_t len;
|
||||
char *e;
|
||||
|
||||
len = strv_length(arg_fdnames);
|
||||
if (len == 1)
|
||||
|
@ -226,15 +187,23 @@ static int exec_process(const char *name, char **argv, char **env, int start_fd,
|
|||
if (!names)
|
||||
return log_oom();
|
||||
|
||||
e = strjoin("LISTEN_FDNAMES=", names);
|
||||
if (!e)
|
||||
char *t = strjoin("LISTEN_FDNAMES=", names);
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
envp[n_env++] = e;
|
||||
r = strv_consume(&envp, t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
joined = strv_join(argv, " ");
|
||||
STRV_FOREACH(s, arg_setenv) {
|
||||
r = strv_env_replace_strdup(&envp, *s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *joined = strv_join(argv, " ");
|
||||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
|
@ -244,7 +213,7 @@ static int exec_process(const char *name, char **argv, char **env, int start_fd,
|
|||
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, joined);
|
||||
}
|
||||
|
||||
static int fork_and_exec_process(const char *child, char **argv, char **env, int fd) {
|
||||
static int fork_and_exec_process(const char *child, char **argv, int fd) {
|
||||
_cleanup_free_ char *joined = NULL;
|
||||
pid_t child_pid;
|
||||
int r;
|
||||
|
@ -260,7 +229,7 @@ static int fork_and_exec_process(const char *child, char **argv, char **env, int
|
|||
return r;
|
||||
if (r == 0) {
|
||||
/* In the child */
|
||||
exec_process(child, argv, env, fd, 1);
|
||||
exec_process(child, argv, fd, 1);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -268,7 +237,7 @@ static int fork_and_exec_process(const char *child, char **argv, char **env, int
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_accept(const char *name, char **argv, char **envp, int fd) {
|
||||
static int do_accept(const char *name, char **argv, int fd) {
|
||||
_cleanup_free_ char *local = NULL, *peer = NULL;
|
||||
_cleanup_close_ int fd_accepted = -1;
|
||||
|
||||
|
@ -284,7 +253,7 @@ static int do_accept(const char *name, char **argv, char **envp, int fd) {
|
|||
(void) getpeername_pretty(fd_accepted, true, &peer);
|
||||
log_info("Connection from %s to %s", strna(peer), strna(local));
|
||||
|
||||
return fork_and_exec_process(name, argv, envp, fd_accepted);
|
||||
return fork_and_exec_process(name, argv, fd_accepted);
|
||||
}
|
||||
|
||||
/* SIGCHLD handler. */
|
||||
|
@ -414,10 +383,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
break;
|
||||
|
||||
case 'E':
|
||||
r = strv_extend(&arg_setenv, optarg);
|
||||
r = strv_env_replace_strdup_passthrough(&arg_setenv, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
||||
break;
|
||||
|
||||
case ARG_FDNAME: {
|
||||
|
@ -471,7 +439,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return 1 /* work to do */;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
int main(int argc, char **argv) {
|
||||
int r, n;
|
||||
int epoll_fd = -1;
|
||||
|
||||
|
@ -508,14 +476,14 @@ int main(int argc, char **argv, char **envp) {
|
|||
|
||||
log_info("Communication attempt on fd %i.", event.data.fd);
|
||||
if (arg_accept) {
|
||||
r = do_accept(argv[optind], argv + optind, envp, event.data.fd);
|
||||
r = do_accept(argv[optind], argv + optind, event.data.fd);
|
||||
if (r < 0)
|
||||
return EXIT_FAILURE;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START, (size_t) n);
|
||||
exec_process(argv[optind], argv + optind, SD_LISTEN_FDS_START, (size_t) n);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -183,39 +183,51 @@ static int env_append(char **r, char ***k, char **a) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
char **strv_env_merge(size_t n_lists, ...) {
|
||||
_cleanup_strv_free_ char **ret = NULL;
|
||||
size_t n = 0;
|
||||
char **l, **k;
|
||||
char** _strv_env_merge(char **first, ...) {
|
||||
_cleanup_strv_free_ char **merged = NULL;
|
||||
char **k;
|
||||
va_list ap;
|
||||
|
||||
/* Merges an arbitrary number of environment sets */
|
||||
|
||||
va_start(ap, n_lists);
|
||||
for (size_t i = 0; i < n_lists; i++) {
|
||||
size_t n = strv_length(first);
|
||||
|
||||
va_start(ap, first);
|
||||
for (;;) {
|
||||
char **l;
|
||||
|
||||
l = va_arg(ap, char**);
|
||||
if (l == POINTER_MAX)
|
||||
break;
|
||||
|
||||
n += strv_length(l);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
ret = new(char*, n+1);
|
||||
if (!ret)
|
||||
k = merged = new(char*, n + 1);
|
||||
if (!merged)
|
||||
return NULL;
|
||||
merged[0] = NULL;
|
||||
|
||||
if (env_append(merged, &k, first) < 0)
|
||||
return NULL;
|
||||
|
||||
*ret = NULL;
|
||||
k = ret;
|
||||
va_start(ap, first);
|
||||
for (;;) {
|
||||
char **l;
|
||||
|
||||
va_start(ap, n_lists);
|
||||
for (size_t i = 0; i < n_lists; i++) {
|
||||
l = va_arg(ap, char**);
|
||||
if (env_append(ret, &k, l) < 0) {
|
||||
if (l == POINTER_MAX)
|
||||
break;
|
||||
|
||||
if (env_append(merged, &k, l) < 0) {
|
||||
va_end(ap);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return TAKE_PTR(ret);
|
||||
return TAKE_PTR(merged);
|
||||
}
|
||||
|
||||
static bool env_match(const char *t, const char *pattern) {
|
||||
|
@ -409,6 +421,32 @@ int strv_env_replace_strdup(char ***l, const char *assignment) {
|
|||
return strv_env_replace_consume(l, p);
|
||||
}
|
||||
|
||||
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment) {
|
||||
/* Like strv_env_replace_strdup(), but pulls the variable from the environment of
|
||||
* the calling program, if a variable name without value is specified.
|
||||
*/
|
||||
char *p;
|
||||
|
||||
if (strchr(assignment, '=')) {
|
||||
if (!env_assignment_is_valid(assignment))
|
||||
return -EINVAL;
|
||||
|
||||
p = strdup(assignment);
|
||||
} else {
|
||||
if (!env_name_is_valid(assignment))
|
||||
return -EINVAL;
|
||||
|
||||
/* If we can't find the variable in our environment, we will use
|
||||
* the empty string. This way "passthrough" is equivalent to passing
|
||||
* --setenv=FOO=$FOO in the shell. */
|
||||
p = strjoin(assignment, "=", secure_getenv(assignment));
|
||||
}
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_env_replace_consume(l, p);
|
||||
}
|
||||
|
||||
int strv_env_assign(char ***l, const char *key, const char *value) {
|
||||
if (!env_name_is_valid(key))
|
||||
return -EINVAL;
|
||||
|
|
|
@ -39,13 +39,15 @@ char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const cha
|
|||
bool strv_env_name_is_valid(char **l);
|
||||
bool strv_env_name_or_assignment_is_valid(char **l);
|
||||
|
||||
char **strv_env_merge(size_t n_lists, ...);
|
||||
char** _strv_env_merge(char **first, ...);
|
||||
#define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
|
||||
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
|
||||
|
||||
char **strv_env_unset(char **l, const char *p); /* In place ... */
|
||||
char **strv_env_unset_many(char **l, ...) _sentinel_;
|
||||
int strv_env_replace_consume(char ***l, char *p); /* In place ... */
|
||||
int strv_env_replace_strdup(char ***l, const char *assignment);
|
||||
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment);
|
||||
int strv_env_assign(char ***l, const char *key, const char *value);
|
||||
|
||||
char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_;
|
||||
|
|
|
@ -2888,7 +2888,7 @@ int bus_exec_context_set_transient_property(
|
|||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
e = strv_env_merge(2, c->environment, l);
|
||||
e = strv_env_merge(c->environment, l);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -2922,7 +2922,7 @@ int bus_exec_context_set_transient_property(
|
|||
if (!joined)
|
||||
return -ENOMEM;
|
||||
|
||||
e = strv_env_merge(2, c->unset_environment, l);
|
||||
e = strv_env_merge(c->unset_environment, l);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -4158,8 +4158,7 @@ static int exec_child(
|
|||
return log_oom();
|
||||
}
|
||||
|
||||
accum_env = strv_env_merge(5,
|
||||
params->environment,
|
||||
accum_env = strv_env_merge(params->environment,
|
||||
our_env,
|
||||
pass_env,
|
||||
context->environment,
|
||||
|
@ -5214,7 +5213,7 @@ static int exec_context_load_environment(const Unit *unit, const ExecContext *c,
|
|||
else {
|
||||
char **m;
|
||||
|
||||
m = strv_env_merge(2, r, p);
|
||||
m = strv_env_merge(r, p);
|
||||
strv_free(r);
|
||||
strv_free(p);
|
||||
if (!m)
|
||||
|
|
|
@ -85,7 +85,7 @@ int locale_setup(char ***environment) {
|
|||
else {
|
||||
char **merged;
|
||||
|
||||
merged = strv_env_merge(2, *environment, add);
|
||||
merged = strv_env_merge(*environment, add);
|
||||
if (!merged)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -3672,7 +3672,7 @@ int manager_transient_environment_add(Manager *m, char **plus) {
|
|||
if (strv_isempty(plus))
|
||||
return 0;
|
||||
|
||||
a = strv_env_merge(2, m->transient_environment, plus);
|
||||
a = strv_env_merge(m->transient_environment, plus);
|
||||
if (!a)
|
||||
return log_oom();
|
||||
|
||||
|
@ -3704,7 +3704,7 @@ int manager_client_environment_modify(
|
|||
}
|
||||
|
||||
if (!strv_isempty(plus)) {
|
||||
b = strv_env_merge(2, l, plus);
|
||||
b = strv_env_merge(l, plus);
|
||||
if (!b) {
|
||||
strv_free(a);
|
||||
return -ENOMEM;
|
||||
|
@ -3731,7 +3731,7 @@ int manager_get_effective_environment(Manager *m, char ***ret) {
|
|||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
l = strv_env_merge(2, m->transient_environment, m->client_environment);
|
||||
l = strv_env_merge(m->transient_environment, m->client_environment);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -1546,7 +1546,7 @@ static int service_spawn(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
final_env = strv_env_merge(2, exec_params.environment, our_env, NULL);
|
||||
final_env = strv_env_merge(exec_params.environment, our_env);
|
||||
if (!final_env)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -2033,143 +2033,143 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
printf("%1$s [OPTIONS...] COMMAND ...\n\n"
|
||||
"%2$sCreate, manipulate or inspect home directories.%3$s\n"
|
||||
"\n%4$sCommands:%5$s\n"
|
||||
" list List home areas\n"
|
||||
" activate USER… Activate a home area\n"
|
||||
" deactivate USER… Deactivate a home area\n"
|
||||
" inspect USER… Inspect a home area\n"
|
||||
" authenticate USER… Authenticate a home area\n"
|
||||
" create USER Create a home area\n"
|
||||
" remove USER… Remove a home area\n"
|
||||
" update USER Update a home area\n"
|
||||
" passwd USER Change password of a home area\n"
|
||||
" resize USER SIZE Resize a home area\n"
|
||||
" lock USER… Temporarily lock an active home area\n"
|
||||
" unlock USER… Unlock a temporarily locked home area\n"
|
||||
" lock-all Lock all suitable home areas\n"
|
||||
" deactivate-all Deactivate all active home areas\n"
|
||||
" with USER [COMMAND…] Run shell or command with access to a home area\n"
|
||||
" list List home areas\n"
|
||||
" activate USER… Activate a home area\n"
|
||||
" deactivate USER… Deactivate a home area\n"
|
||||
" inspect USER… Inspect a home area\n"
|
||||
" authenticate USER… Authenticate a home area\n"
|
||||
" create USER Create a home area\n"
|
||||
" remove USER… Remove a home area\n"
|
||||
" update USER Update a home area\n"
|
||||
" passwd USER Change password of a home area\n"
|
||||
" resize USER SIZE Resize a home area\n"
|
||||
" lock USER… Temporarily lock an active home area\n"
|
||||
" unlock USER… Unlock a temporarily locked home area\n"
|
||||
" lock-all Lock all suitable home areas\n"
|
||||
" deactivate-all Deactivate all active home areas\n"
|
||||
" with USER [COMMAND…] Run shell or command with access to a home area\n"
|
||||
"\n%4$sOptions:%5$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --no-legend Do not show the headers and footers\n"
|
||||
" --no-ask-password Do not ask for system passwords\n"
|
||||
" -H --host=[USER@]HOST Operate on remote host\n"
|
||||
" -M --machine=CONTAINER Operate on local container\n"
|
||||
" --identity=PATH Read JSON identity from file\n"
|
||||
" --json=FORMAT Output inspection data in JSON (takes one of\n"
|
||||
" pretty, short, off)\n"
|
||||
" -j Equivalent to --json=pretty (on TTY) or\n"
|
||||
" --json=short (otherwise)\n"
|
||||
" --export-format= Strip JSON inspection data (full, stripped,\n"
|
||||
" minimal)\n"
|
||||
" -E When specified once equals -j --export-format=\n"
|
||||
" stripped, when specified twice equals\n"
|
||||
" -j --export-format=minimal\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
" --no-legend Do not show the headers and footers\n"
|
||||
" --no-ask-password Do not ask for system passwords\n"
|
||||
" -H --host=[USER@]HOST Operate on remote host\n"
|
||||
" -M --machine=CONTAINER Operate on local container\n"
|
||||
" --identity=PATH Read JSON identity from file\n"
|
||||
" --json=FORMAT Output inspection data in JSON (takes one of\n"
|
||||
" pretty, short, off)\n"
|
||||
" -j Equivalent to --json=pretty (on TTY) or\n"
|
||||
" --json=short (otherwise)\n"
|
||||
" --export-format= Strip JSON inspection data (full, stripped,\n"
|
||||
" minimal)\n"
|
||||
" -E When specified once equals -j --export-format=\n"
|
||||
" stripped, when specified twice equals\n"
|
||||
" -j --export-format=minimal\n"
|
||||
"\n%4$sGeneral User Record Properties:%5$s\n"
|
||||
" -c --real-name=REALNAME Real name for user\n"
|
||||
" --realm=REALM Realm to create user in\n"
|
||||
" --email-address=EMAIL Email address for user\n"
|
||||
" --location=LOCATION Set location of user on earth\n"
|
||||
" --icon-name=NAME Icon name for user\n"
|
||||
" -d --home-dir=PATH Home directory\n"
|
||||
" -u --uid=UID Numeric UID for user\n"
|
||||
" -G --member-of=GROUP Add user to group\n"
|
||||
" --skel=PATH Skeleton directory to use\n"
|
||||
" --shell=PATH Shell for account\n"
|
||||
" --setenv=VARIABLE=VALUE Set an environment variable at log-in\n"
|
||||
" --timezone=TIMEZONE Set a time-zone\n"
|
||||
" --language=LOCALE Set preferred language\n"
|
||||
" -c --real-name=REALNAME Real name for user\n"
|
||||
" --realm=REALM Realm to create user in\n"
|
||||
" --email-address=EMAIL Email address for user\n"
|
||||
" --location=LOCATION Set location of user on earth\n"
|
||||
" --icon-name=NAME Icon name for user\n"
|
||||
" -d --home-dir=PATH Home directory\n"
|
||||
" -u --uid=UID Numeric UID for user\n"
|
||||
" -G --member-of=GROUP Add user to group\n"
|
||||
" --skel=PATH Skeleton directory to use\n"
|
||||
" --shell=PATH Shell for account\n"
|
||||
" --setenv=VARIABLE[=VALUE] Set an environment variable at log-in\n"
|
||||
" --timezone=TIMEZONE Set a time-zone\n"
|
||||
" --language=LOCALE Set preferred language\n"
|
||||
" --ssh-authorized-keys=KEYS\n"
|
||||
" Specify SSH public keys\n"
|
||||
" --pkcs11-token-uri=URI URI to PKCS#11 security token containing\n"
|
||||
" private key and matching X.509 certificate\n"
|
||||
" --fido2-device=PATH Path to FIDO2 hidraw device with hmac-secret\n"
|
||||
" extension\n"
|
||||
" Specify SSH public keys\n"
|
||||
" --pkcs11-token-uri=URI URI to PKCS#11 security token containing\n"
|
||||
" private key and matching X.509 certificate\n"
|
||||
" --fido2-device=PATH Path to FIDO2 hidraw device with hmac-secret\n"
|
||||
" extension\n"
|
||||
" --fido2-with-client-pin=BOOL\n"
|
||||
" Whether to require entering a PIN to unlock the\n"
|
||||
" account\n"
|
||||
" Whether to require entering a PIN to unlock the\n"
|
||||
" account\n"
|
||||
" --fido2-with-user-presence=BOOL\n"
|
||||
" Whether to require user presence to unlock the\n"
|
||||
" account\n"
|
||||
" Whether to require user presence to unlock the\n"
|
||||
" account\n"
|
||||
" --fido2-with-user-verification=BOOL\n"
|
||||
" Whether to require user verification to unlock the\n"
|
||||
" account\n"
|
||||
" --recovery-key=BOOL Add a recovery key\n"
|
||||
"\n%4$sAccount Management User Record Properties:%5$s\n"
|
||||
" --locked=BOOL Set locked account state\n"
|
||||
" --not-before=TIMESTAMP Do not allow logins before\n"
|
||||
" --not-after=TIMESTAMP Do not allow logins after\n"
|
||||
" Whether to require user verification to unlock\n"
|
||||
" the account\n"
|
||||
" --recovery-key=BOOL Add a recovery key\n"
|
||||
"\n%4$sAccount Management User Record Properties:%5$s\n"
|
||||
" --locked=BOOL Set locked account state\n"
|
||||
" --not-before=TIMESTAMP Do not allow logins before\n"
|
||||
" --not-after=TIMESTAMP Do not allow logins after\n"
|
||||
" --rate-limit-interval=SECS\n"
|
||||
" Login rate-limit interval in seconds\n"
|
||||
" Login rate-limit interval in seconds\n"
|
||||
" --rate-limit-burst=NUMBER\n"
|
||||
" Login rate-limit attempts per interval\n"
|
||||
" Login rate-limit attempts per interval\n"
|
||||
"\n%4$sPassword Policy User Record Properties:%5$s\n"
|
||||
" --password-hint=HINT Set Password hint\n"
|
||||
" --password-hint=HINT Set Password hint\n"
|
||||
" --enforce-password-policy=BOOL\n"
|
||||
" Control whether to enforce system's password\n"
|
||||
" policy for this user\n"
|
||||
" -P Equivalent to --enforce-password-password=no\n"
|
||||
" Control whether to enforce system's password\n"
|
||||
" policy for this user\n"
|
||||
" -P Same as --enforce-password-password=no\n"
|
||||
" --password-change-now=BOOL\n"
|
||||
" Require the password to be changed on next login\n"
|
||||
" Require the password to be changed on next login\n"
|
||||
" --password-change-min=TIME\n"
|
||||
" Require minimum time between password changes\n"
|
||||
" Require minimum time between password changes\n"
|
||||
" --password-change-max=TIME\n"
|
||||
" Require maximum time between password changes\n"
|
||||
" Require maximum time between password changes\n"
|
||||
" --password-change-warn=TIME\n"
|
||||
" How much time to warn before password expiry\n"
|
||||
" How much time to warn before password expiry\n"
|
||||
" --password-change-inactive=TIME\n"
|
||||
" How much time to block password after expiry\n"
|
||||
" How much time to block password after expiry\n"
|
||||
"\n%4$sResource Management User Record Properties:%5$s\n"
|
||||
" --disk-size=BYTES Size to assign the user on disk\n"
|
||||
" --access-mode=MODE User home directory access mode\n"
|
||||
" --umask=MODE Umask for user when logging in\n"
|
||||
" --nice=NICE Nice level for user\n"
|
||||
" --disk-size=BYTES Size to assign the user on disk\n"
|
||||
" --access-mode=MODE User home directory access mode\n"
|
||||
" --umask=MODE Umask for user when logging in\n"
|
||||
" --nice=NICE Nice level for user\n"
|
||||
" --rlimit=LIMIT=VALUE[:VALUE]\n"
|
||||
" Set resource limits\n"
|
||||
" --tasks-max=MAX Set maximum number of per-user tasks\n"
|
||||
" --memory-high=BYTES Set high memory threshold in bytes\n"
|
||||
" --memory-max=BYTES Set maximum memory limit\n"
|
||||
" --cpu-weight=WEIGHT Set CPU weight\n"
|
||||
" --io-weight=WEIGHT Set IO weight\n"
|
||||
" Set resource limits\n"
|
||||
" --tasks-max=MAX Set maximum number of per-user tasks\n"
|
||||
" --memory-high=BYTES Set high memory threshold in bytes\n"
|
||||
" --memory-max=BYTES Set maximum memory limit\n"
|
||||
" --cpu-weight=WEIGHT Set CPU weight\n"
|
||||
" --io-weight=WEIGHT Set IO weight\n"
|
||||
"\n%4$sStorage User Record Properties:%5$s\n"
|
||||
" --storage=STORAGE Storage type to use (luks, fscrypt, directory,\n"
|
||||
" subvolume, cifs)\n"
|
||||
" --image-path=PATH Path to image file/directory\n"
|
||||
" --storage=STORAGE Storage type to use (luks, fscrypt, directory,\n"
|
||||
" subvolume, cifs)\n"
|
||||
" --image-path=PATH Path to image file/directory\n"
|
||||
"\n%4$sLUKS Storage User Record Properties:%5$s\n"
|
||||
" --fs-type=TYPE File system type to use in case of luks\n"
|
||||
" storage (btrfs, ext4, xfs)\n"
|
||||
" --luks-discard=BOOL Whether to use 'discard' feature of file system\n"
|
||||
" when activated (mounted)\n"
|
||||
" --fs-type=TYPE File system type to use in case of luks\n"
|
||||
" storage (btrfs, ext4, xfs)\n"
|
||||
" --luks-discard=BOOL Whether to use 'discard' feature of file system\n"
|
||||
" when activated (mounted)\n"
|
||||
" --luks-offline-discard=BOOL\n"
|
||||
" Whether to trim file on logout\n"
|
||||
" --luks-cipher=CIPHER Cipher to use for LUKS encryption\n"
|
||||
" --luks-cipher-mode=MODE Cipher mode to use for LUKS encryption\n"
|
||||
" Whether to trim file on logout\n"
|
||||
" --luks-cipher=CIPHER Cipher to use for LUKS encryption\n"
|
||||
" --luks-cipher-mode=MODE Cipher mode to use for LUKS encryption\n"
|
||||
" --luks-volume-key-size=BITS\n"
|
||||
" Volume key size to use for LUKS encryption\n"
|
||||
" --luks-pbkdf-type=TYPE Password-based Key Derivation Function to use\n"
|
||||
" Volume key size to use for LUKS encryption\n"
|
||||
" --luks-pbkdf-type=TYPE Password-based Key Derivation Function to use\n"
|
||||
" --luks-pbkdf-hash-algorithm=ALGORITHM\n"
|
||||
" PBKDF hash algorithm to use\n"
|
||||
" PBKDF hash algorithm to use\n"
|
||||
" --luks-pbkdf-time-cost=SECS\n"
|
||||
" Time cost for PBKDF in seconds\n"
|
||||
" Time cost for PBKDF in seconds\n"
|
||||
" --luks-pbkdf-memory-cost=BYTES\n"
|
||||
" Memory cost for PBKDF in bytes\n"
|
||||
" Memory cost for PBKDF in bytes\n"
|
||||
" --luks-pbkdf-parallel-threads=NUMBER\n"
|
||||
" Number of parallel threads for PKBDF\n"
|
||||
" Number of parallel threads for PKBDF\n"
|
||||
"\n%4$sMounting User Record Properties:%5$s\n"
|
||||
" --nosuid=BOOL Control the 'nosuid' flag of the home mount\n"
|
||||
" --nodev=BOOL Control the 'nodev' flag of the home mount\n"
|
||||
" --noexec=BOOL Control the 'noexec' flag of the home mount\n"
|
||||
" --nosuid=BOOL Control the 'nosuid' flag of the home mount\n"
|
||||
" --nodev=BOOL Control the 'nodev' flag of the home mount\n"
|
||||
" --noexec=BOOL Control the 'noexec' flag of the home mount\n"
|
||||
"\n%4$sCIFS User Record Properties:%5$s\n"
|
||||
" --cifs-domain=DOMAIN CIFS (Windows) domain\n"
|
||||
" --cifs-user-name=USER CIFS (Windows) user name\n"
|
||||
" --cifs-service=SERVICE CIFS (Windows) service to mount as home area\n"
|
||||
" --cifs-domain=DOMAIN CIFS (Windows) domain\n"
|
||||
" --cifs-user-name=USER CIFS (Windows) user name\n"
|
||||
" --cifs-service=SERVICE CIFS (Windows) service to mount as home area\n"
|
||||
"\n%4$sLogin Behaviour User Record Properties:%5$s\n"
|
||||
" --stop-delay=SECS How long to leave user services running after\n"
|
||||
" logout\n"
|
||||
" --kill-processes=BOOL Whether to kill user processes when sessions\n"
|
||||
" terminate\n"
|
||||
" --auto-login=BOOL Try to log this user in automatically\n"
|
||||
" --stop-delay=SECS How long to leave user services running after\n"
|
||||
" logout\n"
|
||||
" --kill-processes=BOOL Whether to kill user processes when sessions\n"
|
||||
" terminate\n"
|
||||
" --auto-login=BOOL Try to log this user in automatically\n"
|
||||
"\nSee the %6$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
|
@ -2673,10 +2673,6 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (!env_assignment_is_valid(optarg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Environment assignment '%s' not valid.", optarg);
|
||||
|
||||
e = json_variant_by_key(arg_identity_extra, "environment");
|
||||
if (e) {
|
||||
r = json_variant_strv(e, &l);
|
||||
|
@ -2684,9 +2680,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return log_error_errno(r, "Failed to parse JSON environment field: %m");
|
||||
}
|
||||
|
||||
r = strv_env_replace_strdup(&l, optarg);
|
||||
r = strv_env_replace_strdup_passthrough(&l, optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to replace JSON environment field: %m");
|
||||
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
||||
|
||||
strv_sort(l);
|
||||
|
||||
|
|
|
@ -2510,7 +2510,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" --kill-who=WHO Who to send signal to\n"
|
||||
" -s --signal=SIGNAL Which signal to send\n"
|
||||
" --uid=USER Specify user ID to invoke shell as\n"
|
||||
" -E --setenv=VAR=VALUE Add an environment variable for shell\n"
|
||||
" -E --setenv=VAR[=VALUE] Add an environment variable for shell\n"
|
||||
" --read-only Create read-only bind mount\n"
|
||||
" --mkdir Create directory before bind mounting, if missing\n"
|
||||
" -n --lines=INTEGER Number of journal entries to show\n"
|
||||
|
@ -2765,13 +2765,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
break;
|
||||
|
||||
case 'E':
|
||||
if (!env_assignment_is_valid(optarg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Environment assignment invalid: %s", optarg);
|
||||
|
||||
r = strv_extend(&arg_setenv, optarg);
|
||||
r = strv_env_replace_strdup_passthrough(&arg_setenv, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
||||
break;
|
||||
|
||||
case ARG_MAX_ADDRESSES:
|
||||
|
|
|
@ -232,7 +232,7 @@ static int run(int argc, char* argv[]) {
|
|||
|
||||
our_env[i++] = NULL;
|
||||
|
||||
final_env = strv_env_merge(2, our_env, argv + optind);
|
||||
final_env = strv_env_merge(our_env, argv + optind);
|
||||
if (!final_env)
|
||||
return log_oom();
|
||||
|
||||
|
|
|
@ -338,7 +338,7 @@ static int help(void) {
|
|||
" -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n"
|
||||
" -b --boot Boot up full system (i.e. invoke init)\n"
|
||||
" --chdir=PATH Set working directory in the container\n"
|
||||
" -E --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
|
||||
" -E --setenv=NAME[=VALUE] Pass an environment variable to PID 1\n"
|
||||
" -u --user=USER Run the command under specified user or UID\n"
|
||||
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
|
||||
" --notify-ready=BOOLEAN Receive notifications from the child init process\n\n"
|
||||
|
@ -1121,17 +1121,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
arg_settings_mask |= SETTING_CUSTOM_MOUNTS;
|
||||
break;
|
||||
|
||||
case 'E': {
|
||||
if (!env_assignment_is_valid(optarg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Environment variable assignment '%s' is not valid.", optarg);
|
||||
r = strv_env_replace_strdup(&arg_setenv, optarg);
|
||||
case 'E':
|
||||
r = strv_env_replace_strdup_passthrough(&arg_setenv, optarg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
||||
|
||||
arg_settings_mask |= SETTING_ENVIRONMENT;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'q':
|
||||
arg_quiet = true;
|
||||
|
@ -3189,8 +3185,8 @@ static int inner_child(
|
|||
_cleanup_free_ char *home = NULL;
|
||||
char as_uuid[ID128_UUID_STRING_MAX];
|
||||
size_t n_env = 1;
|
||||
const char *envp[] = {
|
||||
"PATH=" DEFAULT_PATH_COMPAT,
|
||||
char *envp[] = {
|
||||
(char*) "PATH=" DEFAULT_PATH_COMPAT,
|
||||
NULL, /* container */
|
||||
NULL, /* TERM */
|
||||
NULL, /* HOME */
|
||||
|
@ -3426,17 +3422,17 @@ static int inner_child(
|
|||
n_env++;
|
||||
|
||||
if (home || !uid_is_valid(arg_uid) || arg_uid == 0)
|
||||
if (asprintf((char**)(envp + n_env++), "HOME=%s", home ?: "/root") < 0)
|
||||
if (asprintf(envp + n_env++, "HOME=%s", home ?: "/root") < 0)
|
||||
return log_oom();
|
||||
|
||||
if (arg_user || !uid_is_valid(arg_uid) || arg_uid == 0)
|
||||
if (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ?: "root") < 0 ||
|
||||
asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)
|
||||
if (asprintf(envp + n_env++, "USER=%s", arg_user ?: "root") < 0 ||
|
||||
asprintf(envp + n_env++, "LOGNAME=%s", arg_user ? arg_user : "root") < 0)
|
||||
return log_oom();
|
||||
|
||||
assert(!sd_id128_is_null(arg_uuid));
|
||||
|
||||
if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_to_uuid_string(arg_uuid, as_uuid)) < 0)
|
||||
if (asprintf(envp + n_env++, "container_uuid=%s", id128_to_uuid_string(arg_uuid, as_uuid)) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (fdset_size(fds) > 0) {
|
||||
|
@ -3444,11 +3440,11 @@ static int inner_child(
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to unset O_CLOEXEC for file descriptors.");
|
||||
|
||||
if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", fdset_size(fds)) < 0) ||
|
||||
(asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0))
|
||||
if ((asprintf(envp + n_env++, "LISTEN_FDS=%u", fdset_size(fds)) < 0) ||
|
||||
(asprintf(envp + n_env++, "LISTEN_PID=1") < 0))
|
||||
return log_oom();
|
||||
}
|
||||
if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0)
|
||||
if (asprintf(envp + n_env++, "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (arg_n_credentials > 0) {
|
||||
|
@ -3458,7 +3454,7 @@ static int inner_child(
|
|||
n_env++;
|
||||
}
|
||||
|
||||
env_use = strv_env_merge(3, envp, os_release_pairs, arg_setenv);
|
||||
env_use = strv_env_merge(envp, os_release_pairs, arg_setenv);
|
||||
if (!env_use)
|
||||
return log_oom();
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ static int help(void) {
|
|||
" --nice=NICE Nice level\n"
|
||||
" --working-directory=PATH Set working directory\n"
|
||||
" -d --same-dir Inherit working directory from caller\n"
|
||||
" -E --setenv=NAME=VALUE Set environment\n"
|
||||
" -E --setenv=NAME[=VALUE] Set environment variable\n"
|
||||
" -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
|
||||
" STDERR\n"
|
||||
" -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
|
||||
|
@ -322,8 +322,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
break;
|
||||
|
||||
case 'E':
|
||||
if (strv_extend(&arg_environment, optarg) < 0)
|
||||
return log_oom();
|
||||
r = strv_env_replace_strdup_passthrough(&arg_environment, optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -1526,7 +1527,7 @@ static int start_transient_scope(sd_bus *bus) {
|
|||
return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid);
|
||||
}
|
||||
|
||||
env = strv_env_merge(3, environ, user_env, arg_environment);
|
||||
env = strv_env_merge(environ, user_env, arg_environment);
|
||||
if (!env)
|
||||
return log_oom();
|
||||
|
||||
|
|
|
@ -73,31 +73,28 @@ static void test_strv_env_unset(void) {
|
|||
static void test_strv_env_merge(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
_cleanup_strv_free_ char **a = NULL, **b = NULL, **r = NULL;
|
||||
char **a = STRV_MAKE("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF", "EQ===");
|
||||
char **b = STRV_MAKE("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES");
|
||||
|
||||
a = strv_new("FOO=BAR", "WALDO=WALDO", "WALDO=", "PIEP", "SCHLUMPF=SMURF");
|
||||
assert_se(a);
|
||||
|
||||
b = strv_new("FOO=KKK", "FOO=", "PIEP=", "SCHLUMPF=SMURFF", "NANANANA=YES");
|
||||
assert_se(b);
|
||||
|
||||
r = strv_env_merge(2, a, b);
|
||||
_cleanup_strv_free_ char **r = strv_env_merge(NULL, a, NULL, b, NULL, a, b, b, NULL);
|
||||
assert_se(r);
|
||||
assert_se(streq(r[0], "FOO="));
|
||||
assert_se(streq(r[1], "WALDO="));
|
||||
assert_se(streq(r[2], "PIEP"));
|
||||
assert_se(streq(r[3], "SCHLUMPF=SMURFF"));
|
||||
assert_se(streq(r[4], "PIEP="));
|
||||
assert_se(streq(r[5], "NANANANA=YES"));
|
||||
assert_se(strv_length(r) == 6);
|
||||
assert_se(streq(r[4], "EQ==="));
|
||||
assert_se(streq(r[5], "PIEP="));
|
||||
assert_se(streq(r[6], "NANANANA=YES"));
|
||||
assert_se(strv_length(r) == 7);
|
||||
|
||||
assert_se(strv_env_clean(r) == r);
|
||||
assert_se(streq(r[0], "FOO="));
|
||||
assert_se(streq(r[1], "WALDO="));
|
||||
assert_se(streq(r[2], "SCHLUMPF=SMURFF"));
|
||||
assert_se(streq(r[3], "PIEP="));
|
||||
assert_se(streq(r[4], "NANANANA=YES"));
|
||||
assert_se(strv_length(r) == 5);
|
||||
assert_se(streq(r[3], "EQ==="));
|
||||
assert_se(streq(r[4], "PIEP="));
|
||||
assert_se(streq(r[5], "NANANANA=YES"));
|
||||
assert_se(strv_length(r) == 6);
|
||||
}
|
||||
|
||||
static void test_strv_env_replace_strdup(void) {
|
||||
|
@ -108,6 +105,7 @@ static void test_strv_env_replace_strdup(void) {
|
|||
assert_se(strv_env_replace_strdup(&a, "a=a") == 1);
|
||||
assert_se(strv_env_replace_strdup(&a, "b=b") == 1);
|
||||
assert_se(strv_env_replace_strdup(&a, "a=A") == 0);
|
||||
assert_se(strv_env_replace_strdup(&a, "c") == -EINVAL);
|
||||
|
||||
assert_se(strv_length(a) == 2);
|
||||
strv_sort(a);
|
||||
|
@ -115,6 +113,27 @@ static void test_strv_env_replace_strdup(void) {
|
|||
assert_se(streq(a[1], "b=b"));
|
||||
}
|
||||
|
||||
static void test_strv_env_replace_strdup_passthrough(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
_cleanup_strv_free_ char **a = NULL;
|
||||
|
||||
assert_se(putenv((char*) "a=a") == 0);
|
||||
assert_se(putenv((char*) "b=") == 0);
|
||||
assert_se(unsetenv("c") == 0);
|
||||
|
||||
assert_se(strv_env_replace_strdup_passthrough(&a, "a") == 1);
|
||||
assert_se(strv_env_replace_strdup_passthrough(&a, "b") == 1);
|
||||
assert_se(strv_env_replace_strdup_passthrough(&a, "c") == 1);
|
||||
assert_se(strv_env_replace_strdup_passthrough(&a, "a") == 0);
|
||||
assert_se(strv_env_replace_strdup_passthrough(&a, "$a") == -EINVAL);
|
||||
|
||||
assert_se(strv_length(a) == 3);
|
||||
assert_se(streq(a[0], "a=a"));
|
||||
assert_se(streq(a[1], "b="));
|
||||
assert_se(streq(a[2], "c="));
|
||||
}
|
||||
|
||||
static void test_strv_env_assign(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
|
@ -418,6 +437,7 @@ int main(int argc, char *argv[]) {
|
|||
test_strv_env_unset();
|
||||
test_strv_env_merge();
|
||||
test_strv_env_replace_strdup();
|
||||
test_strv_env_replace_strdup_passthrough();
|
||||
test_strv_env_assign();
|
||||
test_env_strv_get_n();
|
||||
test_replace_env(false);
|
||||
|
|
Loading…
Reference in a new issue