From: Bruno Haible <bruno@clisp.org>
To: Paul Eggert <eggert@cs.ucla.edu>,
Natanael Copa <natanael.copa@gmail.com>
Cc: "Robert Pluim" <rpluim@gmail.com>,
bug-gnulib@gnu.org, "Pádraig Brady" <P@draigbrady.com>,
"Sven Joachim" <svenjoac@gmx.de>,
64937@debbugs.gnu.org, "Po Lu" <luangruo@yahoo.com>,
"Emacs Development" <Emacs-devel@gnu.org>,
"Thorsten Kukuk" <kukuk@suse.com>,
"Natanael Copa" <ncopa@alpinelinux.org>
Subject: Re: boot time on Linux
Date: Thu, 10 Aug 2023 17:30:06 +0200 [thread overview]
Message-ID: <3699692.1sqS2uS86G@nimes> (raw)
In-Reply-To: <CAJT+8eyiBvfCD6oxV44R6p=ywuv=XbDkx=d=g5EUd3AkXNNVww@mail.gmail.com>
Natanael Copa wrote:
> There are machines without RTC (Raspberry PI for example), and in
> this case the time stamp may end up to be the same every reboot (if
> correctly set up it should save the shutdown time for the reboot and set
> time to this on next boot, but there is no guarantee).
Indeed, on a Raspi with Raspbian (Debian derivative), /var/run/utmp contains
a BOOT_TIME entry with time = 1970-01-01 00:00:05. Which is unusable.
The clock gets set during the boot process, apparently through NTP. Then,
some files get touched:
/var/lib/systemd/timers/stamp-apt-daily.timer
/var/lib/systemd/timers/stamp-apt-daily-upgrade.timer
/var/lib/apt/daily_lock
But I suspect that they may be touched at other moments than during boot.
Therefore here, the workaround with the file time stamps does not work.
But another workaround works:
2023-08-10 Bruno Haible <bruno@clisp.org>
readutmp: Fix the boot time returned on Raspbian.
* lib/readutmp.c (read_utmp_from_file): When the time of the BOOT_TIME
entry is very close to the Epoch, replace it with the time from the
"runlevel"/"~" entry.
diff --git a/lib/readutmp.c b/lib/readutmp.c
index b344d8294d..e383531474 100644
--- a/lib/readutmp.c
+++ b/lib/readutmp.c
@@ -369,6 +369,12 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
SET_UTMP_ENT ();
+# if defined __linux__ && !defined __ANDROID__
+ bool file_is_utmp = (strcmp (file, UTMP_FILE) == 0);
+ /* Timestamp of the "runlevel" entry, if any. */
+ struct timespec runlevel_ts = {0};
+# endif
+
void const *entry;
while ((entry = GET_UTMP_ENT ()) != NULL)
@@ -408,6 +414,13 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
struct UTMP_STRUCT_NAME const *ut = (struct UTMP_STRUCT_NAME const *) entry;
# endif
+ struct timespec ts =
+ #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV)
+ { .tv_sec = ut->ut_tv.tv_sec, .tv_nsec = ut->ut_tv.tv_usec * 1000 };
+ #else
+ { .tv_sec = ut->ut_time, .tv_nsec = 0 };
+ #endif
+
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)
@@ -431,11 +444,7 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
#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
+ ts,
#if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_SESSION : HAVE_STRUCT_UTMP_UT_SESSION)
ut->ut_session,
#else
@@ -443,6 +452,12 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
#endif
UT_EXIT_E_TERMINATION (ut), UT_EXIT_E_EXIT (ut)
);
+# if defined __linux__ && !defined __ANDROID__
+ if (file_is_utmp
+ && memcmp (UT_USER (ut), "runlevel", strlen ("runlevel") + 1) == 0
+ && memcmp (ut->ut_line, "~", strlen ("~") + 1) == 0)
+ runlevel_ts = ts;
+# endif
}
END_UTMP_ENT ();
@@ -450,9 +465,19 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
# if defined __linux__ && !defined __ANDROID__
/* On Alpine Linux, UTMP_FILE is not filled. It is always empty.
So, fake a BOOT_TIME entry, by getting the time stamp of a file that
- gets touched only during the boot process. */
+ gets touched only during the boot process.
+
+ On Raspbian, which runs on hardware without a real-time clock, during boot,
+ 1. the clock gets set to 1970-01-01 00:00:00,
+ 2. an entry gets written into /var/run/utmp, with ut_type = BOOT_TIME,
+ ut_user = "reboot", ut_line = "~", time = 1970-01-01 00:00:05 or so,
+ 3. the clock gets set to a correct value through NTP,
+ 4. an entry gets written into /var/run/utmp, with
+ ut_user = "runlevel", ut_line = "~", time = correct value.
+ In this case, copy the time from the "runlevel" entry to the "reboot"
+ entry. */
if ((options & (READ_UTMP_USER_PROCESS | READ_UTMP_NO_BOOT_TIME)) == 0
- && strcmp (file, UTMP_FILE) == 0)
+ && file_is_utmp)
{
bool have_boot_time = false;
for (idx_t i = 0; i < a.filled; i++)
@@ -460,12 +485,16 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
struct gl_utmp *ut = &a.utmp[i];
if (UT_TYPE_BOOT_TIME (ut))
{
+ /* 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)
{
+ /* Workaround for Alpine Linux: */
const char * const boot_touched_files[] =
{
"/var/lib/systemd/random-seed", /* seen on distros with systemd */
prev parent reply other threads:[~2023-08-10 15:30 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <87tttmpt5h.fsf@turtle.gmx.de>
[not found] ` <20230808173430.GA27131@suse.com>
[not found] ` <26226778.6c9BZvbsD2@nimes>
[not found] ` <3732835.vtg8X0x55z@nimes>
2023-08-09 19:31 ` boot time on Linux Paul Eggert
2023-08-09 21:06 ` Bruno Haible
2023-08-09 23:53 ` Po Lu
2023-08-10 0:14 ` Bruno Haible
2023-08-10 2:14 ` Po Lu
2023-08-10 6:22 ` Paul Eggert
2023-08-10 6:58 ` Po Lu
2023-08-10 10:30 ` Bruno Haible
2023-08-10 12:23 ` bug#64937: " Po Lu via GNU coreutils Bug Reports
2023-08-10 12:25 ` Bruno Haible
2023-08-10 13:04 ` Po Lu
2023-08-10 14:12 ` Bruno Haible
2023-08-11 8:27 ` Po Lu
2023-08-10 9:30 ` Natanael Copa
2023-08-10 9:38 ` Po Lu
2023-08-10 10:05 ` Natanael Copa
2023-08-10 15:30 ` Bruno Haible [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3699692.1sqS2uS86G@nimes \
--to=bruno@clisp.org \
--cc=64937@debbugs.gnu.org \
--cc=Emacs-devel@gnu.org \
--cc=P@draigbrady.com \
--cc=bug-gnulib@gnu.org \
--cc=eggert@cs.ucla.edu \
--cc=kukuk@suse.com \
--cc=luangruo@yahoo.com \
--cc=natanael.copa@gmail.com \
--cc=ncopa@alpinelinux.org \
--cc=rpluim@gmail.com \
--cc=svenjoac@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).