chiark / gitweb /
service: optionally, create INIT_PROCESS/DEAD_PROCESS entries for a service
authorLennart Poettering <lennart@poettering.net>
Fri, 8 Oct 2010 14:06:23 +0000 (16:06 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 8 Oct 2010 14:07:50 +0000 (16:07 +0200)
This should fix accounting for pam_limits and suchlike.

https://bugzilla.redhat.com/show_bug.cgi?id=636036

13 files changed:
Makefile.am
TODO
man/systemd.exec.xml
src/dbus-execute.h
src/execute.c
src/execute.h
src/load-fragment.c
src/mount.c
src/service.c
src/socket.c
src/utmp-wtmp.c
src/utmp-wtmp.h
units/getty@.service.m4

index 021babc..c4d4d27 100644 (file)
@@ -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 cdb4cc5..0a7efa1 100644 (file)
--- 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
index 38b9e06..51dcdcd 100644 (file)
                                 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>
 
index f181431..3d84c20 100644 (file)
@@ -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"
         { 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     }, \
index 6db048c..9c7e0d6 100644 (file)
@@ -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) {
index b612145..ed61e3c 100644 (file)
@@ -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);
index 740c11c..b22955b 100644 (file)
@@ -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"    },
index fefe76b..3320bf1 100644 (file)
@@ -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;
         }
index 195f04a..04496a2 100644 (file)
@@ -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;
index 2567d0f..fc6088c 100644 (file)
@@ -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;
index 77baaff..4158930 100644 (file)
@@ -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;
index 0d608f6..86bc6bd 100644 (file)
@@ -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
index 8df77c7..be5916a 100644 (file)
@@ -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