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 |