]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
util-lib: split out allocation calls into alloc-util.[ch]
[thirdparty/systemd.git] / src / core / execute.c
index 137a176c186c8e234bb357e568067397ec3ba29b..d751065af08af847aeb6d12c343345ade93ad159 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
+#include <glob.h>
+#include <grp.h>
+#include <poll.h>
 #include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <string.h>
+#include <sys/personality.h>
 #include <sys/prctl.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
-#include <grp.h>
-#include <poll.h>
-#include <glob.h>
+#include <sys/un.h>
+#include <unistd.h>
 #include <utmpx.h>
-#include <sys/personality.h>
 
 #ifdef HAVE_PAM
 #include <security/pam_appl.h>
 #include <sys/apparmor.h>
 #endif
 
-#include "barrier.h"
 #include "sd-messages.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "macro.h"
-#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "namespace.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "utmp-wtmp.h"
-#include "def.h"
-#include "path-util.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "async.h"
-#include "selinux-util.h"
-#include "errno-list.h"
+
 #include "af-list.h"
-#include "mkdir.h"
-#include "smack-util.h"
+#include "alloc-util.h"
+#ifdef HAVE_APPARMOR
+#include "apparmor-util.h"
+#endif
+#include "async.h"
+#include "barrier.h"
 #include "bus-endpoint.h"
 #include "cap-list.h"
+#include "capability-util.h"
+#include "def.h"
+#include "env-util.h"
+#include "errno-list.h"
+#include "execute.h"
+#include "exit-status.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "io-util.h"
+#include "ioprio.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "namespace.h"
+#include "parse-util.h"
+#include "path-util.h"
 #include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-
-#ifdef HAVE_APPARMOR
-#include "apparmor-util.h"
-#endif
-
+#include "rlimit-util.h"
+#include "rm-rf.h"
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
-
-#include "execute.h"
+#include "securebits.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "smack-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "unit.h"
+#include "user-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
 
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 #define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
@@ -358,12 +367,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
         return std_output;
 }
 
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
+static int setup_input(
+                const ExecContext *context,
+                const ExecParameters *params,
+                int socket_fd) {
+
         ExecInput i;
 
         assert(context);
+        assert(params);
+
+        if (params->stdin_fd >= 0) {
+                if (dup2(params->stdin_fd, STDIN_FILENO) < 0)
+                        return -errno;
+
+                /* Try to make this the controlling tty, if it is a tty, and reset it */
+                (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE);
+                (void) reset_terminal_fd(STDIN_FILENO, true);
+
+                return STDIN_FILENO;
+        }
 
-        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+        i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
 
         switch (i) {
 
@@ -400,16 +425,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty
         }
 }
 
-static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
+static int setup_output(
+                Unit *unit,
+                const ExecContext *context,
+                const ExecParameters *params,
+                int fileno,
+                int socket_fd,
+                const char *ident,
+                uid_t uid, gid_t gid) {
+
         ExecOutput o;
         ExecInput i;
         int r;
 
         assert(unit);
         assert(context);
+        assert(params);
         assert(ident);
 
-        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+        if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
+
+                if (dup2(params->stdout_fd, STDOUT_FILENO) < 0)
+                        return -errno;
+
+                return STDOUT_FILENO;
+        }
+
+        if (fileno == STDERR_FILENO && params->stderr_fd >= 0) {
+                if (dup2(params->stderr_fd, STDERR_FILENO) < 0)
+                        return -errno;
+
+                return STDERR_FILENO;
+        }
+
+        i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
         o = fixup_output(context->std_output, socket_fd);
 
         if (fileno == STDERR_FILENO) {
@@ -502,9 +551,9 @@ static int chown_terminal(int fd, uid_t uid) {
         return 0;
 }
 
-static int setup_confirm_stdio(int *_saved_stdin,
-                               int *_saved_stdout) {
-        int fd = -1, saved_stdin, saved_stdout = -1, r;
+static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) {
+        _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1;
+        int r;
 
         assert(_saved_stdin);
         assert(_saved_stdout);
@@ -514,10 +563,8 @@ static int setup_confirm_stdio(int *_saved_stdin,
                 return -errno;
 
         saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
-        if (saved_stdout < 0) {
-                r = errno;
-                goto fail;
-        }
+        if (saved_stdout < 0)
+                return -errno;
 
         fd = acquire_terminal(
                         "/dev/console",
@@ -525,39 +572,33 @@ static int setup_confirm_stdio(int *_saved_stdin,
                         false,
                         false,
                         DEFAULT_CONFIRM_USEC);
-        if (fd < 0) {
-                r = fd;
-                goto fail;
-        }
+        if (fd < 0)
+                return fd;
 
         r = chown_terminal(fd, getuid());
         if (r < 0)
-                goto fail;
+                return r;
 
-        if (dup2(fd, STDIN_FILENO) < 0) {
-                r = -errno;
-                goto fail;
-        }
+        r = reset_terminal_fd(fd, true);
+        if (r < 0)
+                return r;
 
-        if (dup2(fd, STDOUT_FILENO) < 0) {
-                r = -errno;
-                goto fail;
-        }
+        if (dup2(fd, STDIN_FILENO) < 0)
+                return -errno;
+
+        if (dup2(fd, STDOUT_FILENO) < 0)
+                return -errno;
 
         if (fd >= 2)
                 safe_close(fd);
+        fd = -1;
 
         *_saved_stdin = saved_stdin;
         *_saved_stdout = saved_stdout;
 
-        return 0;
-
-fail:
-        safe_close(saved_stdout);
-        safe_close(saved_stdin);
-        safe_close(fd);
+        saved_stdin = saved_stdout = -1;
 
-        return r;
+        return 0;
 }
 
 _printf_(1, 2) static int write_confirm_message(const char *format, ...) {
@@ -577,9 +618,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) {
         return 0;
 }
 
-static int restore_confirm_stdio(int *saved_stdin,
-                                 int *saved_stdout) {
-
+static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
         int r = 0;
 
         assert(saved_stdin);
@@ -595,8 +634,8 @@ static int restore_confirm_stdio(int *saved_stdin,
                 if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
                         r = -errno;
 
-        safe_close(*saved_stdin);
-        safe_close(*saved_stdout);
+        *saved_stdin = safe_close(*saved_stdin);
+        *saved_stdout = safe_close(*saved_stdout);
 
         return r;
 }
@@ -1198,6 +1237,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
 static int build_environment(
                 const ExecContext *c,
                 unsigned n_fds,
+                char ** fd_names,
                 usec_t watchdog_usec,
                 const char *home,
                 const char *username,
@@ -1211,11 +1251,13 @@ static int build_environment(
         assert(c);
         assert(ret);
 
-        our_env = new0(char*, 10);
+        our_env = new0(char*, 11);
         if (!our_env)
                 return -ENOMEM;
 
         if (n_fds > 0) {
+                _cleanup_free_ char *joined = NULL;
+
                 if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
                         return -ENOMEM;
                 our_env[n_env++] = x;
@@ -1223,6 +1265,15 @@ static int build_environment(
                 if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
                         return -ENOMEM;
                 our_env[n_env++] = x;
+
+                joined = strv_join(fd_names, ":");
+                if (!joined)
+                        return -ENOMEM;
+
+                x = strjoin("LISTEN_FDNAMES=", joined, NULL);
+                if (!x)
+                        return -ENOMEM;
+                our_env[n_env++] = x;
         }
 
         if (watchdog_usec > 0) {
@@ -1273,7 +1324,7 @@ static int build_environment(
         }
 
         our_env[n_env++] = NULL;
-        assert(n_env <= 10);
+        assert(n_env <= 11);
 
         *ret = our_env;
         our_env = NULL;
@@ -1311,6 +1362,44 @@ static bool exec_needs_mount_namespace(
         return false;
 }
 
+static int close_remaining_fds(
+                const ExecParameters *params,
+                ExecRuntime *runtime,
+                int socket_fd,
+                int *fds, unsigned n_fds) {
+
+        unsigned n_dont_close = 0;
+        int dont_close[n_fds + 7];
+
+        assert(params);
+
+        if (params->stdin_fd >= 0)
+                dont_close[n_dont_close++] = params->stdin_fd;
+        if (params->stdout_fd >= 0)
+                dont_close[n_dont_close++] = params->stdout_fd;
+        if (params->stderr_fd >= 0)
+                dont_close[n_dont_close++] = params->stderr_fd;
+
+        if (socket_fd >= 0)
+                dont_close[n_dont_close++] = socket_fd;
+        if (n_fds > 0) {
+                memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
+                n_dont_close += n_fds;
+        }
+
+        if (params->bus_endpoint_fd >= 0)
+                dont_close[n_dont_close++] = params->bus_endpoint_fd;
+
+        if (runtime) {
+                if (runtime->netns_storage_socket[0] >= 0)
+                        dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
+                if (runtime->netns_storage_socket[1] >= 0)
+                        dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
+        }
+
+        return close_all_fds(dont_close, n_dont_close);
+}
+
 static int exec_child(
                 Unit *unit,
                 ExecCommand *command,
@@ -1326,8 +1415,6 @@ static int exec_child(
         _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
         _cleanup_free_ char *mac_selinux_context_net = NULL;
         const char *username = NULL, *home = NULL, *shell = NULL, *wd;
-        unsigned n_dont_close = 0;
-        int dont_close[n_fds + 4];
         uid_t uid = UID_INVALID;
         gid_t gid = GID_INVALID;
         int i, r;
@@ -1367,22 +1454,7 @@ static int exec_child(
 
         log_forget_fds();
 
-        if (socket_fd >= 0)
-                dont_close[n_dont_close++] = socket_fd;
-        if (n_fds > 0) {
-                memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
-                n_dont_close += n_fds;
-        }
-        if (params->bus_endpoint_fd >= 0)
-                dont_close[n_dont_close++] = params->bus_endpoint_fd;
-        if (runtime) {
-                if (runtime->netns_storage_socket[0] >= 0)
-                        dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
-                if (runtime->netns_storage_socket[1] >= 0)
-                        dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
-        }
-
-        r = close_all_fds(dont_close, n_dont_close);
+        r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds);
         if (r < 0) {
                 *exit_status = EXIT_FDS;
                 return r;
@@ -1438,21 +1510,21 @@ static int exec_child(
         /* If a socket is connected to STDIN/STDOUT/STDERR, we
          * must sure to drop O_NONBLOCK */
         if (socket_fd >= 0)
-                fd_nonblock(socket_fd, false);
+                (void) fd_nonblock(socket_fd, false);
 
-        r = setup_input(context, socket_fd, params->apply_tty_stdin);
+        r = setup_input(context, params, socket_fd);
         if (r < 0) {
                 *exit_status = EXIT_STDIN;
                 return r;
         }
 
-        r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+        r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
         if (r < 0) {
                 *exit_status = EXIT_STDOUT;
                 return r;
         }
 
-        r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+        r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
         if (r < 0) {
                 *exit_status = EXIT_STDERR;
                 return r;
@@ -1850,7 +1922,7 @@ static int exec_child(
 #endif
         }
 
-        r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
+        r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env);
         if (r < 0) {
                 *exit_status = EXIT_MEMORY;
                 return r;
@@ -2250,7 +2322,7 @@ static void strv_fprintf(FILE *f, char **l) {
 }
 
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
-        char **e;
+        char **e, **d;
         unsigned i;
 
         assert(c);
@@ -2286,6 +2358,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         STRV_FOREACH(e, c->environment_files)
                 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
 
+        fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
+
+        STRV_FOREACH(d, c->runtime_directory)
+                fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
+
         if (c->nice_set)
                 fprintf(f,
                         "%sNice: %i\n",
@@ -2712,7 +2789,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
         if (!l)
                 return -ENOMEM;
 
-        r = strv_extend_strv(&c->argv, l);
+        r = strv_extend_strv(&c->argv, l, false);
         if (r < 0)
                 return r;