summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--TODO2
-rw-r--r--man/systemd.exec.xml21
-rw-r--r--src/dbus-execute.h8
-rw-r--r--src/execute.c15
-rw-r--r--src/execute.h4
-rw-r--r--src/load-fragment.c3
-rw-r--r--src/mount.c2
-rw-r--r--src/service.c4
-rw-r--r--src/socket.c2
-rw-r--r--src/utmp-wtmp.c78
-rw-r--r--src/utmp-wtmp.h3
-rw-r--r--units/getty@.service.m41
13 files changed, 128 insertions, 17 deletions
diff --git a/Makefile.am b/Makefile.am
index 021babc43..c4d4d2773 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
diff --git a/TODO b/TODO
index cdb4cc57f..0a7efa111 100644
--- a/TODO
+++ b/TODO
@@ -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 38b9e0608..51dcdcd94 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 f1814315f..3d84c2061 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 6db048c5f..9c7e0d6b7 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 b61214502..ed61e3c62 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 740c11c3c..b22955b42 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 fefe76bb4..3320bf120 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 195f04a31..04496a2dd 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 2567d0feb..fc6088c26 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 77baaffac..41589303b 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 0d608f6a5..86bc6bd3f 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 8df77c701..be5916a15 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