Add initial support for logging boot time to wtmp database.
authorDavin McCall <davmac@davmac.org>
Thu, 22 Nov 2018 15:40:13 +0000 (15:40 +0000)
committerDavin McCall <davmac@davmac.org>
Sat, 24 Nov 2018 11:09:49 +0000 (11:09 +0000)
src/dinit.cc
src/includes/dinit-utmp.h [new file with mode: 0644]
src/includes/dinit.h
src/service.cc
src/tests/test-includes/dinit.h

index 1369d3bf4d5def0c6e7bb2d24a279d2e9bf3aaac..191e504417676a95546b25e8312803a63cc0e497 100644 (file)
@@ -29,6 +29,7 @@
 #include "dinit-log.h"
 #include "dinit-socket.h"
 #include "static-string.h"
+#include "dinit-utmp.h"
 
 #include "mconfig.h"
 
@@ -54,6 +55,7 @@ eventloop_t event_loop;
 static void sigint_reboot_cb(eventloop_t &eloop) noexcept;
 static void sigquit_cb(eventloop_t &eloop) noexcept;
 static void sigterm_cb(eventloop_t &eloop) noexcept;
+static void open_control_socket(bool report_ro_failure = true) noexcept;
 static void close_control_socket() noexcept;
 static void wait_for_user_input() noexcept;
 static void read_env_file(const char *);
@@ -68,6 +70,7 @@ static dirload_service_set *services;
 static bool am_pid_one = false;     // true if we are PID 1
 static bool am_system_init = false; // true if we are the system init process
 
+static bool did_log_boot = false;
 static bool control_socket_open = false;
 static bool external_log_open = false;
 int active_control_conns = 0;
@@ -604,10 +607,19 @@ static void control_socket_cb(eventloop_t *loop, int sockfd)
     }
 }
 
+// Callback when the root filesystem is read/write:
+void rootfs_is_rw() noexcept
+{
+    open_control_socket(true);
+    if (! did_log_boot) {
+        did_log_boot = log_boot();
+    }
+}
+
 // Open/create the control socket, normally /dev/dinitctl, used to allow client programs to connect
 // and issue service orders and shutdown commands etc. This can safely be called multiple times;
 // once the socket has been successfully opened, further calls have no effect.
-void open_control_socket(bool report_ro_failure) noexcept
+static void open_control_socket(bool report_ro_failure) noexcept
 {
     if (! control_socket_open) {
         const char * saddrname = control_socket_path;
diff --git a/src/includes/dinit-utmp.h b/src/includes/dinit-utmp.h
new file mode 100644 (file)
index 0000000..b270a8b
--- /dev/null
@@ -0,0 +1,67 @@
+// Wrappers for utmp/wtmp & equivalent database access.
+
+#ifndef DINIT_UTMP_H_INCLUDED
+#define DINIT_UTMP_H_INCLUDED
+
+#ifndef USE_UTMPX
+#define USE_UTMPX 1
+#endif
+
+#ifndef USE_UPDWTMPX
+#ifdef __linux__
+#define USE_UPDWTMPX 1
+#else
+#define USE_UPDWTMPX 0
+#endif
+#endif
+
+#if USE_UTMPX
+
+#include <cstring>
+
+#include <utmpx.h>
+#include <sys/time.h>
+
+// Set the time for a utmpx record to the current time.
+inline void set_current_time(struct utmpx *record)
+{
+#ifdef __linux__
+    // On Linux, ut_tv is not actually a struct timeval:
+    timeval curtime;
+    gettimeofday(&curtime, nullptr);
+    record->ut_tv.tv_sec = curtime.tv_sec;
+    record->ut_tv.tv_usec = curtime.tv_usec;
+#else
+    gettimeofday(&record->ut_tv, nullptr);
+#endif
+}
+
+// Log the boot time to the wtmp database (or equivalent).
+inline bool log_boot()
+{
+    struct utmpx record;
+    memset(&record, 0, sizeof(record));
+    record.ut_type = BOOT_TIME;
+
+    set_current_time(&record);
+
+    // On FreeBSD, putxline will update all appropriate databases. On Linux, it only updates
+    // the utmp database: we need to update the wtmp database explicitly:
+#if USE_UPDWTMPX
+    updwtmpx(_PATH_WTMPX, &record);
+#endif
+
+    setutxent();
+    bool success = (pututxline(&record) != NULL);
+    endutxent();
+
+    return success;
+}
+
+#else // Don't update databases:
+
+static inline void log_boot()  {  }
+
+#endif
+
+#endif
index ef6b96254cddd1b9e55522db6bdd19890a795699..fc20ee34efcf09136f48366862dd967e049e3488 100644 (file)
@@ -13,7 +13,7 @@ using clock_type = dasynq::clock_type;
 using rearm = dasynq::rearm;
 using time_val = dasynq::time_val;
 
-void open_control_socket(bool report_ro_failure = true) noexcept;
+void rootfs_is_rw() noexcept;
 void setup_external_log() noexcept;
 
 extern eventloop_t event_loop;
index 2d94e57389a0c4d62f9d8ba3cdb19739ae4cfaaf..aa00cee8f18925435ea6fc07acbbbc9be7fcd086 100644 (file)
@@ -379,7 +379,7 @@ void service_record::started() noexcept
     notify_listeners(service_event_t::STARTED);
 
     if (onstart_flags.rw_ready) {
-        open_control_socket();
+        rootfs_is_rw();
     }
     if (onstart_flags.log_ready) {
         setup_external_log();
index 14c1ee932c9437e553a72dbe8f55d0bb2b525725..e2a043992e639c6215500dabd05c77e5f1256fc5 100644 (file)
@@ -174,7 +174,7 @@ class eventloop_t
        std::map<int, fd_watcher *> regd_fd_watchers;
 };
 
-inline void open_control_socket(bool report_ro_failure = true) noexcept
+inline void rootfs_is_rw() noexcept
 {
 }