With these two patches, read_utmp() and get_boot_time() succeed on Haiku. Haiku has a get_system_info() call that is supposed to return the boot time. But, like the sysctl on *BSD platforms, its value changes after the VM has been put to sleep and resumed (and the date has changed, which happens automatically after the network connection is restored). So this approach is only usable as a fallback.
I did not find a file that is touched immediately after boot (other than files that contains settings, likely to be touched at other occasions as well). But some directory under /dev does the trick. 2023-08-12 Bruno Haible <br...@clisp.org> readutmp, boot-time: On Haiku, return the boot time. * m4/readutmp.m4 (gl_PREREQ_READUTMP_H): Test whether <OS.h> exists. * lib/boot-time-aux.h (get_haiku_boot_time, get_haiku_boot_time_final_fallback): New functions. * lib/readutmp.c: Include <OS.h>. (read_utmp_from_file): If opening UTMP_FILE fails, continue processing instead of failing. Invoke get_haiku_boot_time and get_haiku_boot_time_final_fallback. * lib/boot-time.c: Include <OS.h>. (get_boot_time_uncached): Invoke get_haiku_boot_time and get_haiku_boot_time_final_fallback. 2023-08-12 Bruno Haible <br...@clisp.org> readutmp: Reduce code duplication. * lib/readutmp.c (have_boot_time): New function. (read_utmp_from_file): Invoke it, instead of duplicating the same loop.
>From 826c19d3dc416244267d3d21f7a901a7163d7d22 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sat, 12 Aug 2023 19:01:56 +0200 Subject: [PATCH 1/2] readutmp: Reduce code duplication. * lib/readutmp.c (have_boot_time): New function. (read_utmp_from_file): Invoke it, instead of duplicating the same loop. --- ChangeLog | 6 +++ lib/readutmp.c | 108 +++++++++++++++++++++---------------------------- 2 files changed, 52 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index d407d7b4c6..f1db83be86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2023-08-12 Bruno Haible <br...@clisp.org> + + readutmp: Reduce code duplication. + * lib/readutmp.c (have_boot_time): New function. + (read_utmp_from_file): Invoke it, instead of duplicating the same loop. + 2023-08-12 Paul Eggert <egg...@cs.ucla.edu> c-file-type: new module diff --git a/lib/readutmp.c b/lib/readutmp.c index 9a5b34054a..d3ed04e242 100644 --- a/lib/readutmp.c +++ b/lib/readutmp.c @@ -297,6 +297,20 @@ finish_utmp (struct utmp_alloc a) return a; } +/* Determine whether A already contains an entry of type BOOT_TIME. */ +_GL_ATTRIBUTE_MAYBE_UNUSED +static bool +have_boot_time (struct utmp_alloc a) +{ + for (idx_t i = 0; i < a.filled; i++) + { + struct gl_utmp *ut = &a.utmp[i]; + if (UT_TYPE_BOOT_TIME (ut)) + return true; + } + return false; +} + # if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION && !HAVE_DECL_GETUTENT struct utmp *getutent (void); # endif @@ -411,7 +425,6 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 && file_is_utmp) { - bool have_boot_time = false; for (idx_t i = 0; i < a.filled; i++) { struct gl_utmp *ut = &a.utmp[i]; @@ -420,11 +433,10 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, /* Workaround for Raspbian: */ if (ut->ut_ts.tv_sec <= 60 && runlevel_ts.tv_sec != 0) ut->ut_ts = runlevel_ts; - have_boot_time = true; break; } } - if (!have_boot_time) + if (!have_boot_time (a)) { /* Workaround for Alpine Linux: */ struct timespec boot_time; @@ -445,29 +457,17 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, it produces wrong values after the date has been bumped in the running system. */ if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 - && strcmp (file, UTMP_FILE) == 0) + && strcmp (file, UTMP_FILE) == 0 + && !have_boot_time (a)) { - bool have_boot_time = false; - for (idx_t i = 0; i < a.filled; i++) - { - struct gl_utmp *ut = &a.utmp[i]; - if (UT_TYPE_BOOT_TIME (ut)) - { - have_boot_time = true; - break; - } - } - if (!have_boot_time) - { - struct timespec boot_time; - if (get_android_boot_time (&boot_time) >= 0) - a = add_utmp (a, options, - "reboot", strlen ("reboot"), - "", 0, - "", 0, - "", 0, - 0, BOOT_TIME, boot_time, 0, 0, 0); - } + struct timespec boot_time; + if (get_android_boot_time (&boot_time) >= 0) + a = add_utmp (a, options, + "reboot", strlen ("reboot"), + "", 0, + "", 0, + "", 0, + 0, BOOT_TIME, boot_time, 0, 0, 0); } # endif @@ -557,21 +557,17 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, # if defined __OpenBSD__ if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 - && strcmp (file, UTMP_FILE) == 0) + && strcmp (file, UTMP_FILE) == 0 + && !have_boot_time (a)) { - /* OpenBSD's 'struct utmp' does not have an ut_type field. */ - bool have_boot_time = false; - if (!have_boot_time) - { - struct timespec boot_time; - if (get_openbsd_boot_time (&boot_time) >= 0) - a = add_utmp (a, options, - "reboot", strlen ("reboot"), - "", 0, - "", 0, - "", 0, - 0, BOOT_TIME, boot_time, 0, 0, 0); - } + struct timespec boot_time; + if (get_openbsd_boot_time (&boot_time) >= 0) + a = add_utmp (a, options, + "reboot", strlen ("reboot"), + "", 0, + "", 0, + "", 0, + 0, BOOT_TIME, boot_time, 0, 0, 0); } # endif @@ -581,29 +577,17 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, && defined CTL_KERN && defined KERN_BOOTTIME \ && !defined __minix if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 - && strcmp (file, UTMP_FILE) == 0) + && strcmp (file, UTMP_FILE) == 0 + && !have_boot_time (a)) { - bool have_boot_time = false; - for (idx_t i = 0; i < a.filled; i++) - { - struct gl_utmp *ut = &a.utmp[i]; - if (UT_TYPE_BOOT_TIME (ut)) - { - have_boot_time = true; - break; - } - } - if (!have_boot_time) - { - struct timespec boot_time; - if (get_bsd_boot_time_final_fallback (&boot_time) >= 0) - a = add_utmp (a, options, - "reboot", strlen ("reboot"), - "", 0, - "", 0, - "", 0, - 0, BOOT_TIME, boot_time, 0, 0, 0); - } + struct timespec boot_time; + if (get_bsd_boot_time_final_fallback (&boot_time) >= 0) + a = add_utmp (a, options, + "reboot", strlen ("reboot"), + "", 0, + "", 0, + "", 0, + 0, BOOT_TIME, boot_time, 0, 0, 0); } # endif @@ -612,7 +596,7 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, # if defined __CYGWIN__ || defined _WIN32 if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 && strcmp (file, UTMP_FILE) == 0 - && a.filled == 0) + && !have_boot_time (a)) { struct timespec boot_time; if (get_windows_boot_time (&boot_time) >= 0) -- 2.34.1
>From 92a6fbdeccc6373e554d014ba9465b8d1d9cd150 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sat, 12 Aug 2023 19:40:28 +0200 Subject: [PATCH 2/2] readutmp, boot-time: On Haiku, return the boot time. * m4/readutmp.m4 (gl_PREREQ_READUTMP_H): Test whether <OS.h> exists. * lib/boot-time-aux.h (get_haiku_boot_time, get_haiku_boot_time_final_fallback): New functions. * lib/readutmp.c: Include <OS.h>. (read_utmp_from_file): If opening UTMP_FILE fails, continue processing instead of failing. Invoke get_haiku_boot_time and get_haiku_boot_time_final_fallback. * lib/boot-time.c: Include <OS.h>. (get_boot_time_uncached): Invoke get_haiku_boot_time and get_haiku_boot_time_final_fallback. --- ChangeLog | 14 +++++ lib/boot-time-aux.h | 45 ++++++++++++++ lib/boot-time.c | 20 +++++- lib/readutmp.c | 148 +++++++++++++++++++++++++++++--------------- m4/readutmp.m4 | 4 +- 5 files changed, 178 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1db83be86..30bf3bef82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2023-08-12 Bruno Haible <br...@clisp.org> + + readutmp, boot-time: On Haiku, return the boot time. + * m4/readutmp.m4 (gl_PREREQ_READUTMP_H): Test whether <OS.h> exists. + * lib/boot-time-aux.h (get_haiku_boot_time, + get_haiku_boot_time_final_fallback): New functions. + * lib/readutmp.c: Include <OS.h>. + (read_utmp_from_file): If opening UTMP_FILE fails, continue processing + instead of failing. Invoke get_haiku_boot_time and + get_haiku_boot_time_final_fallback. + * lib/boot-time.c: Include <OS.h>. + (get_boot_time_uncached): Invoke get_haiku_boot_time and + get_haiku_boot_time_final_fallback. + 2023-08-12 Bruno Haible <br...@clisp.org> readutmp: Reduce code duplication. diff --git a/lib/boot-time-aux.h b/lib/boot-time-aux.h index 8de834efd7..8006b72134 100644 --- a/lib/boot-time-aux.h +++ b/lib/boot-time-aux.h @@ -227,6 +227,51 @@ get_bsd_boot_time_final_fallback (struct timespec *p_boot_time) #endif +#if defined __HAIKU__ + +static int +get_haiku_boot_time (struct timespec *p_boot_time) +{ + /* On Haiku, /etc/utmp does not exist. During boot, + 1. the current time is restored, but possibly with a wrong time zone, + that is, with an offset of a few hours, + 2. some symlinks and files get created, + 3. the various devices are brought up, in particular the network device, + 4. the correct date and time is set, + 5. some more device nodes get created. + The boot time can be retrieved by looking at a directory created during + phase 5, such as /dev/input. */ + const char * const boot_touched_file = "/dev/input"; + struct stat statbuf; + if (stat (boot_touched_file, &statbuf) >= 0) + { + *p_boot_time = get_stat_mtime (&statbuf); + return 0; + } + return -1; +} + +#endif + +#if HAVE_OS_H /* BeOS, Haiku */ + +/* The following approach is only usable as a fallback, because it produces + wrong values after the date has been bumped in the running system, which + happens frequently if the system is running in a virtual machine and this + VM has been put into "saved" or "sleep" state and then resumed. */ +static int +get_haiku_boot_time_final_fallback (struct timespec *p_boot_time) +{ + system_info si; + + get_system_info (&si); + p_boot_time->tv_sec = si.boot_time / 1000000; + p_boot_time->tv_nsec = (si.boot_time % 1000000) * 1000; + return 0; +} + +#endif + #if defined __CYGWIN__ || defined _WIN32 static int diff --git a/lib/boot-time.c b/lib/boot-time.c index b27cb6c6b6..53bd8b148b 100644 --- a/lib/boot-time.c +++ b/lib/boot-time.c @@ -39,6 +39,10 @@ # include <sys/sysctl.h> #endif +#if HAVE_OS_H +# include <OS.h> +#endif + #include "idx.h" #include "readutmp.h" #include "stat-time.h" @@ -162,7 +166,7 @@ get_boot_time_uncached (struct timespec *p_boot_time) found_boot_time = runlevel_ts; # endif -# else /* HP-UX */ +# else /* HP-UX, Haiku */ FILE *f = fopen (UTMP_FILE, "re"); @@ -216,6 +220,20 @@ get_boot_time_uncached (struct timespec *p_boot_time) } # endif +# if defined __HAIKU__ + if (found_boot_time.tv_sec == 0) + { + get_haiku_boot_time (&found_boot_time); + } +# endif + +# if HAVE_OS_H + if (found_boot_time.tv_sec == 0) + { + get_haiku_boot_time_final_fallback (&found_boot_time); + } +# endif + # if defined __CYGWIN__ || defined _WIN32 if (found_boot_time.tv_sec == 0) { diff --git a/lib/readutmp.c b/lib/readutmp.c index d3ed04e242..d0c6303466 100644 --- a/lib/readutmp.c +++ b/lib/readutmp.c @@ -47,6 +47,10 @@ # include <sys/sysctl.h> #endif +#if HAVE_OS_H +# include <OS.h> +#endif + #include "stat-time.h" #include "xalloc.h" @@ -495,64 +499,74 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, } # endif -# else /* old FreeBSD, OpenBSD, HP-UX */ +# else /* old FreeBSD, OpenBSD, HP-UX, Haiku */ FILE *f = fopen (file, "re"); - if (! f) - return -1; - - for (;;) + if (f != NULL) { - struct UTMP_STRUCT_NAME ut; + for (;;) + { + struct UTMP_STRUCT_NAME ut; - if (fread (&ut, sizeof ut, 1, f) == 0) - break; - a = add_utmp (a, options, - UT_USER (&ut), strnlen (UT_USER (&ut), UT_USER_SIZE), - #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID) - ut.ut_id, strnlen (ut.ut_id, UT_ID_SIZE), - #else - "", 0, - #endif - ut.ut_line, strnlen (ut.ut_line, UT_LINE_SIZE), - #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_HOST : HAVE_STRUCT_UTMP_UT_HOST) - ut.ut_host, strnlen (ut.ut_host, UT_HOST_SIZE), - #else - "", 0, - #endif - #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID) - ut.ut_pid, - #else - 0, - #endif - #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE) - ut.ut_type, - #else - 0, - #endif - #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV) - (struct timespec) { .tv_sec = ut.ut_tv.tv_sec, .tv_nsec = ut.ut_tv.tv_usec * 1000 }, - #else - (struct timespec) { .tv_sec = ut.ut_time, .tv_nsec = 0 }, - #endif - #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_SESSION : HAVE_STRUCT_UTMP_UT_SESSION) - ut.ut_session, - #else - 0, - #endif - UT_EXIT_E_TERMINATION (&ut), UT_EXIT_E_EXIT (&ut) - ); - } + if (fread (&ut, sizeof ut, 1, f) == 0) + break; + a = add_utmp (a, options, + UT_USER (&ut), strnlen (UT_USER (&ut), UT_USER_SIZE), + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID) + ut.ut_id, strnlen (ut.ut_id, UT_ID_SIZE), + #else + "", 0, + #endif + ut.ut_line, strnlen (ut.ut_line, UT_LINE_SIZE), + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_HOST : HAVE_STRUCT_UTMP_UT_HOST) + ut.ut_host, strnlen (ut.ut_host, UT_HOST_SIZE), + #else + "", 0, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID) + ut.ut_pid, + #else + 0, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE) + ut.ut_type, + #else + 0, + #endif + #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV) + (struct timespec) { .tv_sec = ut.ut_tv.tv_sec, .tv_nsec = ut.ut_tv.tv_usec * 1000 }, + #else + (struct timespec) { .tv_sec = ut.ut_time, .tv_nsec = 0 }, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_SESSION : HAVE_STRUCT_UTMP_UT_SESSION) + ut.ut_session, + #else + 0, + #endif + UT_EXIT_E_TERMINATION (&ut), UT_EXIT_E_EXIT (&ut) + ); + } - int saved_errno = ferror (f) ? errno : 0; - if (fclose (f) != 0) - saved_errno = errno; - if (saved_errno != 0) + int saved_errno = ferror (f) ? errno : 0; + if (fclose (f) != 0) + saved_errno = errno; + if (saved_errno != 0) + { + free (a.utmp); + errno = saved_errno; + return -1; + } + } + else { - free (a.utmp); - errno = saved_errno; - return -1; + if (strcmp (file, UTMP_FILE) != 0) + { + int saved_errno = errno; + free (a.utmp); + errno = saved_errno; + return -1; + } } # if defined __OpenBSD__ @@ -591,6 +605,38 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, } # endif +# if defined __HAIKU__ + if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 + && strcmp (file, UTMP_FILE) == 0 + && !have_boot_time (a)) + { + struct timespec boot_time; + if (get_haiku_boot_time (&boot_time) >= 0) + a = add_utmp (a, options, + "reboot", strlen ("reboot"), + "", 0, + "", 0, + "", 0, + 0, BOOT_TIME, boot_time, 0, 0, 0); + } +# endif + +# if HAVE_OS_H /* BeOS, Haiku */ + if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0 + && strcmp (file, UTMP_FILE) == 0 + && !have_boot_time (a)) + { + struct timespec boot_time; + if (get_haiku_boot_time_final_fallback (&boot_time) >= 0) + a = add_utmp (a, options, + "reboot", strlen ("reboot"), + "", 0, + "", 0, + "", 0, + 0, BOOT_TIME, boot_time, 0, 0, 0); + } +# endif + # endif # if defined __CYGWIN__ || defined _WIN32 diff --git a/m4/readutmp.m4 b/m4/readutmp.m4 index 357bb8b3c8..827b573f46 100644 --- a/m4/readutmp.m4 +++ b/m4/readutmp.m4 @@ -1,4 +1,4 @@ -# readutmp.m4 serial 25 +# readutmp.m4 serial 26 dnl Copyright (C) 2002-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -112,4 +112,6 @@ AC_DEFUN_ONCE([gl_PREREQ_READUTMP_H] #endif ]) AC_CHECK_FUNCS([sysctl]) + + AC_CHECK_HEADERS_ONCE([OS.h]) ]) -- 2.34.1