diff options
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | TODO | 2 | ||||
| -rw-r--r-- | man/systemd.exec.xml | 21 | ||||
| -rw-r--r-- | src/dbus-execute.h | 8 | ||||
| -rw-r--r-- | src/execute.c | 15 | ||||
| -rw-r--r-- | src/execute.h | 4 | ||||
| -rw-r--r-- | src/load-fragment.c | 3 | ||||
| -rw-r--r-- | src/mount.c | 2 | ||||
| -rw-r--r-- | src/service.c | 4 | ||||
| -rw-r--r-- | src/socket.c | 2 | ||||
| -rw-r--r-- | src/utmp-wtmp.c | 78 | ||||
| -rw-r--r-- | src/utmp-wtmp.h | 3 | ||||
| -rw-r--r-- | units/getty@.service.m4 | 1 | 
13 files changed, 128 insertions, 17 deletions
| diff --git a/Makefile.am b/Makefile.am index 021babc439..c4d4d2773d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -374,6 +374,7 @@ libsystemd_core_la_SOURCES = \  	src/path.c \  	src/load-dropin.c \  	src/execute.c \ +	src/utmp-wtmp.c \  	src/exit-status.c \  	src/dbus.c \  	src/dbus-manager.c \ @@ -440,7 +441,6 @@ EXTRA_DIST += \  	src/dbus-common.h \  	src/bus-errors.h \  	src/cgroup-show.h \ -	src/utmp-wtmp.h \  	src/build.h \  	src/shutdownd.h \  	src/readahead-common.h @@ -24,8 +24,6 @@     - bluetoothd (/var/run/sdp! @/org/bluez/audio!)     - distccd -* write utmp record a la upstart for processes -  * selinux policy loading  * fingerprint.target, wireless.target, gps.target diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 38b9e06086..51dcdcd947 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -728,6 +728,27 @@                                  it.</para></listitem>                          </varlistentry> +                        <varlistentry> +                                <term><varname>UtmpIdentifier=</varname></term> + +                                <listitem><para>Takes a a four +                                character identifier string for an +                                utmp/wtmp entry for this service. This +                                should only be set for services such +                                as <command>getty</command> +                                implementations where utmp/wtmp +                                entries must be created and cleared +                                before and after execution. If the +                                configured string is longer than four +                                characters it is truncated and the +                                terminal four characters are +                                used. This setting interprets %I style +                                string replacements. This setting is +                                unset by default, i.e. no utmp/wtmp +                                entries are created or cleaned up for +                                this service.</para></listitem> +                        </varlistentry> +                  </variablelist>          </refsect1> diff --git a/src/dbus-execute.h b/src/dbus-execute.h index f1814315f7..3d84c20614 100644 --- a/src/dbus-execute.h +++ b/src/dbus-execute.h @@ -84,8 +84,9 @@          "  <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \          "  <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \          "  <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \ -        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \ -        "  <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" +        "  <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n"  \ +        "  <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \ +        "  <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n"  #define BUS_EXEC_COMMAND_INTERFACE(name)                             \          "  <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n" @@ -142,7 +143,8 @@          { interface, "PrivateTmp",                    bus_property_append_bool,   "b",     &(context).private_tmp                  }, \          { interface, "SameProcessGroup",              bus_property_append_bool,   "b",     &(context).same_pgrp                    }, \          { interface, "KillMode",                      bus_execute_append_kill_mode, "s",   &(context).kill_mode                    }, \ -        { interface, "KillSignal",                    bus_property_append_int,    "i",     &(context).kill_signal                  } +        { interface, "KillSignal",                    bus_property_append_int,    "i",     &(context).kill_signal                  }, \ +        { interface, "UtmpIdentifier",                bus_property_append_string, "s",     &(context).utmp_id                      }  #define BUS_EXEC_STATUS_PROPERTIES(interface, estatus, prefix)           \          { interface, prefix "StartTimestamp",         bus_property_append_usec,   "t",     &(estatus).start_timestamp.realtime     }, \ diff --git a/src/execute.c b/src/execute.c index 6db048c5fc..9c7e0d6b70 100644 --- a/src/execute.c +++ b/src/execute.c @@ -54,6 +54,7 @@  #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 @@ -1129,6 +1130,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) { @@ -1604,6 +1608,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {                  "%sKillSignal: SIG%s\n",                  prefix, kill_mode_to_string(c->kill_mode),                  prefix, signal_to_string(c->kill_signal)); + +        if (c->utmp_id) +                fprintf(f, +                        "%sUtmpIdentifier: %s\n", +                        prefix, c->utmp_id); +  }  void exec_status_start(ExecStatus *s, pid_t pid) { @@ -1614,7 +1624,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) || @@ -1626,6 +1636,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) { diff --git a/src/execute.h b/src/execute.h index b612145027..ed61e3c62f 100644 --- a/src/execute.h +++ b/src/execute.h @@ -127,6 +127,8 @@ struct ExecContext {          char *pam_name; +        char *utmp_id; +          char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;          unsigned long mount_flags; @@ -191,7 +193,7 @@ void exec_context_done(ExecContext *c);  void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);  void exec_status_start(ExecStatus *s, pid_t pid); -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);  void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);  const char* exec_output_to_string(ExecOutput i); diff --git a/src/load-fragment.c b/src/load-fragment.c index 740c11c3c2..b22955b424 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -1669,7 +1669,8 @@ static int load_from_path(Unit *u, const char *path) {                  { "TCPWrapName",            config_parse_string_printf,   &(context).tcpwrap_name,                         section   }, \                  { "PAMName",                config_parse_string_printf,   &(context).pam_name,                             section   }, \                  { "KillMode",               config_parse_kill_mode,       &(context).kill_mode,                            section   }, \ -                { "KillSignal",             config_parse_kill_signal,     &(context).kill_signal,                          section   } +                { "KillSignal",             config_parse_kill_signal,     &(context).kill_signal,                          section   }, \ +                { "UtmpIdentifier",         config_parse_string_printf,   &(context).utmp_id,                              section   }          const ConfigItem items[] = {                  { "Names",                  config_parse_names,           u,                                               "Unit"    }, diff --git a/src/mount.c b/src/mount.c index fefe76bb4d..3320bf1202 100644 --- a/src/mount.c +++ b/src/mount.c @@ -1057,7 +1057,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {          m->failure = m->failure || !success;          if (m->control_command) { -                exec_status_exit(&m->control_command->exec_status, pid, code, status); +                exec_status_exit(&m->control_command->exec_status, pid, code, status, m->exec_context.utmp_id);                  m->control_command = NULL;                  m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;          } diff --git a/src/service.c b/src/service.c index 195f04a315..04496a2dd2 100644 --- a/src/service.c +++ b/src/service.c @@ -2406,7 +2406,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {          if (s->main_pid == pid) {                  s->main_pid = 0; -                exec_status_exit(&s->main_exec_status, pid, code, status); +                exec_status_exit(&s->main_exec_status, pid, code, status, s->exec_context.utmp_id);                  if (s->type != SERVICE_FORKING && s->control_command) {                          s->control_command->exec_status = s->main_exec_status; @@ -2483,7 +2483,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {                  s->control_pid = 0;                  if (s->control_command) { -                        exec_status_exit(&s->control_command->exec_status, pid, code, status); +                        exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id);                          if (s->control_command->ignore)                                  success = true; diff --git a/src/socket.c b/src/socket.c index 2567d0febf..fc6088c261 100644 --- a/src/socket.c +++ b/src/socket.c @@ -1601,7 +1601,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {          success = is_clean_exit(code, status);          if (s->control_command) { -                exec_status_exit(&s->control_command->exec_status, pid, code, status); +                exec_status_exit(&s->control_command->exec_status, pid, code, status, s->exec_context.utmp_id);                  if (s->control_command->ignore)                          success = true; diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c index 77baaffacf..41589303ba 100644 --- a/src/utmp-wtmp.c +++ b/src/utmp-wtmp.c @@ -92,19 +92,26 @@ int utmp_get_runlevel(int *runlevel, int *previous) {          return r;  } -static void init_entry(struct utmpx *store, usec_t t) { -        struct utsname uts; - +static void init_timestamp(struct utmpx *store, usec_t t) {          assert(store);          zero(*store); -        zero(uts);          if (t <= 0)                  t = now(CLOCK_REALTIME);          store->ut_tv.tv_sec = t / USEC_PER_SEC;          store->ut_tv.tv_usec = t % USEC_PER_SEC; +} + +static void init_entry(struct utmpx *store, usec_t t) { +        struct utsname uts; + +        assert(store); + +        init_timestamp(store, t); + +        zero(uts);          if (uname(&uts) >= 0)                  strncpy(store->ut_host, uts.release, sizeof(store->ut_host)); @@ -187,6 +194,69 @@ int utmp_put_reboot(usec_t t) {          return write_entry_both(&store);  } +static const char *sanitize_id(const char *id) { +        size_t l; + +        assert(id); +        l = strlen(id); + +        if (l <= sizeof(((struct utmpx*) NULL)->ut_id)) +                return id; + +        return id + l - sizeof(((struct utmpx*) NULL)->ut_id); +} + +int utmp_put_init_process(usec_t t, const char *id, pid_t pid, pid_t sid, const char *line) { +        struct utmpx store; + +        assert(id); + +        init_timestamp(&store, t); + +        store.ut_type = INIT_PROCESS; +        store.ut_pid = pid; +        store.ut_session = sid; + +        strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id)); + +        if (line) +                strncpy(store.ut_line, file_name_from_path(line), sizeof(store.ut_line)); + +        return write_entry_both(&store); +} + +int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { +        struct utmpx lookup, store, *found; + +        assert(id); + +        setutxent(); + +        zero(lookup); +        lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ +        strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id)); + +        if (!(found = getutxid(&lookup))) +                return 0; + +        if (found->ut_pid != pid) +                return 0; + +        zero(store); + +        memcpy(&store, &lookup, sizeof(store)); +        store.ut_type = DEAD_PROCESS; +        store.ut_exit.e_termination = code; +        store.ut_exit.e_exit = status; + +        zero(store.ut_user); +        zero(store.ut_host); +        zero(store.ut_tv); + +        return write_entry_both(&store); +} + +  int utmp_put_runlevel(usec_t t, int runlevel, int previous) {          struct utmpx store;          int r; diff --git a/src/utmp-wtmp.h b/src/utmp-wtmp.h index 0d608f6a5e..86bc6bd3fc 100644 --- a/src/utmp-wtmp.h +++ b/src/utmp-wtmp.h @@ -30,6 +30,9 @@ int utmp_put_shutdown(usec_t timestamp);  int utmp_put_reboot(usec_t timestamp);  int utmp_put_runlevel(usec_t timestamp, int runlevel, int previous); +int utmp_put_dead_process(const char *id, pid_t pid, int code, int status); +int utmp_put_init_process(usec_t timestamp, const char *id, pid_t pid, pid_t sid, const char *line); +  int utmp_wall(const char *message);  #endif diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 index 8df77c701c..be5916a155 100644 --- a/units/getty@.service.m4 +++ b/units/getty@.service.m4 @@ -33,6 +33,7 @@ Environment=TERM=linux  ExecStart=-GETTY %I  Restart=always  RestartSec=0 +UtmpIdentifier=%I  KillMode=process-group  # Some login implementations ignore SIGTERM, so we send SIGHUP | 
