execute.c revision 351a19b17d51ba0a5737f35d3c5deb8e7975fdee
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync This file is part of systemd.
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync Copyright 2010 Lennart Poettering
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync systemd is free software; you can redistribute it and/or modify it
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync under the terms of the GNU Lesser General Public License as published by
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync the Free Software Foundation; either version 2.1 of the License, or
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync (at your option) any later version.
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync systemd is distributed in the hope that it will be useful, but
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync WITHOUT ANY WARRANTY; without even the implied warranty of
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync Lesser General Public License for more details.
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync You should have received a copy of the GNU Lesser General Public License
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync along with systemd; If not, see <http://www.gnu.org/licenses/>.
d604c03c7ae485c94bccd5629e96f5c10da81467vboxsync/* This assumes there is a 'tty' group */
if (n_fds <= 0)
start = 0;
int nfd;
return -errno;
restart_from = i;
if (restart_from < 0)
if (n_fds <= 0)
for (i = 0; i < n_fds; i++) {
o == EXEC_OUTPUT_TTY ||
o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
o == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
int fd, r;
if (fd < 0)
return -errno;
r = nfd;
static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
int fd, r;
assert(ident);
if (fd < 0)
return -errno;
return -errno;
return -errno;
r = nfd;
int fd, r;
return fd;
r = nfd;
i == EXEC_INPUT_TTY ||
i == EXEC_INPUT_TTY_FORCE ||
i == EXEC_INPUT_TTY_FAIL;
return EXEC_INPUT_NULL;
return EXEC_INPUT_NULL;
return std_input;
return EXEC_OUTPUT_INHERIT;
return std_output;
ExecInput i;
case EXEC_INPUT_NULL:
case EXEC_INPUT_TTY:
case EXEC_INPUT_TTY_FORCE:
case EXEC_INPUT_TTY_FAIL: {
int fd, r;
i == EXEC_INPUT_TTY_FAIL,
i == EXEC_INPUT_TTY_FORCE,
if (fd < 0)
return fd;
r = STDIN_FILENO;
case EXEC_INPUT_SOCKET:
static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
ExecOutput o;
ExecInput i;
assert(ident);
ExecOutput e;
if (e == EXEC_OUTPUT_INHERIT &&
o == EXEC_OUTPUT_INHERIT &&
i == EXEC_INPUT_NULL &&
return fileno;
if (e == o || e == EXEC_OUTPUT_INHERIT)
} else if (o == EXEC_OUTPUT_INHERIT) {
if (i != EXEC_INPUT_NULL)
return fileno;
case EXEC_OUTPUT_NULL:
case EXEC_OUTPUT_TTY:
if (is_terminal_input(i))
case EXEC_OUTPUT_SYSLOG:
case EXEC_OUTPUT_KMSG:
case EXEC_OUTPUT_JOURNAL:
NULL);
case EXEC_OUTPUT_SOCKET:
return -errno;
return -EPERM;
int *_saved_stdout) {
if (saved_stdin < 0)
return -errno;
if (saved_stdout < 0) {
r = errno;
goto fail;
if (fd < 0) {
r = fd;
goto fail;
goto fail;
r = -errno;
goto fail;
r = -errno;
goto fail;
fail:
if (saved_stdout >= 0)
if (saved_stdin >= 0)
if (fd >= 0)
int fd;
if (fd < 0)
return fd;
int *saved_stdout) {
if (*saved_stdin >= 0)
r = -errno;
if (*saved_stdout >= 0)
r = -errno;
if (*saved_stdin >= 0)
if (*saved_stdout >= 0)
char *line;
if (!line)
return -ENOMEM;
bool keep_groups = false;
return -errno;
keep_groups = true;
return -errno;
int ngroups_max, k;
return -ENOMEM;
if (keep_groups) {
return -errno;
if (k >= ngroups_max) {
return -E2BIG;
return -errno;
if (uid != 0) {
return -errno;
return -errno;
return -errno;
if (cap_set_proc(d) < 0)
return -errno;
return -errno;
#ifdef HAVE_PAM
static int null_conv(
int num_msg,
void *appdata_ptr) {
return PAM_CONV_ERR;
static int setup_pam(
const char *name,
const char *user,
const char *tty,
char ***pam_env,
int err;
char **e = NULL;
bool close_session = false;
int flags = 0;
goto fail;
if (tty) {
goto fail;
goto fail;
goto fail;
close_session = true;
goto fail;
goto fail;
if (pam_pid < 0)
goto fail;
if (pam_pid == 0) {
int sig;
int r = EXIT_PAM;
goto child_finish;
goto child_finish;
goto child_finish;
_exit(r);
goto fail;
closelog();
*pam_env = e;
e = NULL;
fail:
if (handle) {
if (close_session)
strv_free(e);
closelog();
return err;
size_t l;
if (isempty(p)) {
l = strlen(p);
#ifdef HAVE_SECCOMP
Iterator i;
void *id;
assert(c);
if (!seccomp)
return -ENOMEM;
if (idle_pipe[0] >= 0) {
static int build_environment(
ExecContext *c,
unsigned n_fds,
const char *home,
const char *username,
const char *shell,
char ***ret) {
unsigned n_env = 0;
assert(c);
if (!our_env)
return -ENOMEM;
if (n_fds > 0) {
return -ENOMEM;
return -ENOMEM;
if (watchdog_usec > 0) {
return -ENOMEM;
return -ENOMEM;
if (home) {
return -ENOMEM;
if (username) {
return -ENOMEM;
return -ENOMEM;
if (shell) {
return -ENOMEM;
c->tty_path) {
return -ENOMEM;
char **argv,
char **environment,
bool apply_permissions,
bool apply_chroot,
bool apply_tty_stdin,
bool confirm_spawn,
const char *cgroup_path,
const char *unit_id,
int socket_fd;
char *line;
return -EINVAL;
n_fds = 0;
NULL);
if (!argv)
if (!line)
return log_oom();
NULL);
if (pid < 0)
return -errno;
if (pid == 0) {
_cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
unsigned n_dont_close = 0;
int i, err;
r = EXIT_SIGNAL_MASK;
goto fail_child;
if (idle_pipe)
if (socket_fd >= 0)
if (n_fds > 0) {
if (runtime) {
if (err < 0) {
r = EXIT_FDS;
goto fail_child;
if (setsid() < 0) {
r = EXIT_SETSID;
goto fail_child;
if (socket_fd >= 0)
r = EXIT_TCPWRAP;
goto fail_child;
for (i = 0; i < (int) n_fds; i++) {
r = EXIT_TCPWRAP;
goto fail_child;
if (confirm_spawn) {
char response;
else if (err < 0)
write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err));
r = EXIT_CONFIRM;
goto fail_child;
err = r = 0;
goto fail_child;
if (socket_fd >= 0)
if (err < 0) {
r = EXIT_STDIN;
goto fail_child;
err = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin);
if (err < 0) {
r = EXIT_STDOUT;
goto fail_child;
err = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), unit_id, apply_tty_stdin);
if (err < 0) {
r = EXIT_STDERR;
goto fail_child;
if (cgroup_path) {
if (err < 0) {
r = EXIT_CGROUP;
goto fail_child;
char_array_0(t);
r = EXIT_OOM_ADJUST;
goto fail_child;
r = EXIT_NICE;
goto fail_child;
r = sched_setscheduler(0,
SCHED_RESET_ON_FORK : 0),
¶m);
r = EXIT_SETSCHEDULER;
goto fail_child;
r = EXIT_CPUAFFINITY;
goto fail_child;
r = EXIT_IOPRIO;
goto fail_child;
r = EXIT_TIMERSLACK;
goto fail_child;
if (err < 0) {
r = EXIT_USER;
goto fail_child;
if (err < 0) {
r = EXIT_STDIN;
goto fail_child;
#ifdef HAVE_PAM
if (err < 0) {
r = EXIT_CGROUP;
goto fail_child;
if (err < 0) {
r = EXIT_CGROUP;
goto fail_child;
if (apply_permissions) {
if (err < 0) {
r = EXIT_GROUP;
goto fail_child;
#ifdef HAVE_PAM
if (err < 0) {
r = EXIT_PAM;
goto fail_child;
if (err < 0) {
r = EXIT_NETWORK;
goto fail_child;
tmp,
var,
if (err < 0) {
r = EXIT_NAMESPACE;
goto fail_child;
if (apply_chroot) {
r = EXIT_CHROOT;
goto fail_child;
r = EXIT_CHDIR;
goto fail_child;
r = EXIT_MEMORY;
goto fail_child;
if (chdir(d) < 0) {
r = EXIT_CHDIR;
goto fail_child;
if (err >= 0)
if (err >= 0)
if (err < 0) {
r = EXIT_FDS;
goto fail_child;
if (apply_permissions) {
for (i = 0; i < RLIMIT_NLIMITS; i++) {
r = EXIT_LIMITS;
goto fail_child;
if (err < 0) {
r = EXIT_CAPABILITIES;
goto fail_child;
if (err < 0) {
r = EXIT_USER;
goto fail_child;
r = EXIT_SECUREBITS;
goto fail_child;
r = EXIT_CAPABILITIES;
goto fail_child;
goto fail_child;
#ifdef HAVE_SECCOMP
if (err < 0) {
r = EXIT_SECCOMP;
goto fail_child;
#ifdef HAVE_SELINUX
bool ignore;
ignore = true;
ignore = false;
r = EXIT_SELINUX_CONTEXT;
goto fail_child;
r = EXIT_MEMORY;
goto fail_child;
NULL);
if (!final_env) {
r = EXIT_MEMORY;
goto fail_child;
if (!final_argv) {
r = EXIT_MEMORY;
goto fail_child;
if (line) {
log_open();
NULL);
log_close();
r = EXIT_EXEC;
log_open();
NULL);
log_close();
_exit(r);
NULL);
if (cgroup_path)
assert(c);
c->syslog_level_prefix = true;
c->ignore_sigpipe = true;
assert(c);
if (c->capabilities) {
if (c->cpuset)
#ifdef HAVE_SECCOMP
assert(c);
exec_command_done(c+i);
ExecCommand *i;
free(i);
exec_command_free_list(c[i]);
c[i] = NULL;
char **i, **r = NULL;
assert(c);
assert(l);
char *fn;
bool ignore = false;
int count, n;
fn = *i;
ignore = true;
fn ++;
if (ignore)
strv_free(r);
return -EINVAL;
errno = 0;
if (ignore)
strv_free(r);
if (count == 0) {
if (ignore)
strv_free(r);
return -EINVAL;
for (n = 0; n < count; n++) {
if (ignore)
strv_free(r);
if (r == NULL)
strv_free(r);
strv_free(p);
return -ENOMEM;
if (!console)
assert(f);
STRV_FOREACH(g, l)
assert(c);
assert(f);
fprintf(f,
if (c->tcpwrap_name)
fprintf(f,
if (c->nice_set)
fprintf(f,
if (c->oom_score_adjust_set)
fprintf(f,
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i])
fprintf(f, "%s%s: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
if (c->ioprio_set) {
char *class_str;
fprintf(f,
if (c->cpu_sched_set) {
char *policy_str;
fprintf(f,
if (c->cpuset) {
for (i = 0; i < c->cpuset_ncpus; i++)
fprintf(f,
if (c->tty_path)
fprintf(f,
fprintf(f,
if (c->capabilities) {
_cleanup_cap_free_charp_ char *t;
if (c->secure_bits)
if (c->capability_bounding_set_drop) {
for (l = 0; l <= cap_last_cap(); l++)
_cleanup_cap_free_charp_ char *t;
t = cap_to_name(l);
if (c->user)
if (c->group)
if (c->pam_name)
if (c->utmp_id)
fprintf(f,
if (c->selinux_context)
fprintf(f,
if (c->syscall_filter) {
#ifdef HAVE_SECCOMP
Iterator j;
void *id;
bool first = true;
fprintf(f,
prefix);
if (!c->syscall_whitelist)
#ifdef HAVE_SECCOMP
if (first)
first = false;
if (c->syscall_errno != 0)
fprintf(f,
assert(s);
zero(*s);
assert(s);
zero(*s);
if (context) {
assert(s);
assert(f);
if (!prefix)
if (s->pid <= 0)
fprintf(f,
fprintf(f,
fprintf(f,
size_t k;
bool first = true;
if (!(n = new(char, k)))
return NULL;
if (!first)
first = false;
p = stpcpy(p, *a);
p = stpcpy(p, *a);
char *p2;
const char *prefix2;
char *cmd;
assert(c);
assert(f);
if (!prefix)
fprintf(f,
assert(f);
if (!prefix)
assert(l);
assert(e);
assert(c);
return -ENOMEM;
strv_free(l);
return -ENOMEM;
c->path = p;
c->argv = l;
if (*rt)
if (!*rt)
return -ENOMEM;
assert(c);
if (*rt)
return -errno;
assert(r);
r->n_ref++;
return NULL;
r->n_ref--;
if (r->n_ref <= 0) {
free(r);
return NULL;
assert(u);
assert(f);
if (!rt)
int copy;
if (copy < 0)
return copy;
int copy;
if (copy < 0)
return copy;
int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds) {
char *copy;
if (!copy)
return log_oom();
char *copy;
if (!copy)
return log_oom();
int fd;
int fd;
static void *remove_tmpdir_thread(void *p) {
return NULL;
if (!rt)