chiark / gitweb /
execute: support minimal environment variable replacement when executing processes
[elogind.git] / src / execute.c
index 9ded1c77882cd3e5750f3f8cb348eedeb6ffbc3b..955a3e23784f43605416c8553dbb9f7891487a70 100644 (file)
@@ -197,7 +197,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
                 output == EXEC_OUTPUT_KMSG ? "kmsg" : "syslog",
                 context->syslog_priority,
                 context->syslog_identifier ? context->syslog_identifier : ident,
-                !context->syslog_no_prefix);
+                context->syslog_level_prefix);
 
         if (fd != nfd) {
                 r = dup2(fd, nfd) < 0 ? -errno : nfd;
@@ -232,7 +232,10 @@ static bool is_terminal_input(ExecInput i) {
                 i == EXEC_INPUT_TTY_FAIL;
 }
 
-static int fixup_input(ExecInput std_input, int socket_fd) {
+static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
+
+        if (is_terminal_input(std_input) && !apply_tty_stdin)
+                return EXEC_INPUT_NULL;
 
         if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
                 return EXEC_INPUT_NULL;
@@ -248,12 +251,12 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
         return std_output;
 }
 
-static int setup_input(const ExecContext *context, int socket_fd) {
+static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
         ExecInput i;
 
         assert(context);
 
-        i = fixup_input(context->std_input, socket_fd);
+        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
 
         switch (i) {
 
@@ -289,14 +292,14 @@ static int setup_input(const ExecContext *context, int socket_fd) {
         }
 }
 
-static int setup_output(const ExecContext *context, int socket_fd, const char *ident) {
+static int setup_output(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) {
         ExecOutput o;
         ExecInput i;
 
         assert(context);
         assert(ident);
 
-        i = fixup_input(context->std_input, socket_fd);
+        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
         o = fixup_output(context->std_output, socket_fd);
 
         /* This expects the input is already set up */
@@ -305,16 +308,16 @@ static int setup_output(const ExecContext *context, int socket_fd, const char *i
 
         case EXEC_OUTPUT_INHERIT:
 
-                /* If the input is connected to a terminal, inherit that... */
+                /* If the input is connected to anything that's not a /dev/null, inherit that... */
                 if (i != EXEC_INPUT_NULL)
                         return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
 
-                /* For PID 1 stdout is always connected to /dev/null,
-                 * hence reopen the console if out parent is PID1. */
-                if (getppid() == 1)
-                        return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
+                /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
+                if (getppid() != 1)
+                        return STDOUT_FILENO;
 
-                return STDOUT_FILENO;
+                /* We need to open /dev/null here anew, to get the
+                 * right access mode. So we fall through */
 
         case EXEC_OUTPUT_NULL:
                 return open_null_as(O_WRONLY, STDOUT_FILENO);
@@ -339,14 +342,14 @@ static int setup_output(const ExecContext *context, int socket_fd, const char *i
         }
 }
 
-static int setup_error(const ExecContext *context, int socket_fd, const char *ident) {
+static int setup_error(const ExecContext *context, int socket_fd, const char *ident, bool apply_tty_stdin) {
         ExecOutput o, e;
         ExecInput i;
 
         assert(context);
         assert(ident);
 
-        i = fixup_input(context->std_input, socket_fd);
+        i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
         o = fixup_output(context->std_output, socket_fd);
         e = fixup_output(context->std_error, socket_fd);
 
@@ -356,7 +359,7 @@ static int setup_error(const ExecContext *context, int socket_fd, const char *id
          * the way and are not on a tty */
         if (e == EXEC_OUTPUT_INHERIT &&
             o == EXEC_OUTPUT_INHERIT &&
-            i != EXEC_INPUT_NULL &&
+            i == EXEC_INPUT_NULL &&
             getppid () != 1)
                 return STDERR_FILENO;
 
@@ -889,6 +892,7 @@ int exec_spawn(ExecCommand *command,
                char **environment,
                bool apply_permissions,
                bool apply_chroot,
+               bool apply_tty_stdin,
                bool confirm_spawn,
                CGroupBonding *cgroup_bondings,
                pid_t *ret) {
@@ -939,7 +943,7 @@ int exec_spawn(ExecCommand *command,
                 const char *username = NULL, *home = NULL;
                 uid_t uid = (uid_t) -1;
                 gid_t gid = (gid_t) -1;
-                char **our_env = NULL, **pam_env = NULL, **final_env = NULL;
+                char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
                 unsigned n_env = 0;
                 int saved_stdout = -1, saved_stdin = -1;
                 bool keep_stdout = false, keep_stdin = false;
@@ -964,7 +968,7 @@ int exec_spawn(ExecCommand *command,
                         goto fail;
                 }
 
-                if (!context->no_setsid)
+                if (!context->same_pgrp)
                         if (setsid() < 0) {
                                 r = EXIT_SETSID;
                                 goto fail;
@@ -985,7 +989,9 @@ int exec_spawn(ExecCommand *command,
                         }
                 }
 
-                if (confirm_spawn) {
+                /* We skip the confirmation step if we shall not apply the TTY */
+                if (confirm_spawn &&
+                    (!is_terminal_input(context->std_input) || apply_tty_stdin)) {
                         char response;
 
                         /* Set up terminal for the question */
@@ -1018,18 +1024,18 @@ int exec_spawn(ExecCommand *command,
                 }
 
                 if (!keep_stdin)
-                        if (setup_input(context, socket_fd) < 0) {
+                        if (setup_input(context, socket_fd, apply_tty_stdin) < 0) {
                                 r = EXIT_STDIN;
                                 goto fail;
                         }
 
                 if (!keep_stdout)
-                        if (setup_output(context, socket_fd, file_name_from_path(command->path)) < 0) {
+                        if (setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) {
                                 r = EXIT_STDOUT;
                                 goto fail;
                         }
 
-                if (setup_error(context, socket_fd, file_name_from_path(command->path)) < 0) {
+                if (setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin) < 0) {
                         r = EXIT_STDERR;
                         goto fail;
                 }
@@ -1071,8 +1077,8 @@ int exec_spawn(ExecCommand *command,
                         }
                 }
 
-                if (context->cpu_affinity_set)
-                        if (sched_setaffinity(0, sizeof(context->cpu_affinity), &context->cpu_affinity) < 0) {
+                if (context->cpuset)
+                        if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
                                 r = EXIT_CPUAFFINITY;
                                 goto fail;
                         }
@@ -1083,8 +1089,8 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
                         }
 
-                if (context->timer_slack_ns_set)
-                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_ns_set) < 0) {
+                if (context->timer_slack_nsec_set)
+                        if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
                                 r = EXIT_TIMERSLACK;
                                 goto fail;
                         }
@@ -1254,13 +1260,19 @@ int exec_spawn(ExecCommand *command,
                         goto fail;
                 }
 
-                execve(command->path, argv, final_env);
+                if (!(final_argv = replace_env_argv(argv, final_env))) {
+                        r = EXIT_MEMORY;
+                        goto fail;
+                }
+
+                execve(command->path, final_argv, final_env);
                 r = EXIT_EXEC;
 
         fail:
                 strv_free(our_env);
                 strv_free(final_env);
                 strv_free(pam_env);
+                strv_free(final_argv);
 
                 if (saved_stdin >= 0)
                         close_nointr_nofail(saved_stdin);
@@ -1281,8 +1293,7 @@ int exec_spawn(ExecCommand *command,
 
         log_debug("Forked %s as %lu", command->path, (unsigned long) pid);
 
-        command->exec_status.pid = pid;
-        dual_timestamp_get(&command->exec_status.start_timestamp);
+        exec_status_start(&command->exec_status, pid);
 
         *ret = pid;
         return 0;
@@ -1295,6 +1306,7 @@ void exec_context_init(ExecContext *c) {
         c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
         c->cpu_sched_policy = SCHED_OTHER;
         c->syslog_priority = LOG_DAEMON|LOG_INFO;
+        c->syslog_level_prefix = true;
         c->mount_flags = MS_SHARED;
 }
 
@@ -1350,6 +1362,9 @@ void exec_context_done(ExecContext *c) {
 
         strv_free(c->inaccessible_dirs);
         c->inaccessible_dirs = NULL;
+
+        if (c->cpuset)
+                CPU_FREE(c->cpuset);
 }
 
 void exec_command_done(ExecCommand *c) {
@@ -1458,16 +1473,16 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                         prefix, c->cpu_sched_priority,
                         prefix, yes_no(c->cpu_sched_reset_on_fork));
 
-        if (c->cpu_affinity_set) {
+        if (c->cpuset) {
                 fprintf(f, "%sCPUAffinity:", prefix);
-                for (i = 0; i < CPU_SETSIZE; i++)
-                        if (CPU_ISSET(i, &c->cpu_affinity))
+                for (i = 0; i < c->cpuset_ncpus; i++)
+                        if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
                                 fprintf(f, " %i", i);
                 fputs("\n", f);
         }
 
-        if (c->timer_slack_ns_set)
-                fprintf(f, "%sTimerSlackNS: %lu\n", prefix, c->timer_slack_ns);
+        if (c->timer_slack_nsec_set)
+                fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
 
         fprintf(f,
                 "%sStandardInput: %s\n"
@@ -1558,9 +1573,21 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         }
 }
 
-void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) {
+void exec_status_start(ExecStatus *s, pid_t pid) {
         assert(s);
 
+        zero(*s);
+        s->pid = pid;
+        dual_timestamp_get(&s->start_timestamp);
+}
+
+void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status) {
+        assert(s);
+
+        if ((s->pid && s->pid != pid) ||
+            !s->start_timestamp.realtime <= 0)
+                zero(*s);
+
         s->pid = pid;
         dual_timestamp_get(&s->exit_timestamp);