From mboxrd@z Thu Jan  1 00:00:00 1970
Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail
From: Bruno Haible <bruno@clisp.org>
Newsgroups: gmane.comp.lib.gnulib.bugs,gmane.emacs.devel
Subject: Re: boot time on Linux
Date: Thu, 10 Aug 2023 17:30:06 +0200
Message-ID: <3699692.1sqS2uS86G@nimes>
References: <87tttmpt5h.fsf@turtle.gmx.de>
 <c8c927bb-5e44-f26d-837e-ae6b73e60add@cs.ucla.edu>
 <CAJT+8eyiBvfCD6oxV44R6p=ywuv=XbDkx=d=g5EUd3AkXNNVww@mail.gmail.com>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7Bit
Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214";
	logging-data="15260"; mail-complaints-to="usenet@ciao.gmane.io"
Cc: Robert Pluim <rpluim@gmail.com>, bug-gnulib@gnu.org,
 =?ISO-8859-1?Q?P=E1draig?= 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>
To: Paul Eggert <eggert@cs.ucla.edu>, Natanael Copa <natanael.copa@gmail.com>
Original-X-From: bug-gnulib-bounces+gnu-bug-gnulib=m.gmane-mx.org@gnu.org Thu Aug 10 17:30:40 2023
Return-path: <bug-gnulib-bounces+gnu-bug-gnulib=m.gmane-mx.org@gnu.org>
Envelope-to: gnu-bug-gnulib@m.gmane-mx.org
Original-Received: from lists.gnu.org ([209.51.188.17])
	by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
	(Exim 4.92)
	(envelope-from <bug-gnulib-bounces+gnu-bug-gnulib=m.gmane-mx.org@gnu.org>)
	id 1qU7cV-0003li-Ob
	for gnu-bug-gnulib@m.gmane-mx.org; Thu, 10 Aug 2023 17:30:39 +0200
Original-Received: from localhost ([::1] helo=lists1p.gnu.org)
	by lists.gnu.org with esmtp (Exim 4.90_1)
	(envelope-from <bug-gnulib-bounces@gnu.org>)
	id 1qU7cI-0002zl-5I; Thu, 10 Aug 2023 11:30:26 -0400
Original-Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <bruno@clisp.org>)
 id 1qU7cG-0002zV-2Q; Thu, 10 Aug 2023 11:30:24 -0400
Original-Received: from mo4-p01-ob.smtp.rzone.de ([81.169.146.167])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <bruno@clisp.org>)
 id 1qU7cD-0001hf-QA; Thu, 10 Aug 2023 11:30:23 -0400
ARC-Seal: i=1; a=rsa-sha256; t=1691681407; cv=none;
 d=strato.com; s=strato-dkim-0002;
 b=JgjTqhz1NosdpYPkLsjY013q2b1+OSug1GZwFfv1cvXvB9JBEDsYjnUKscp/hLHlIC
 qg9P1I9Z8IK62larIdw3I1AS6tnsswbiGiOYeLc3De2NJZ54hzM41wj6wDfnC3pvsMLg
 zQ/Grl8PN5CAvkXdMuc5hh+tjsKYZbbS0vYXi53MSVsID7Hx6Ej8vieB33qZ1+bslNTN
 4vKlDpp80WGNIepkhJCLxSVvdio3VsM75dIRj57uPe15xJnTcEV7ziHwMalBdWMjJ6Jg
 qz8oa2w99lAGx5SqkO1kuZSFvWDQ44hocIu/GT5HDQG3M2lTMhgJ/fR6GFmX+gNAw6ss
 l4Mw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1691681407;
 s=strato-dkim-0002; d=strato.com;
 h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date:
 From:Subject:Sender;
 bh=KQVk5SCYmHv5y7uDYq5UybN1nLJkASUjS9JdTj/31SU=;
 b=F+RiqcOYMwx6AR+7aWQV4D25a5szd89tH+JDqbsCXNJ1A7JSs6QxSgo6aTKPu9hLed
 P8Vu3T0EcQz7ne0x0O5DUzFMgMtuCTKHMFEpSm8hlPBeUBDl1THSGHkSa9N0HDY3ED9W
 FZAvAL1G/57rlpszv/5T7KjSvvpIPApAu9RdY02LC3943+qWVGPLGHLfFWiyAL+aNety
 x24cPdAohNCKhbMMlu7Uver68I9OojuVFVA8BE92R+K2LyloeroUjY6E9i9u1Kjpymis
 +bta8ZJA6lrbLnGtSbDi/O43MhthFfp5q1QgNLplV/wGZ3nGLk0fwai54BL8uyVK5QWV
 MT/Q==
ARC-Authentication-Results: i=1; strato.com;
    arc=none;
    dkim=none
X-RZG-CLASS-ID: mo01
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1691681407;
 s=strato-dkim-0002; d=clisp.org;
 h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date:
 From:Subject:Sender;
 bh=KQVk5SCYmHv5y7uDYq5UybN1nLJkASUjS9JdTj/31SU=;
 b=RM2TBjs5SsThStyQC9l0NDwEjSlnAA1mUczdBQtdJWFqOvtVeYzDixL83Y/84bsXWx
 WCet+v8A6UWMyh22Cvb0D2PpH+lbgmwp8ae2DOrLRnNXRhWVw7A/tRIZIcP5MiYvEU99
 XKo6Qbe3kMvm/M1lyddQw11QbjoFQr0F8pbRZrBQewHtpjN80dB8sLxiY8sIbfsJZraW
 qBDkMX+b/kr1x6X10QHqck4NS6MEuGcaoYxNHEwS6cJUgftbcS2z5nleNkDE70z5Yyes
 CvQ/3WJCbL4lruFdmWOeqjWA5J2zzaRlocYtnLF6+mcWH6y5wevagQ22fKzeh0nIXrYR
 F8Ag==
DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1691681407;
 s=strato-dkim-0003; d=clisp.org;
 h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date:
 From:Subject:Sender;
 bh=KQVk5SCYmHv5y7uDYq5UybN1nLJkASUjS9JdTj/31SU=;
 b=bMZazSXtd5JEnMn0SIzrps0jDTUTzHNevkPRV4kWyhE3rWz1NsngiUfVsKHWXh7fRR
 MssE+uPFGIJIkhF0D2Cw==
X-RZG-AUTH: ":Ln4Re0+Ic/6oZXR1YgKryK8brlshOcZlIWs+iCP5vnk6shH0WWb0LN8XZoH94zq68+3cfpOS3/KAj5mP2WdWFYXnsMspu5Gi+A=="
Original-Received: from nimes.localnet by smtp.strato.de (RZmta 49.6.6 AUTH)
 with ESMTPSA id x129eaz7AFU6wy9
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits))
 (Client did not present a certificate);
 Thu, 10 Aug 2023 17:30:06 +0200 (CEST)
In-Reply-To: <CAJT+8eyiBvfCD6oxV44R6p=ywuv=XbDkx=d=g5EUd3AkXNNVww@mail.gmail.com>
Received-SPF: none client-ip=81.169.146.167; envelope-from=bruno@clisp.org;
 helo=mo4-p01-ob.smtp.rzone.de
X-Spam_score_int: -27
X-Spam_score: -2.8
X-Spam_bar: --
X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,
 RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001,
 SPF_HELO_PASS=-0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-BeenThere: bug-gnulib@gnu.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Gnulib discussion list <bug-gnulib.gnu.org>
List-Unsubscribe: <https://lists.gnu.org/mailman/options/bug-gnulib>,
 <mailto:bug-gnulib-request@gnu.org?subject=unsubscribe>
List-Archive: <https://lists.gnu.org/archive/html/bug-gnulib>
List-Post: <mailto:bug-gnulib@gnu.org>
List-Help: <mailto:bug-gnulib-request@gnu.org?subject=help>
List-Subscribe: <https://lists.gnu.org/mailman/listinfo/bug-gnulib>,
 <mailto:bug-gnulib-request@gnu.org?subject=subscribe>
Errors-To: bug-gnulib-bounces+gnu-bug-gnulib=m.gmane-mx.org@gnu.org
Original-Sender: bug-gnulib-bounces+gnu-bug-gnulib=m.gmane-mx.org@gnu.org
Xref: news.gmane.io gmane.comp.lib.gnulib.bugs:48150 gmane.emacs.devel:308539
Archived-At: <http://permalink.gmane.org/gmane.comp.lib.gnulib.bugs/48150>

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 */