X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fexecute.c;h=6b6c2855b48739c04febe6878c37d6370f3e3b11;hp=37b2f8412c87af5ec18c2553941e874325ce87b5;hb=21d21ea42eadd742873c2bddfd474e3b34510431;hpb=15ca554ba3a40e6840c6d6095ec90cf448720454 diff --git a/src/execute.c b/src/execute.c index 37b2f8412..6b6c2855b 100644 --- a/src/execute.c +++ b/src/execute.c @@ -37,6 +37,10 @@ #include #include +#ifdef HAVE_PAM +#include +#endif + #include "execute.h" #include "strv.h" #include "macro.h" @@ -46,6 +50,7 @@ #include "securebits.h" #include "cgroup.h" #include "namespace.h" +#include "tcpwrap.h" /* This assumes there is a 'tty' group */ #define TTY_MODE 0620 @@ -166,7 +171,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)) < 0) { + if (connect(fd, &sa.sa, sizeof(sa_family_t) + 1 + sizeof(LOGGER_SOCKET) - 1) < 0) { close_nointr_nofail(fd); return -errno; } @@ -189,10 +194,10 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons "%i\n" "%s\n" "%i\n", - output == EXEC_OUTPUT_KERNEL ? "kmsg" : "syslog", + 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; @@ -227,39 +232,31 @@ static bool is_terminal_input(ExecInput i) { i == EXEC_INPUT_TTY_FAIL; } -static int fixup_input(const ExecContext *context, int socket_fd) { - assert(context); +static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) { - if (socket_fd < 0 && context->std_input == EXEC_INPUT_SOCKET) + if (is_terminal_input(std_input) && !apply_tty_stdin) return EXEC_INPUT_NULL; - return context->std_input; -} - -static int fixup_output(const ExecContext *context, int socket_fd) { - assert(context); - - if (socket_fd < 0 && context->std_output == EXEC_OUTPUT_SOCKET) - return EXEC_OUTPUT_INHERIT; + if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0) + return EXEC_INPUT_NULL; - return context->std_output; + return std_input; } -static int fixup_error(const ExecContext *context, int socket_fd) { - assert(context); +static int fixup_output(ExecOutput std_output, int socket_fd) { - if (socket_fd < 0 && context->std_error == EXEC_OUTPUT_SOCKET) + if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0) return EXEC_OUTPUT_INHERIT; - return context->std_error; + 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, socket_fd); + i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); switch (i) { @@ -295,15 +292,15 @@ 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, socket_fd); - o = fixup_output(context, 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 */ @@ -311,11 +308,20 @@ 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 (is_terminal_input(i) || i == EXEC_INPUT_SOCKET) + /* If input got downgraded, inherit the original value */ + if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input)) + return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_FILENO); + + /* 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; - return STDIN_FILENO; + /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */ + if (getppid() != 1) + 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); @@ -328,7 +334,7 @@ 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_KERNEL: + case EXEC_OUTPUT_KMSG: return connect_logger_as(context, o, ident, STDOUT_FILENO); case EXEC_OUTPUT_SOCKET: @@ -340,16 +346,16 @@ 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, socket_fd); - o = fixup_output(context, socket_fd); - e = fixup_error(context, 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); /* This expects the input and output are already set up */ @@ -357,10 +363,12 @@ 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 && - !is_terminal_input(i)) + i == EXEC_INPUT_NULL && + !is_terminal_input(context->std_input) && + getppid () != 1) return STDERR_FILENO; - /* Duplicate form stdout if possible */ + /* Duplicate from stdout if possible */ if (e == o || e == EXEC_OUTPUT_INHERIT) return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO; @@ -377,7 +385,7 @@ 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_KERNEL: + case EXEC_OUTPUT_KMSG: return connect_logger_as(context, e, ident, STDERR_FILENO); case EXEC_OUTPUT_SOCKET: @@ -724,6 +732,164 @@ static int enforce_user(const ExecContext *context, uid_t uid) { return 0; } +#ifdef HAVE_PAM + +static int null_conv( + int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) { + + /* We don't support conversations */ + + return PAM_CONV_ERR; +} + +static int setup_pam( + const char *name, + const char *user, + const char *tty, + char ***pam_env, + int fds[], unsigned n_fds) { + + static const struct pam_conv conv = { + .conv = null_conv, + .appdata_ptr = NULL + }; + + pam_handle_t *handle = NULL; + sigset_t ss, old_ss; + int pam_code = PAM_SUCCESS; + char **e = NULL; + bool close_session = false; + pid_t pam_pid = 0, parent_pid; + + assert(name); + assert(user); + 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 + * 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 + * of the daemon is the one we initially fork()ed. */ + + if ((pam_code = pam_start(name, user, &conv, &handle)) != PAM_SUCCESS) { + handle = NULL; + goto fail; + } + + if (tty) + if ((pam_code = pam_set_item(handle, PAM_TTY, tty)) != PAM_SUCCESS) + goto fail; + + if ((pam_code = pam_acct_mgmt(handle, PAM_SILENT)) != PAM_SUCCESS) + goto fail; + + if ((pam_code = pam_open_session(handle, PAM_SILENT)) != PAM_SUCCESS) + goto fail; + + close_session = true; + + if ((pam_code = pam_setcred(handle, PAM_ESTABLISH_CRED | PAM_SILENT)) != PAM_SUCCESS) + goto fail; + + if ((!(e = pam_getenvlist(handle)))) { + pam_code = PAM_BUF_ERR; + goto fail; + } + + /* Block SIGTERM, so that we know that it won't get lost in + * the child */ + if (sigemptyset(&ss) < 0 || + sigaddset(&ss, SIGTERM) < 0 || + sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0) + goto fail; + + parent_pid = getpid(); + + if ((pam_pid = fork()) < 0) + goto fail; + + if (pam_pid == 0) { + int sig; + int r = EXIT_PAM; + + /* The child's job is to reset the PAM session on + * termination */ + + /* This string must fit in 10 chars (i.e. the length + * of "/sbin/init") */ + rename_process("sd:pam"); + + /* Make sure we don't keep open the passed fds in this + child. We assume that otherwise only those fds are + open here that have been opened by PAM. */ + close_many(fds, n_fds); + + /* Wait until our parent died. This will most likely + * not work since the kernel does not allow + * unpriviliged paretns kill their priviliged children + * this way. We rely on the control groups kill logic + * to do the rest for us. */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + goto child_finish; + + /* Check if our parent process might already have + * died? */ + if (getppid() == parent_pid) { + if (sigwait(&ss, &sig) < 0) + goto child_finish; + + assert(sig == SIGTERM); + } + + /* Only if our parent died we'll end the session */ + if (getppid() != parent_pid) + if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS) + goto child_finish; + + r = 0; + + child_finish: + pam_end(handle, pam_code | PAM_DATA_SILENT); + _exit(r); + } + + /* If the child was forked off successfully it will do all the + * cleanups, so forget about the handle here. */ + handle = NULL; + + /* Unblock SIGSUR1 again in the parent */ + if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0) + goto fail; + + /* We close the log explicitly here, since the PAM modules + * might have opened it, but we don't want this fd around. */ + closelog(); + + return 0; + +fail: + if (handle) { + if (close_session) + pam_code = pam_close_session(handle, PAM_DATA_SILENT); + + pam_end(handle, pam_code | PAM_DATA_SILENT); + } + + strv_free(e); + + closelog(); + + if (pam_pid > 1) + kill(pam_pid, SIGTERM); + + return EXIT_PAM; +} +#endif + int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, @@ -731,6 +897,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) { @@ -781,14 +948,24 @@ 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, **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; /* child */ - reset_all_signal_handlers(); + /* This string must fit in 10 chars (i.e. the length + * of "/sbin/init") */ + rename_process("sd:exec"); + + /* We reset exactly these signals, since they are the + * only ones we set to SIG_IGN in the main daemon. All + * others we leave untouched because we set them to + * SIG_DFL or a valid handler initially, both of which + * will be demoted to SIG_DFL. */ + default_signals(SIGNALS_CRASH_HANDLER, + SIGNALS_IGNORE, -1); if (sigemptyset(&ss) < 0 || sigprocmask(SIG_SETMASK, &ss, NULL) < 0) { @@ -796,13 +973,38 @@ int exec_spawn(ExecCommand *command, goto fail; } - if (!context->no_setsid) + /* Close sockets very early to make sure we don't + * block init reexecution because it cannot bind its + * sockets */ + if (close_all_fds(fds, n_fds) < 0) { + r = EXIT_FDS; + goto fail; + } + + if (!context->same_pgrp) if (setsid() < 0) { r = EXIT_SETSID; goto fail; } - if (confirm_spawn) { + if (context->tcpwrap_name) { + if (socket_fd >= 0) + if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) { + r = EXIT_TCPWRAP; + goto fail; + } + + for (i = 0; i < (int) n_fds; i++) { + if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) { + r = EXIT_TCPWRAP; + goto fail; + } + } + } + + /* 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 */ @@ -835,18 +1037,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; } @@ -888,8 +1090,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; } @@ -900,25 +1102,12 @@ 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; } - if (strv_length(context->read_write_dirs) > 0 || - strv_length(context->read_only_dirs) > 0 || - strv_length(context->inaccessible_dirs) > 0 || - context->mount_flags != MS_SHARED || - context->private_tmp) - if ((r = setup_namespace( - context->read_write_dirs, - context->read_only_dirs, - context->inaccessible_dirs, - context->private_tmp, - context->mount_flags)) < 0) - goto fail; - if (context->user) { username = context->user; if (get_user_creds(&username, &uid, &gid, &home) < 0) { @@ -933,6 +1122,15 @@ int exec_spawn(ExecCommand *command, } } +#ifdef HAVE_PAM + if (context->pam_name && username) { + if (setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds) < 0) { + r = EXIT_PAM; + goto fail; + } + } +#endif + if (apply_permissions) if (enforce_groups(context, username, uid) < 0) { r = EXIT_GROUP; @@ -941,6 +1139,19 @@ int exec_spawn(ExecCommand *command, umask(context->umask); + if (strv_length(context->read_write_dirs) > 0 || + strv_length(context->read_only_dirs) > 0 || + strv_length(context->inaccessible_dirs) > 0 || + context->mount_flags != MS_SHARED || + context->private_tmp) + if ((r = setup_namespace( + context->read_write_dirs, + context->read_only_dirs, + context->inaccessible_dirs, + context->private_tmp, + context->mount_flags)) < 0) + goto fail; + if (apply_chroot) { if (context->root_directory) if (chroot(context->root_directory) < 0) { @@ -972,6 +1183,8 @@ int exec_spawn(ExecCommand *command, free(d); } + /* We repeat the fd closing here, to make sure that + * nothing is leaked from the PAM modules */ if (close_all_fds(fds, n_fds) < 0 || shift_fds(fds, n_fds) < 0 || flags_fds(fds, n_fds, context->non_blocking) < 0) { @@ -1020,7 +1233,7 @@ int exec_spawn(ExecCommand *command, } if (n_fds > 0) - if (asprintf(our_env + n_env++, "LISTEN_PID=%llu", (unsigned long long) getpid()) < 0 || + if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 || asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) { r = EXIT_MEMORY; goto fail; @@ -1041,17 +1254,30 @@ int exec_spawn(ExecCommand *command, assert(n_env <= 6); - if (!(final_env = strv_env_merge(environment, our_env, context->environment, NULL))) { + if (!(final_env = strv_env_merge( + 4, + environment, + our_env, + context->environment, + pam_env, + NULL))) { r = EXIT_MEMORY; 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); @@ -1070,10 +1296,9 @@ int exec_spawn(ExecCommand *command, if (cgroup_bondings) cgroup_bonding_install_list(cgroup_bondings, pid); - log_debug("Forked %s as %llu", command->path, (unsigned long long) pid); + log_debug("Forked %s as %lu", command->path, (unsigned long) pid); - command->exec_status.pid = pid; - command->exec_status.start_timestamp = now(CLOCK_REALTIME); + exec_status_start(&command->exec_status, pid); *ret = pid; return 0; @@ -1086,11 +1311,9 @@ 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; - - c->std_input = EXEC_INPUT_NULL; - c->std_output = EXEC_OUTPUT_SYSLOG; - c->std_error = EXEC_OUTPUT_SYSLOG; + c->kill_signal = SIGTERM; } void exec_context_done(ExecContext *c) { @@ -1114,6 +1337,9 @@ void exec_context_done(ExecContext *c) { free(c->tty_path); c->tty_path = NULL; + free(c->tcpwrap_name); + c->tcpwrap_name = NULL; + free(c->syslog_identifier); c->syslog_identifier = NULL; @@ -1126,6 +1352,9 @@ void exec_context_done(ExecContext *c) { strv_free(c->supplementary_groups); c->supplementary_groups = NULL; + free(c->pam_name); + c->pam_name = NULL; + if (c->capabilities) { cap_free(c->capabilities); c->capabilities = NULL; @@ -1139,6 +1368,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) { @@ -1212,6 +1444,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { for (e = c->environment; *e; e++) fprintf(f, "%sEnvironment: %s\n", prefix, *e); + if (c->tcpwrap_name) + fprintf(f, + "%sTCPWrapName: %s\n", + prefix, c->tcpwrap_name); + if (c->nice_set) fprintf(f, "%sNice: %i\n", @@ -1242,16 +1479,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" @@ -1266,8 +1503,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sTTYPath: %s\n", prefix, c->tty_path); - if (c->std_output == EXEC_OUTPUT_SYSLOG || c->std_output == EXEC_OUTPUT_KERNEL || - c->std_error == EXEC_OUTPUT_SYSLOG || c->std_error == EXEC_OUTPUT_KERNEL) + 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) fprintf(f, "%sSyslogFacility: %s\n" "%sSyslogLevel: %s\n", @@ -1310,9 +1547,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { } if (c->user) - fprintf(f, "%sUser: %s", prefix, c->user); + fprintf(f, "%sUser: %s\n", prefix, c->user); if (c->group) - fprintf(f, "%sGroup: %s", prefix, c->group); + fprintf(f, "%sGroup: %s\n", prefix, c->group); if (strv_length(c->supplementary_groups) > 0) { fprintf(f, "%sSupplementaryGroups:", prefix); @@ -1320,6 +1557,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fputs("\n", f); } + if (c->pam_name) + fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name); + if (strv_length(c->read_write_dirs) > 0) { fprintf(f, "%sReadWriteDirs:", prefix); strv_fprintf(f, c->read_write_dirs); @@ -1337,13 +1577,31 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { strv_fprintf(f, c->inaccessible_dirs); fputs("\n", f); } + + fprintf(f, + "%sKillMode: %s\n" + "%sKillSignal: SIG%s\n", + prefix, kill_mode_to_string(c->kill_mode), + prefix, signal_to_string(c->kill_signal)); } -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; - s->exit_timestamp = now(CLOCK_REALTIME); + 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); s->code = code; s->status = status; @@ -1362,20 +1620,20 @@ void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) { return; fprintf(f, - "%sPID: %llu\n", - prefix, (unsigned long long) s->pid); + "%sPID: %lu\n", + prefix, (unsigned long) s->pid); - if (s->start_timestamp > 0) + if (s->start_timestamp.realtime > 0) fprintf(f, "%sStart Timestamp: %s\n", - prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp)); + prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime)); - if (s->exit_timestamp > 0) + if (s->exit_timestamp.realtime > 0) fprintf(f, "%sExit Timestamp: %s\n" "%sExit Code: %s\n" "%sExit Status: %i\n", - prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp), + prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime), prefix, sigchld_code_to_string(s->code), prefix, s->status); } @@ -1598,6 +1856,12 @@ const char* exit_status_to_string(ExitStatus status) { case EXIT_STDERR: return "STDERR"; + case EXIT_TCPWRAP: + return "TCPWRAP"; + + case EXIT_PAM: + return "PAM"; + default: return NULL; } @@ -1616,7 +1880,7 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = { [EXEC_OUTPUT_NULL] = "null", [EXEC_OUTPUT_TTY] = "tty", [EXEC_OUTPUT_SYSLOG] = "syslog", - [EXEC_OUTPUT_KERNEL] = "kernel", + [EXEC_OUTPUT_KMSG] = "kmsg", [EXEC_OUTPUT_SOCKET] = "socket" };