From 89916ae1282daa1580384d1e6c6b6ff3edac6ff8 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Thu, 22 Nov 2018 15:40:13 +0000 Subject: [PATCH] Add initial support for logging boot time to wtmp database. --- src/dinit.cc | 14 ++++++- src/includes/dinit-utmp.h | 67 +++++++++++++++++++++++++++++++++ src/includes/dinit.h | 2 +- src/service.cc | 2 +- src/tests/test-includes/dinit.h | 2 +- 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 src/includes/dinit-utmp.h diff --git a/src/dinit.cc b/src/dinit.cc index 1369d3b..191e504 100644 --- a/src/dinit.cc +++ b/src/dinit.cc @@ -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 index 0000000..b270a8b --- /dev/null +++ b/src/includes/dinit-utmp.h @@ -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 + +#include +#include + +// 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 diff --git a/src/includes/dinit.h b/src/includes/dinit.h index ef6b962..fc20ee3 100644 --- a/src/includes/dinit.h +++ b/src/includes/dinit.h @@ -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; diff --git a/src/service.cc b/src/service.cc index 2d94e57..aa00cee 100644 --- a/src/service.cc +++ b/src/service.cc @@ -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(); diff --git a/src/tests/test-includes/dinit.h b/src/tests/test-includes/dinit.h index 14c1ee9..e2a0439 100644 --- a/src/tests/test-includes/dinit.h +++ b/src/tests/test-includes/dinit.h @@ -174,7 +174,7 @@ class eventloop_t std::map regd_fd_watchers; }; -inline void open_control_socket(bool report_ro_failure = true) noexcept +inline void rootfs_is_rw() noexcept { } -- 2.25.1