execute.c revision 5c56a259e07661a66e806cc2fbc71de96a75f78e
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt This file is part of systemd.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt Copyright 2010 Lennart Poettering
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt systemd is free software; you can redistribute it and/or modify it
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt under the terms of the GNU Lesser General Public License as published by
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt the Free Software Foundation; either version 2.1 of the License, or
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt (at your option) any later version.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt systemd is distributed in the hope that it will be useful, but
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt WITHOUT ANY WARRANTY; without even the implied warranty of
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt Lesser General Public License for more details.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt You should have received a copy of the GNU Lesser General Public License
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt along with systemd; If not, see <http://www.gnu.org/licenses/>.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt/* This assumes there is a 'tty' group */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int shift_fds(int fds[], unsigned n_fds) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Modifies the fds array! (sorts it) */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Already at right index? */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Hmm, the fd we wanted isn't free? Then
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * let's remember that and try again from here*/
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt for (i = 0; i < n_fds; i++) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* We unconditionally drop FD_CLOEXEC from the fds,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * since after all we want to pass these fds to our
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * children */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt_pure_ static const char *tty_path(const ExecContext *context) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic void exec_context_tty_reset(const ExecContext *context) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (context->tty_vt_disallocate && context->tty_path)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic bool is_terminal_output(ExecOutput o) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt .un.sun_path = "/run/systemd/journal/stdout",
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt context->syslog_identifier ? context->syslog_identifier : ident,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int open_terminal_as(const char *path, mode_t mode, int nfd) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (is_terminal_input(std_input) && !apply_tty_stdin)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int fixup_output(ExecOutput std_output, int socket_fd) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt o = fixup_output(context->std_output, socket_fd);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt e = fixup_output(context->std_error, socket_fd);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* This expects the input and output are already set up */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* Don't change the stderr file descriptor if we inherit all
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * the way and are not on a tty */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Duplicate from stdout if possible */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (e == o || e == EXEC_OUTPUT_INHERIT)
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt } else if (o == EXEC_OUTPUT_INHERIT) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* If input got downgraded, inherit the original value */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return open_terminal_as(tty_path(context), O_WRONLY, fileno);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* If the input is connected to anything that's not a /dev/null, inherit that... */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* We need to open /dev/null here anew, to get the right access mode. */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* We don't reset the terminal if this is just about output */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt return open_terminal_as(tty_path(context), O_WRONLY, fileno);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt r = connect_logger_as(context, o, ident, unit_id, fileno);
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt "MESSAGE=Failed to connect std%s of %s to the journal socket: %s",
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt "ERRNO=%d", -r,
e1323fbfbe8a574f28b704f2df8ce7f99e3a28f5Michal Schmidt return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int chown_terminal(int fd, uid_t uid) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* This might fail. What matters are the results. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int setup_confirm_stdio(int *_saved_stdin,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt int fd = -1, saved_stdin, saved_stdout = -1, r;
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int restore_confirm_stdio(int *saved_stdin,
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidtstatic int ask_for_confirmation(char *response, char **argv) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt r = ask(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt restore_confirm_stdio(&saved_stdin, &saved_stdout);
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Lookup and set GID and supplementary group list. Here too
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * we avoid NSS lookups for gid=0. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* First step, initialize groups from /etc/groups */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Second step, set our gids */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Final step, initialize any manually set supplementary groups */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if ((k = getgroups(ngroups_max, gids)) < 0) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt STRV_FOREACH(i, context->supplementary_groups) {
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt const char *g;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidtstatic int enforce_user(const ExecContext *context, uid_t uid) {
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* Sets (but doesn't lookup) the uid and make sure we keep the
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * capabilities while doing so. */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt CAP_SETUID, /* Necessary so that we can run setresuid() below */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* First step: If we need to keep capabilities but
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * drop privileges we need to make sure we keep our
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * caps, while we drop privileges. */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* Second step: set the capabilities. This will reduce
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * the capabilities to the minimum we need. */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* Third step: actually set the uids */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* At this point we should have all necessary capabilities but
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt are otherwise a normal user. However, the caps might got
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt corrupted due to the setresuid() so we need clean them up
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt later. This is done outside of this call. */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* We don't support conversations */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* We set up PAM in the parent process, then fork. The child
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * will then stay around until killed via PR_GET_PDEATHSIG or
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * systemd via the cgroup logic. It will then remove the PAM
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * session again. The parent process will exec() the actual
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * daemon. We do things this way to ensure that the main PID
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt * of the daemon is the one we initially fork()ed. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt if (log_get_max_level() < LOG_PRI(LOG_DEBUG))
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt pam_code = pam_start(name, user, &conv, &handle);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt pam_code = pam_set_item(handle, PAM_TTY, tty);
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Block SIGTERM, so that we know that it won't get lost in
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * the child */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* The child's job is to reset the PAM session on
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * termination */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* This string must fit in 10 chars (i.e. the length
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * of "/sbin/init"), to look pretty in /bin/ps */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Make sure we don't keep open the passed fds in this
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt child. We assume that otherwise only those fds are
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt open here that have been opened by PAM. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Drop privileges - we don't need any to pam_close_session
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * and this will make PR_SET_PDEATHSIG work in most cases.
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * If this fails, ignore the error - but expect sd-pam threads
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * to fail to exit normally */
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r));
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt /* Wait until our parent died. This will only work if
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt * the above setresuid() succeeds, otherwise the kernel
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt * will not allow unprivileged parents kill their privileged
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt * children this way. We rely on the control groups kill logic
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt * to do the rest for us. */
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt /* Check if our parent process might already have
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* If our parent died we'll end the session */
9ba81d5a61b7c992a1d2e5e02f334b8e2a0b0c22Michal Schmidt /* If the child was forked off successfully it will do all the
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt * cleanups, so forget about the handle here. */
32a4456cc252689f51f383d150d34ed636bfec4dMichal Schmidt /* Unblock SIGTERM again in the parent */
8f88aed740ded77af443bb1b7c79bb229b50f8f8Michal Schmidt if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
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);
struct sock_filter *f;
for (i = 0, n = 0; i < syscall_max(); i++)
for (i = 0, n = 0; i < syscall_max(); i++)
return -errno;
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;
if (err < 0) {
r = EXIT_SECCOMP;
goto fail_child;
#ifdef HAVE_SELINUX
if (err < 0) {
r = EXIT_SELINUX_CONTEXT;
goto fail_child;
if (err < 0) {
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)
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,
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)