chiark / gitweb /
Spelling Corrections
[elogind.git] / src / execute.c
index 2443d9c74d08e65c543ebed36350bed31593d5d6..d6f09e26fea39c9519fe5cd13a485553f44e516c 100644 (file)
@@ -36,6 +36,7 @@
 #include <pwd.h>
 #include <sys/mount.h>
 #include <linux/fs.h>
+#include <linux/oom.h>
 
 #ifdef HAVE_PAM
 #include <security/pam_appl.h>
@@ -52,6 +53,8 @@
 #include "namespace.h"
 #include "tcpwrap.h"
 #include "exit-status.h"
+#include "missing.h"
+#include "utmp-wtmp.h"
 
 /* This assumes there is a 'tty' group */
 #define TTY_MODE 0620
@@ -172,7 +175,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
         sa.sa.sa_family = AF_UNIX;
         strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
 
-        if (connect(fd, &sa.sa, sizeof(sa_family_t) + 1 + sizeof(LOGGER_SOCKET) - 1) < 0) {
+        if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + sizeof(LOGGER_SOCKET) - 1) < 0) {
                 close_nointr_nofail(fd);
                 return -errno;
         }
@@ -195,7 +198,10 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
                 "%i\n"
                 "%s\n"
                 "%i\n",
-                output == EXEC_OUTPUT_KMSG ? "kmsg" : "syslog",
+                output == EXEC_OUTPUT_KMSG ?             "kmsg" :
+                output == EXEC_OUTPUT_KMSG_AND_CONSOLE ? "kmsg+console" :
+                output == EXEC_OUTPUT_SYSLOG ?           "syslog" :
+                                                         "syslog+console",
                 context->syslog_priority,
                 context->syslog_identifier ? context->syslog_identifier : ident,
                 context->syslog_level_prefix);
@@ -335,7 +341,9 @@ static int setup_output(const ExecContext *context, int socket_fd, const char *i
                 return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO);
 
         case EXEC_OUTPUT_SYSLOG:
+        case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
         case EXEC_OUTPUT_KMSG:
+        case EXEC_OUTPUT_KMSG_AND_CONSOLE:
                 return connect_logger_as(context, o, ident, STDOUT_FILENO);
 
         case EXEC_OUTPUT_SOCKET:
@@ -386,7 +394,9 @@ static int setup_error(const ExecContext *context, int socket_fd, const char *id
                 return open_terminal_as(tty_path(context), O_WRONLY, STDERR_FILENO);
 
         case EXEC_OUTPUT_SYSLOG:
+        case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
         case EXEC_OUTPUT_KMSG:
+        case EXEC_OUTPUT_KMSG_AND_CONSOLE:
                 return connect_logger_as(context, e, ident, STDERR_FILENO);
 
         case EXEC_OUTPUT_SOCKET:
@@ -582,7 +592,7 @@ static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const c
 
                 /* If there are multiple users with the same id, make
                  * sure to leave $USER to the configured value instead
-                 * of the first occurence in the database. However if
+                 * of the first occurrence in the database. However if
                  * the uid was configured by a numeric uid, then let's
                  * pick the real username from /etc/passwd. */
                 if (*username && p)
@@ -607,7 +617,7 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_
 
         assert(context);
 
-        /* Lookup and ser GID and supplementary group list. Here too
+        /* Lookup and set GID and supplementary group list. Here too
          * we avoid NSS lookups for gid=0. */
 
         if (context->group || username) {
@@ -690,7 +700,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
 
                 /* First step: If we need to keep capabilities but
                  * drop privileges we need to make sure we keep our
-                 * caps, whiel we drop priviliges. */
+                 * caps, whiel we drop privileges. */
                 if (uid != 0) {
                         int sb = context->secure_bits|SECURE_KEEP_CAPS;
 
@@ -699,7 +709,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
                                         return -errno;
                 }
 
-                /* Second step: set the capabilites. This will reduce
+                /* Second step: set the capabilities. This will reduce
                  * the capabilities to the minimum we need. */
 
                 if (!(d = cap_dup(context->capabilities)))
@@ -770,7 +780,7 @@ static int setup_pam(
         assert(pam_env);
 
         /* We set up PAM in the parent process, then fork. The child
-         * will then stay around untill killed via PR_GET_PDEATHSIG or
+         * will then stay around until killed via PR_GET_PDEATHSIG or
          * systemd via the cgroup logic. It will then remove the PAM
          * session again. The parent process will exec() the actual
          * daemon. We do things this way to ensure that the main PID
@@ -831,7 +841,7 @@ static int setup_pam(
 
                 /* Wait until our parent died. This will most likely
                  * not work since the kernel does not allow
-                 * unpriviliged paretns kill their priviliged children
+                 * unprivileged parents kill their privileged children
                  * this way. We rely on the control groups kill logic
                  * to do the rest for us. */
                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
@@ -1066,15 +1076,27 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
                         }
 
-                if (context->oom_adjust_set) {
+                if (context->oom_score_adjust_set) {
                         char t[16];
 
-                        snprintf(t, sizeof(t), "%i", context->oom_adjust);
+                        snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
                         char_array_0(t);
 
-                        if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
-                                r = EXIT_OOM_ADJUST;
-                                goto fail;
+                        if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
+                                /* Compatibility with Linux <= 2.6.35 */
+
+                                int adj;
+
+                                adj = (context->oom_score_adjust * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
+                                adj = CLAMP(adj, OOM_DISABLE, OOM_ADJUST_MAX);
+
+                                snprintf(t, sizeof(t), "%i", adj);
+                                char_array_0(t);
+
+                                if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
+                                        r = EXIT_OOM_ADJUST;
+                                        goto fail;
+                                }
                         }
                 }
 
@@ -1115,6 +1137,9 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
                         }
 
+                if (context->utmp_id)
+                        utmp_put_init_process(0, context->utmp_id, getpid(), getsid(0), context->tty_path);
+
                 if (context->user) {
                         username = context->user;
                         if (get_user_creds(&username, &uid, &gid, &home) < 0) {
@@ -1217,7 +1242,7 @@ int exec_spawn(ExecCommand *command,
                                         goto fail;
                                 }
 
-                        /* PR_GET_SECUREBITS is not priviliged, while
+                        /* PR_GET_SECUREBITS is not privileged, while
                          * PR_SET_SECUREBITS is. So to suppress
                          * potential EPERMs we'll try not to call
                          * PR_SET_SECUREBITS unless necessary. */
@@ -1234,7 +1259,7 @@ int exec_spawn(ExecCommand *command,
                                 }
                 }
 
-                if (!(our_env = new0(char*, 6))) {
+                if (!(our_env = new0(char*, 7))) {
                         r = EXIT_MEMORY;
                         goto fail;
                 }
@@ -1259,7 +1284,15 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
                         }
 
-                assert(n_env <= 6);
+                if (is_terminal_input(context->std_input) ||
+                    context->std_output == EXEC_OUTPUT_TTY ||
+                    context->std_error == EXEC_OUTPUT_TTY)
+                        if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
+                                r = EXIT_MEMORY;
+                                goto fail;
+                        }
+
+                assert(n_env <= 7);
 
                 if (!(final_env = strv_env_merge(
                                       4,
@@ -1277,6 +1310,8 @@ int exec_spawn(ExecCommand *command,
                         goto fail;
                 }
 
+                final_env = strv_env_clean(final_env);
+
                 execve(command->path, final_argv, final_env);
                 r = EXIT_EXEC;
 
@@ -1321,6 +1356,7 @@ void exec_context_init(ExecContext *c) {
         c->syslog_level_prefix = true;
         c->mount_flags = MS_SHARED;
         c->kill_signal = SIGTERM;
+        c->send_sigkill = true;
 }
 
 void exec_context_done(ExecContext *c) {
@@ -1378,6 +1414,9 @@ void exec_context_done(ExecContext *c) {
 
         if (c->cpuset)
                 CPU_FREE(c->cpuset);
+
+        free(c->utmp_id);
+        c->utmp_id = NULL;
 }
 
 void exec_command_done(ExecCommand *c) {
@@ -1461,10 +1500,10 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                         "%sNice: %i\n",
                         prefix, c->nice);
 
-        if (c->oom_adjust_set)
+        if (c->oom_score_adjust_set)
                 fprintf(f,
-                        "%sOOMAdjust: %i\n",
-                        prefix, c->oom_adjust);
+                        "%sOOMScoreAdjust: %i\n",
+                        prefix, c->oom_score_adjust);
 
         for (i = 0; i < RLIM_NLIMITS; i++)
                 if (c->rlimit[i])
@@ -1511,7 +1550,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                         prefix, c->tty_path);
 
         if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KMSG ||
-            c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG)
+            c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
+            c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KMSG ||
+            c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE)
                 fprintf(f,
                         "%sSyslogFacility: %s\n"
                         "%sSyslogLevel: %s\n",
@@ -1587,9 +1628,16 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
 
         fprintf(f,
                 "%sKillMode: %s\n"
-                "%sKillSignal: SIG%s\n",
+                "%sKillSignal: SIG%s\n"
+                "%sSendSIGKILL: %s\n",
                 prefix, kill_mode_to_string(c->kill_mode),
-                prefix, signal_to_string(c->kill_signal));
+                prefix, signal_to_string(c->kill_signal),
+                prefix, yes_no(c->send_sigkill));
+
+        if (c->utmp_id)
+                fprintf(f,
+                        "%sUtmpIdentifier: %s\n",
+                        prefix, c->utmp_id);
 }
 
 void exec_status_start(ExecStatus *s, pid_t pid) {
@@ -1600,7 +1648,7 @@ void exec_status_start(ExecStatus *s, pid_t pid) {
         dual_timestamp_get(&s->start_timestamp);
 }
 
-void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status) {
+void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status, const char *utmp_id) {
         assert(s);
 
         if ((s->pid && s->pid != pid) ||
@@ -1612,6 +1660,9 @@ void exec_status_exit(ExecStatus *s, pid_t pid, int code, int status) {
 
         s->code = code;
         s->status = status;
+
+        if (utmp_id)
+                utmp_put_dead_process(utmp_id, pid, code, status);
 }
 
 void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
@@ -1728,7 +1779,7 @@ void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
         assert(e);
 
         if (*l) {
-                /* It's kinda important that we keep the order here */
+                /* It's kind of important, that we keep the order here */
                 LIST_FIND_TAIL(ExecCommand, command, *l, end);
                 LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
         } else
@@ -1771,15 +1822,34 @@ static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
         [EXEC_INPUT_SOCKET] = "socket"
 };
 
+DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+
 static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
         [EXEC_OUTPUT_INHERIT] = "inherit",
         [EXEC_OUTPUT_NULL] = "null",
         [EXEC_OUTPUT_TTY] = "tty",
         [EXEC_OUTPUT_SYSLOG] = "syslog",
+        [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
         [EXEC_OUTPUT_KMSG] = "kmsg",
+        [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
         [EXEC_OUTPUT_SOCKET] = "socket"
 };
 
 DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
 
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
+static const char* const kill_mode_table[_KILL_MODE_MAX] = {
+        [KILL_CONTROL_GROUP] = "control-group",
+        [KILL_PROCESS_GROUP] = "process-group",
+        [KILL_PROCESS] = "process",
+        [KILL_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
+
+static const char* const kill_who_table[_KILL_WHO_MAX] = {
+        [KILL_MAIN] = "main",
+        [KILL_CONTROL] = "control",
+        [KILL_ALL] = "all"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);