* Re: boot time on Linux
[not found] ` <3732835.vtg8X0x55z@nimes>
@ 2023-08-09 19:31 ` Paul Eggert
2023-08-09 21:06 ` Bruno Haible
` (2 more replies)
0 siblings, 3 replies; 17+ messages in thread
From: Paul Eggert @ 2023-08-09 19:31 UTC (permalink / raw)
To: Bruno Haible
Cc: Robert Pluim, bug-gnulib, Pádraig Brady, Sven Joachim, 64937,
Natanael Copa, Po Lu, Emacs Development, Thorsten Kukuk
[-- Attachment #1: Type: text/plain, Size: 1203 bytes --]
[For those cc'ed, the thread's at <https://bugs.gnu.org/64937#142>.]
On 2023-08-09 07:29, Bruno Haible wrote:
> And on Alpine Linux, while /var/run/utmp is empty, its time stamp is
> essentially the boot time.
>
> The approach used by Emacs, namely to look at the time stamp of
> /var/run/random-seed, is therefore essentially one of the best approaches.
> It just needs to also look at /var/lib/systemd/random-seed and - on Alpine
> Linux - /var/run/utmp .
Thanks for looking into this. Clearly Emacs had some catching up to do,
since it was using a location for the random-seed file that current
GNU/Linux distros no longer use. To try to fix this I installed the
attached patch to Emacs master on Savannah.
This patch does not address the problem for Alpine, nor I suspect for
Android. I suppose Alpine could use the timestamp of /var/run/utmp (or
is that /run/utmp?) but I don't know how 'configure' would reliably
detect it's being built or cross-built for Alpine. I'll cc this to
Natanael Copa, who does the Alpine ports for Emacs, to see whether he
can give advice.
Also, I don't know how Android records boot time so I'll cc this to Po
Lu, the main developer for Emacs on Android.
[-- Attachment #2: 0001-Adjust-to-random-seed-move.patch --]
[-- Type: text/x-patch, Size: 3400 bytes --]
From cc0a30a876adffa5ec110df9f4e0f21097f6d73e Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Wed, 9 Aug 2023 12:06:25 -0700
Subject: [PATCH] Adjust to random-seed move
For some time, GNU/Linux systems have put their random-seed file
somewhere other than where src/filelock.c looks for it.
Catch up to this by having 'configure' scout for it.
* configure.ac (BOOT_TIME_FILE):
Define this at configure-time.
* nt/inc/ms-w32.h (BOOT_TIME_FILE): Override 'configure'.
* src/filelock.c (BOOT_TIME_FILE): Remove default definition,
since 'configure' defaults it now.
---
configure.ac | 31 +++++++++++++++++++++++++++++++
nt/inc/ms-w32.h | 1 +
src/filelock.c | 6 ------
3 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/configure.ac b/configure.ac
index 6e080c1c666..56c8cf1ae05 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2625,6 +2625,37 @@ AC_DEFUN
fi
AC_SUBST([AUTO_DEPEND])
+AC_CACHE_CHECK([for old but post-boot file],
+ [emacs_cv_boot_time_file],
+ [AS_CASE([$opsys],
+ [*bsd|darwin|dragonfly],
+ [emacs_cv_boot_time_file='not needed'],
+ [emacs_cv_boot_time_file=unknown
+ AS_IF([test $cross_compiling = no],
+ [# systemd puts it in /var/lib/systemd.
+ # initscripts puts it in /var/lib/urandom (previously /var/lib).
+ # Linux drivers/char/random.c before 2022-02-21 suggests /var/run.
+ for file in \
+ /var/lib/systemd/random-seed \
+ /var/lib/urandom/random-seed \
+ /var/lib/random-seed \
+ /var/run/random-seed
+ do
+ test -f $file && { emacs_cv_boot_time_file=$file; break; }
+ done])])])
+AS_CASE([$emacs_cv_boot_time_file],
+ [/*|*:*], [BOOT_TIME_FILE=\"$emacs_cv_boot_time_file\"],
+ [NULL|nullptr|0], [BOOT_TIME_FILE=$emacs_cv_boot_time_file],
+ ['not needed'], [BOOT_TIME_FILE=NULL],
+ [# Guess systemd if unknown.
+ # If guess is wrong, Emacs falls back on something else.
+ BOOT_TIME_FILE=\"/var/lib/systemd/random-seed\"])
+AC_DEFINE_UNQUOTED([BOOT_TIME_FILE], [$BOOT_TIME_FILE],
+ [Name of file that, if it exists, postdates boot and predates
+ the first Emacs invocation; or a null pointer if no such file is known.
+ This file is used only on GNU/Linux and other systems
+ that lack the FreeBSD-style sysctl with KERN_BOOTTIME.])
+
#### Choose a window system.
## We leave window_system equal to none if
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index 58be1199345..b23fd5030fa 100644
--- a/nt/inc/ms-w32.h
+++ b/nt/inc/ms-w32.h
@@ -121,6 +121,7 @@ #define HAVE_C99_STRTOLD 1
the output, but that's gross. So this should do; if the file is
not there, the boot time will be returned as zero, and filelock.c
already handles that. */
+#undef BOOT_TIME_FILE
#define BOOT_TIME_FILE "C:/pagefile.sys"
/* ============================================================ */
diff --git a/src/filelock.c b/src/filelock.c
index 66b8fd2ceac..0ad130353f3 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -59,12 +59,6 @@ Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2023 Free Software
#include <utmp.h>
#endif
-/* A file whose last-modified time is just after the most recent boot.
- Define this to be NULL to disable checking for this file. */
-#ifndef BOOT_TIME_FILE
-#define BOOT_TIME_FILE "/var/run/random-seed"
-#endif
-
/* Boot time is not available on Android. */
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
--
2.39.2
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: boot time on Linux
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 9:30 ` Natanael Copa
2 siblings, 0 replies; 17+ messages in thread
From: Bruno Haible @ 2023-08-09 21:06 UTC (permalink / raw)
To: Paul Eggert
Cc: Robert Pluim, bug-gnulib, Pádraig Brady, Sven Joachim, 64937,
Natanael Copa, Po Lu, Emacs Development, Thorsten Kukuk
Paul Eggert wrote:
> This patch does not address the problem for Alpine, nor I suspect for
> Android. I suppose Alpine could use the timestamp of /var/run/utmp (or
> is that /run/utmp?) but I don't know how 'configure' would reliably
> detect it's being built or cross-built for Alpine. I'll cc this to
> Natanael Copa, who does the Alpine ports for Emacs, to see whether he
> can give advice.
For Alpine Linux, in Gnulib, I've used the following approach:
Read the entire contents of /var/run/utmp, and if it contains no entry
with ut_type == BOOT_TIME, look at the time stamp of some files,
in particular /var/run/utmp. It doesn't require a configure test.
Bruno
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
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 9:30 ` Natanael Copa
2 siblings, 1 reply; 17+ messages in thread
From: Po Lu @ 2023-08-09 23:53 UTC (permalink / raw)
To: Paul Eggert
Cc: Bruno Haible, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs Development,
Thorsten Kukuk
Paul Eggert <eggert@cs.ucla.edu> writes:
> [For those cc'ed, the thread's at <https://bugs.gnu.org/64937#142>.]
>
> On 2023-08-09 07:29, Bruno Haible wrote:
>
>> And on Alpine Linux, while /var/run/utmp is empty, its time stamp is
>> essentially the boot time.
>> The approach used by Emacs, namely to look at the time stamp of
>> /var/run/random-seed, is therefore essentially one of the best
>> approaches.
>> It just needs to also look at /var/lib/systemd/random-seed and - on
>> Alpine
>> Linux - /var/run/utmp .
>
> Thanks for looking into this. Clearly Emacs had some catching up to
> do, since it was using a location for the random-seed file that
> current GNU/Linux distros no longer use. To try to fix this I
> installed the attached patch to Emacs master on Savannah.
>
> This patch does not address the problem for Alpine, nor I suspect for
> Android. I suppose Alpine could use the timestamp of /var/run/utmp (or
> is that /run/utmp?) but I don't know how 'configure' would reliably
> detect it's being built or cross-built for Alpine. I'll cc this to
> Natanael Copa, who does the Alpine ports for Emacs, to see whether he
> can give advice.
>
> Also, I don't know how Android records boot time so I'll cc this to Po
> Lu, the main developer for Emacs on Android.
The boot time is off limits to user programs on Android, for security
reasons. It should suffice to undefine BOOT_TIME_FILE there.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-09 23:53 ` Po Lu
@ 2023-08-10 0:14 ` Bruno Haible
2023-08-10 2:14 ` Po Lu
0 siblings, 1 reply; 17+ messages in thread
From: Bruno Haible @ 2023-08-10 0:14 UTC (permalink / raw)
To: Paul Eggert, Po Lu
Cc: Robert Pluim, bug-gnulib, Pádraig Brady, Sven Joachim, 64937,
Natanael Copa, Emacs-devel, Thorsten Kukuk
[-- Attachment #1: Type: text/plain, Size: 645 bytes --]
Po Lu wrote:
> > Also, I don't know how Android records boot time so I'll cc this to Po
> > Lu, the main developer for Emacs on Android.
>
> The boot time is off limits to user programs on Android, for security
> reasons.
No, it isn't. The attached file, when compiled and run under Termux (which
doesn't have particular permissions), prints e.g.:
from clock : 1691616762.476870660 = 2023-08-09 21:32:42.476870660
from sysinfo: 1691616762.329261637 = 2023-08-09 21:32:42.329261637
Note that this uses the kernel's uptime counter, so it will not work well
when the user changes the current time manually. But this is rare on Android.
Bruno
[-- Attachment #2: foo.c --]
[-- Type: text/x-csrc, Size: 2906 bytes --]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/sysinfo.h>
static const char *
as_time_string (time_t tim)
{
struct tm *gmt = gmtime (&tim);
static char timbuf[100];
if (gmt == NULL
|| strftime (timbuf, sizeof (timbuf), "%Y-%m-%d %H:%M:%S", gmt)
== 0)
strcpy (timbuf, "---");
return timbuf;
}
int main ()
{
/* clock() returns the uptime with a resolution of ca. 1 usec. */
struct timespec ts_now;
struct timespec up;
if (clock_gettime (CLOCK_REALTIME, &ts_now) == 0
&& clock_gettime (CLOCK_BOOTTIME, &up) == 0)
{
struct timespec result = ts_now;
if (result.tv_nsec < up.tv_nsec)
{
result.tv_nsec += 1000000000;
result.tv_sec -= 1;
}
result.tv_sec -= up.tv_sec;
result.tv_nsec -= up.tv_nsec;
printf ("from clock : %d.%09d = %s.%09d\n",
(int) result.tv_sec, (int) result.tv_nsec,
as_time_string (result.tv_sec), (int) result.tv_nsec);
}
/* /proc/uptime contains the uptime with a resolution of 0.01 sec. */
FILE *fp = fopen ("/proc/uptime", "re");
if (fp != NULL)
{
char buf[32 + 1];
size_t n = fread (buf, 1, sizeof (buf) - 1, fp);
fclose (fp);
if (n > 0)
{
buf[n] = '\0';
/* buf now contains two values: the uptime and the idle time. */
char *endptr;
double uptime = strtod (buf, &endptr);
if (endptr > buf)
{
struct timespec result;
if (clock_gettime (CLOCK_REALTIME, &result) == 0)
{
time_t uptime_sec = uptime;
struct timespec up =
{
.tv_sec = uptime_sec,
.tv_nsec = (uptime - uptime_sec) * 1e9 + 0.5
};
if (result.tv_nsec < up.tv_nsec)
{
result.tv_nsec += 1000000000;
result.tv_sec -= 1;
}
result.tv_sec -= up.tv_sec;
result.tv_nsec -= up.tv_nsec;
printf ("from /proc : %d.%09d = %s.%09d\n",
(int) result.tv_sec, (int) result.tv_nsec,
as_time_string (result.tv_sec), (int) result.tv_nsec);
}
}
}
}
/* The sysinfo call returns the uptime with a resolution of 1 sec only. */
struct sysinfo info;
if (sysinfo (&info) >= 0)
{
struct timespec result;
if (clock_gettime (CLOCK_REALTIME, &result) == 0)
{
result.tv_sec -= info.uptime;
printf ("from sysinfo: %d.%09d = %s.%09d\n",
(int) result.tv_sec, (int) result.tv_nsec,
as_time_string (result.tv_sec), (int) result.tv_nsec);
}
}
return 0;
}
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 0:14 ` Bruno Haible
@ 2023-08-10 2:14 ` Po Lu
2023-08-10 6:22 ` Paul Eggert
2023-08-10 10:30 ` Bruno Haible
0 siblings, 2 replies; 17+ messages in thread
From: Po Lu @ 2023-08-10 2:14 UTC (permalink / raw)
To: Bruno Haible
Cc: Paul Eggert, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
Bruno Haible <bruno@clisp.org> writes:
> Po Lu wrote:
>> > Also, I don't know how Android records boot time so I'll cc this to Po
>> > Lu, the main developer for Emacs on Android.
>>
>> The boot time is off limits to user programs on Android, for security
>> reasons.
>
> No, it isn't. The attached file, when compiled and run under Termux (which
> doesn't have particular permissions), prints e.g.:
>
> from clock : 1691616762.476870660 = 2023-08-09 21:32:42.476870660
> from sysinfo: 1691616762.329261637 = 2023-08-09 21:32:42.329261637
>
> Note that this uses the kernel's uptime counter, so it will not work well
> when the user changes the current time manually. But this is rare on Android.
This uses the uptime counter (which also results in an SELinux denial
for me, but different Android distributions have SELinux policies of
varying strictness), which cannot establish the precise time the system
started, since time elapses between the read from the uptime counter and
the read from the RTC.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
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
1 sibling, 1 reply; 17+ messages in thread
From: Paul Eggert @ 2023-08-10 6:22 UTC (permalink / raw)
To: Po Lu, Bruno Haible
Cc: Robert Pluim, bug-gnulib, Pádraig Brady, Sven Joachim, 64937,
Natanael Copa, Emacs-devel, Thorsten Kukuk
On 2023-08-09 19:14, Po Lu wrote:
> This uses the uptime counter (which also results in an SELinux denial
> for me, but different Android distributions have SELinux policies of
> varying strictness), which cannot establish the precise time the system
> started
Emacs doesn't need a precise boot time. All it really needs is an
integer that uniquely identifies the current OS boot.
> since time elapses between the read from the uptime counter and
> the read from the RTC.
Emacs allows for up to one second of slop in computing the boot time.
(In other words, it assumes that reboots are at least one second apart.)
So if there are minor errors in computing the boot time it should be OK.
If the errors are greater than one second, though, lock-file may assume
that locks are stale when they're not.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 6:22 ` Paul Eggert
@ 2023-08-10 6:58 ` Po Lu
0 siblings, 0 replies; 17+ messages in thread
From: Po Lu @ 2023-08-10 6:58 UTC (permalink / raw)
To: Paul Eggert
Cc: Bruno Haible, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
Paul Eggert <eggert@cs.ucla.edu> writes:
> On 2023-08-09 19:14, Po Lu wrote:
>> This uses the uptime counter (which also results in an SELinux denial
>> for me, but different Android distributions have SELinux policies of
>> varying strictness), which cannot establish the precise time the system
>> started
>
> Emacs doesn't need a precise boot time. All it really needs is an
> integer that uniquely identifies the current OS boot.
>
>> since time elapses between the read from the uptime counter and
>> the read from the RTC.
>
> Emacs allows for up to one second of slop in computing the boot
> time. (In other words, it assumes that reboots are at least one second
> apart.) So if there are minor errors in computing the boot time it
> should be OK. If the errors are greater than one second, though,
> lock-file may assume that locks are stale when they're not.
OK, but the SELinux problem still stands in the way. There's an uptime
counter in the Settings app though -- I'll try to establish how that
works.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
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 9:30 ` Natanael Copa
2023-08-10 9:38 ` Po Lu
2023-08-10 15:30 ` Bruno Haible
2 siblings, 2 replies; 17+ messages in thread
From: Natanael Copa @ 2023-08-10 9:30 UTC (permalink / raw)
To: Paul Eggert
Cc: Bruno Haible, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Po Lu, Emacs Development, Thorsten Kukuk,
Natanael Copa
[-- Attachment #1: Type: text/plain, Size: 2250 bytes --]
Hi, I had a quick look at the thread, and I have a few comments.
1) it is openrc's bootmisc (
https://github.com/OpenRC/openrc/blob/86efc43d0e0d7569f5d2e7a58b8c461ac9f7dae8/init.d/bootmisc.in#L197)
that creates /var/run/utmp. There is no guarantee that this exists. You
can for example run emacs in a alpine docker container.
2) Even if it does exist, there is no guarantee that the timestamp is
correct. 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).
For emacs' use case I'd say the best solution would be to use uptime from
sysinfo(2) and assume system time is correct (NTP client should be running
at the time emacs is started).
-nc
On Wed, Aug 9, 2023 at 9:31 PM Paul Eggert <eggert@cs.ucla.edu> wrote:
> [For those cc'ed, the thread's at <https://bugs.gnu.org/64937#142>.]
>
> On 2023-08-09 07:29, Bruno Haible wrote:
>
> > And on Alpine Linux, while /var/run/utmp is empty, its time stamp is
> > essentially the boot time.
> >
> > The approach used by Emacs, namely to look at the time stamp of
> > /var/run/random-seed, is therefore essentially one of the best
> approaches.
> > It just needs to also look at /var/lib/systemd/random-seed and - on
> Alpine
> > Linux - /var/run/utmp .
>
> Thanks for looking into this. Clearly Emacs had some catching up to do,
> since it was using a location for the random-seed file that current
> GNU/Linux distros no longer use. To try to fix this I installed the
> attached patch to Emacs master on Savannah.
>
> This patch does not address the problem for Alpine, nor I suspect for
> Android. I suppose Alpine could use the timestamp of /var/run/utmp (or
> is that /run/utmp?) but I don't know how 'configure' would reliably
> detect it's being built or cross-built for Alpine. I'll cc this to
> Natanael Copa, who does the Alpine ports for Emacs, to see whether he
> can give advice.
>
> Also, I don't know how Android records boot time so I'll cc this to Po
> Lu, the main developer for Emacs on Android.
--
Natanael Copa
[-- Attachment #2: Type: text/html, Size: 3086 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
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
1 sibling, 1 reply; 17+ messages in thread
From: Po Lu @ 2023-08-10 9:38 UTC (permalink / raw)
To: Natanael Copa
Cc: Paul Eggert, Bruno Haible, Robert Pluim, bug-gnulib,
Pádraig Brady, Sven Joachim, 64937, Emacs Development,
Thorsten Kukuk, Natanael Copa
Natanael Copa <natanael.copa@gmail.com> writes:
> 2) Even if it does exist, there is no guarantee that the timestamp is
> correct. 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).
If so, doesn't that discount the possibility of deriving the boot time
from the timestamp of any particular file? Since AFAIU these machines
lacking a TOY clock are relatively widespread?
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 9:38 ` Po Lu
@ 2023-08-10 10:05 ` Natanael Copa
0 siblings, 0 replies; 17+ messages in thread
From: Natanael Copa @ 2023-08-10 10:05 UTC (permalink / raw)
To: Po Lu
Cc: Natanael Copa, Paul Eggert, Bruno Haible, Robert Pluim,
bug-gnulib, Pádraig Brady, Sven Joachim, 64937,
Emacs Development, Thorsten Kukuk
On Thu, 10 Aug 2023 17:38:10 +0800
Po Lu <luangruo@yahoo.com> wrote:
> Natanael Copa <natanael.copa@gmail.com> writes:
>
> > 2) Even if it does exist, there is no guarantee that the timestamp is
> > correct. 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).
>
> If so, doesn't that discount the possibility of deriving the boot time
> from the timestamp of any particular file? Since AFAIU these machines
> lacking a TOY clock are relatively widespread?
That was sort of my point. It is better to avoid if possible. In emacs
case I believe it is.
-nc
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 2:14 ` Po Lu
2023-08-10 6:22 ` Paul Eggert
@ 2023-08-10 10:30 ` Bruno Haible
2023-08-10 12:23 ` bug#64937: " Po Lu via GNU coreutils Bug Reports
1 sibling, 1 reply; 17+ messages in thread
From: Bruno Haible @ 2023-08-10 10:30 UTC (permalink / raw)
To: Po Lu
Cc: Paul Eggert, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
[-- Attachment #1: Type: text/plain, Size: 928 bytes --]
I wrote:
> > No, it isn't. The attached file, when compiled and run under Termux (which
> > doesn't have particular permissions), prints e.g.:
> >
> > from clock : 1691616762.476870660 = 2023-08-09 21:32:42.476870660
> > from sysinfo: 1691616762.329261637 = 2023-08-09 21:32:42.329261637
> >
> > Note that this uses the kernel's uptime counter, so it will not work well
> > when the user changes the current time manually. But this is rare on Android.
It works well enough, that I'm adding it to Gnulib, through the attached patch.
Po Lu wrote:
> This uses the uptime counter (which also results in an SELinux denial
> for me, but different Android distributions have SELinux policies of
> varying strictness)
How did you run the program, and which of the two calls (clock_gettime, sysinfo)
failed for you? Maybe it depends not only on the Android version and device,
but also on the permissions required by the app?
Bruno
[-- Attachment #2: 0001-readutmp-Return-a-boot-time-also-on-Android.patch --]
[-- Type: text/x-patch, Size: 9546 bytes --]
From 9db6a91083ecca9c49bd5353c7624c6388f332fb Mon Sep 17 00:00:00 2001
From: Bruno Haible <bruno@clisp.org>
Date: Thu, 10 Aug 2023 07:59:19 +0200
Subject: [PATCH] readutmp: Return a boot time also on Android.
* lib/readutmp.c (get_linux_uptime): New function, extracted from
get_boot_time_uncached.
(read_utmp_from_file): Don't look for file time stamps on Android.
Instead, use get_linux_uptime.
(get_boot_time_uncached): Use get_linux_uptime.
---
ChangeLog | 9 +++
lib/readutmp.c | 196 +++++++++++++++++++++++++++++--------------------
2 files changed, 124 insertions(+), 81 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 3c2256a7b2..b167189c03 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2023-08-10 Bruno Haible <bruno@clisp.org>
+
+ readutmp: Return a boot time also on Android.
+ * lib/readutmp.c (get_linux_uptime): New function, extracted from
+ get_boot_time_uncached.
+ (read_utmp_from_file): Don't look for file time stamps on Android.
+ Instead, use get_linux_uptime.
+ (get_boot_time_uncached): Use get_linux_uptime.
+
2023-08-09 Bruno Haible <bruno@clisp.org>
readutmp: Fix a mistake (regression 2023-08-08).
diff --git a/lib/readutmp.c b/lib/readutmp.c
index ec21f5e16f..b344d8294d 100644
--- a/lib/readutmp.c
+++ b/lib/readutmp.c
@@ -31,11 +31,13 @@
#include <stdlib.h>
#include <stdint.h>
+#if READUTMP_USE_SYSTEMD || defined __ANDROID__
+# include <sys/sysinfo.h>
+# include <time.h>
+#endif
#if READUTMP_USE_SYSTEMD
# include <dirent.h>
-# include <sys/sysinfo.h>
# include <systemd/sd-login.h>
-# include <time.h>
#endif
#include "stat-time.h"
@@ -284,6 +286,60 @@ finish_utmp (struct utmp_alloc a)
return a;
}
+# if READUTMP_USE_SYSTEMD || defined __ANDROID__
+
+/* Store the uptime counter, as managed by the Linux kernel, in *P_UPTIME.
+ Return 0 upon success, -1 upon failure. */
+static int
+get_linux_uptime (struct timespec *p_uptime)
+{
+ /* The clock_gettime facility returns the uptime with a resolution of 1 µsec.
+ It is available with glibc >= 2.14. In glibc < 2.17 it required linking
+ with librt. */
+# if (__GLIBC__ + (__GLIBC_MINOR__ >= 17) > 2) || defined __ANDROID__
+ if (clock_gettime (CLOCK_BOOTTIME, p_uptime) >= 0)
+ return 0;
+# endif
+
+ /* /proc/uptime contains the uptime with a resolution of 0.01 sec.
+ But it does not have read permissions on Android. */
+# if !defined __ANDROID__
+ FILE *fp = fopen ("/proc/uptime", "re");
+ if (fp != NULL)
+ {
+ char buf[32 + 1];
+ size_t n = fread (buf, 1, sizeof (buf) - 1, fp);
+ fclose (fp);
+ if (n > 0)
+ {
+ buf[n] = '\0';
+ /* buf now contains two values: the uptime and the idle time. */
+ char *endptr;
+ double uptime = strtod (buf, &endptr);
+ if (endptr > buf)
+ {
+ p_uptime->tv_sec = (time_t) uptime;
+ p_uptime->tv_nsec = (uptime - p_uptime->tv_sec) * 1e9 + 0.5;
+ return 0;
+ }
+ }
+ }
+# endif
+
+ /* The sysinfo call returns the uptime with a resolution of 1 sec only. */
+ struct sysinfo info;
+ if (sysinfo (&info) >= 0)
+ {
+ p_uptime->tv_sec = info.uptime;
+ p_uptime->tv_nsec = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+# endif
+
# if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION && !HAVE_DECL_GETUTENT
struct utmp *getutent (void);
# endif
@@ -391,7 +447,7 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
END_UTMP_ENT ();
-# if defined __linux__
+# 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. */
@@ -436,6 +492,37 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
}
# endif
+# if defined __ANDROID__
+ /* On Android, there is no /var, and normal processes don't have access
+ to system files. Therefore use the kernel's uptime counter, although
+ it produces wrong values after the date has been bumped in the running
+ system. */
+ {
+ struct timespec uptime;
+ if (get_linux_uptime (&uptime) >= 0)
+ {
+ struct timespec result;
+ if (clock_gettime (CLOCK_REALTIME, &result) >= 0)
+ {
+ if (result.tv_nsec < uptime.tv_nsec)
+ {
+ result.tv_nsec += 1000000000;
+ result.tv_sec -= 1;
+ }
+ result.tv_sec -= uptime.tv_sec;
+ result.tv_nsec -= uptime.tv_nsec;
+ struct timespec boot_time = result;
+ a = add_utmp (a, options,
+ "reboot", strlen ("reboot"),
+ "", 0,
+ "", 0,
+ "", 0,
+ 0, BOOT_TIME, boot_time, 0, 0, 0);
+ }
+ }
+ }
+# endif
+
# else /* old FreeBSD, OpenBSD, HP-UX */
FILE *f = fopen (file, "re");
@@ -522,7 +609,7 @@ read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
a = add_utmp (a, options,
"reboot", strlen ("reboot"),
"", 0,
- "", strlen (""),
+ "", 0,
"", 0,
0, BOOT_TIME, boot_time, 0, 0, 0);
break;
@@ -562,87 +649,34 @@ get_boot_time_uncached (void)
free (utmp);
}
- /* The following approaches are only usable as fallbacks, because they are
- all of the form
+ /* The following approach is only usable as a fallback, because it is of
+ the form
boot_time = (time now) - (kernel's ktime_get_boottime[_ts64] ())
- and therefore produce wrong values after the date has been bumped in the
+ and therefore 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. */
-
- /* The clock_gettime facility returns the uptime with a resolution of 1 µsec.
- It is available with glibc >= 2.14. In glibc < 2.17 it required linking
- with librt. */
-# if __GLIBC__ + (__GLIBC_MINOR__ >= 17) > 2
- struct timespec up;
- if (clock_gettime (CLOCK_BOOTTIME, &up) >= 0)
- {
- struct timespec result;
- /* equivalent to:
- if (clock_gettime (CLOCK_REALTIME, &result) >= 0)
- */
- if (timespec_get (&result, TIME_UTC) >= 0)
- {
- if (result.tv_nsec < up.tv_nsec)
- {
- result.tv_nsec += 1000000000;
- result.tv_sec -= 1;
- }
- result.tv_sec -= up.tv_sec;
- result.tv_nsec -= up.tv_nsec;
- return result;
- }
- }
-# endif
-
- /* /proc/uptime contains the uptime with a resolution of 0.01 sec. */
- FILE *fp = fopen ("/proc/uptime", "re");
- if (fp != NULL)
- {
- char buf[32 + 1];
- size_t n = fread (buf, 1, sizeof (buf) - 1, fp);
- fclose (fp);
- if (n > 0)
- {
- buf[n] = '\0';
- /* buf now contains two values: the uptime and the idle time. */
- char *endptr;
- double uptime = strtod (buf, &endptr);
- if (endptr > buf)
- {
- struct timespec result;
- if (0 <= timespec_get (&result, TIME_UTC))
- {
- time_t uptime_sec = uptime;
- struct timespec up =
- {
- .tv_sec = uptime_sec,
- .tv_nsec = (uptime - uptime_sec) * 1e9 + 0.5
- };
- if (result.tv_nsec < up.tv_nsec)
- {
- result.tv_nsec += 1000000000;
- result.tv_sec -= 1;
- }
- result.tv_sec -= up.tv_sec;
- result.tv_nsec -= up.tv_nsec;
- return result;
- }
- }
- }
- }
-
- /* The sysinfo call returns the uptime with a resolution of 1 sec only. */
- struct sysinfo info;
- if (sysinfo (&info) >= 0)
- {
- struct timespec result;
- if (0 <= timespec_get (&result, TIME_UTC))
- {
- result.tv_sec -= info.uptime;
- return result;
- }
- }
+ {
+ struct timespec uptime;
+ if (get_linux_uptime (&uptime) >= 0)
+ {
+ struct timespec result;
+ /* equivalent to:
+ if (clock_gettime (CLOCK_REALTIME, &result) >= 0)
+ */
+ if (timespec_get (&result, TIME_UTC) >= 0)
+ {
+ if (result.tv_nsec < uptime.tv_nsec)
+ {
+ result.tv_nsec += 1000000000;
+ result.tv_sec -= 1;
+ }
+ result.tv_sec -= uptime.tv_sec;
+ result.tv_nsec -= uptime.tv_nsec;
+ return result;
+ }
+ }
+ }
/* We shouldn't get here. */
return (struct timespec) {0};
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* bug#64937: boot time on Linux
2023-08-10 10:30 ` Bruno Haible
@ 2023-08-10 12:23 ` Po Lu via GNU coreutils Bug Reports
2023-08-10 12:25 ` Bruno Haible
0 siblings, 1 reply; 17+ messages in thread
From: Po Lu via GNU coreutils Bug Reports @ 2023-08-10 12:23 UTC (permalink / raw)
To: Bruno Haible
Cc: Paul Eggert, bug-gnulib, Thorsten Kukuk, Robert Pluim,
Emacs-devel, Natanael Copa, Pádraig Brady, Sven Joachim,
64937
Bruno Haible <bruno@clisp.org> writes:
> I wrote:
>> > No, it isn't. The attached file, when compiled and run under Termux (which
>> > doesn't have particular permissions), prints e.g.:
>> >
>> > from clock : 1691616762.476870660 = 2023-08-09 21:32:42.476870660
>> > from sysinfo: 1691616762.329261637 = 2023-08-09 21:32:42.329261637
>> >
>> > Note that this uses the kernel's uptime counter, so it will not work well
>> > when the user changes the current time manually. But this is rare on Android.
>
> It works well enough, that I'm adding it to Gnulib, through the attached patch.
>
> Po Lu wrote:
>> This uses the uptime counter (which also results in an SELinux denial
>> for me, but different Android distributions have SELinux policies of
>> varying strictness)
>
> How did you run the program, and which of the two calls (clock_gettime, sysinfo)
> failed for you? Maybe it depends not only on the Android version and device,
> but also on the permissions required by the app?
Both clock_gettime (CLOCK_BOOTIME, ... sysinfo fail with AVC denial
errors and errno set to EACCESS.
I think it is a bit of a stretch to ascribe this to an app's requested
permissions, though, since none of the listed permissions available to
user programs seems pertinent.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
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
0 siblings, 1 reply; 17+ messages in thread
From: Bruno Haible @ 2023-08-10 12:25 UTC (permalink / raw)
To: Po Lu
Cc: Paul Eggert, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
Po Lu wrote:
> Both clock_gettime (CLOCK_BOOTIME, ... sysinfo fail with AVC denial
> errors and errno set to EACCESS.
Was this inside Termux, or inside the Emacs app?
Bruno
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 12:25 ` Bruno Haible
@ 2023-08-10 13:04 ` Po Lu
2023-08-10 14:12 ` Bruno Haible
0 siblings, 1 reply; 17+ messages in thread
From: Po Lu @ 2023-08-10 13:04 UTC (permalink / raw)
To: Bruno Haible
Cc: Paul Eggert, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
Bruno Haible <bruno@clisp.org> writes:
> Po Lu wrote:
>> Both clock_gettime (CLOCK_BOOTIME, ... sysinfo fail with AVC denial
>> errors and errno set to EACCESS.
>
> Was this inside Termux, or inside the Emacs app?
Inside the Emacs app. I'll try Termux soon: maybe the target SDK
version is the culprit.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 13:04 ` Po Lu
@ 2023-08-10 14:12 ` Bruno Haible
2023-08-11 8:27 ` Po Lu
0 siblings, 1 reply; 17+ messages in thread
From: Bruno Haible @ 2023-08-10 14:12 UTC (permalink / raw)
To: Po Lu
Cc: Paul Eggert, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
Po Lu wrote:
> >> Both clock_gettime (CLOCK_BOOTIME, ... sysinfo fail with AVC denial
> >> errors and errno set to EACCESS.
> >
> > Was this inside Termux, or inside the Emacs app?
>
> Inside the Emacs app.
Emacs does not have the following in AndroidManifest.xml, which Termux has:
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.DUMP"/>
Maybe one of these makes the difference?
Bruno
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 9:30 ` Natanael Copa
2023-08-10 9:38 ` Po Lu
@ 2023-08-10 15:30 ` Bruno Haible
1 sibling, 0 replies; 17+ messages in thread
From: Bruno Haible @ 2023-08-10 15:30 UTC (permalink / raw)
To: Paul Eggert, Natanael Copa
Cc: Robert Pluim, bug-gnulib, Pádraig Brady, Sven Joachim, 64937,
Po Lu, Emacs Development, Thorsten Kukuk, Natanael Copa
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 */
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: boot time on Linux
2023-08-10 14:12 ` Bruno Haible
@ 2023-08-11 8:27 ` Po Lu
0 siblings, 0 replies; 17+ messages in thread
From: Po Lu @ 2023-08-11 8:27 UTC (permalink / raw)
To: Bruno Haible
Cc: Paul Eggert, Robert Pluim, bug-gnulib, Pádraig Brady,
Sven Joachim, 64937, Natanael Copa, Emacs-devel, Thorsten Kukuk
Bruno Haible <bruno@clisp.org> writes:
> Po Lu wrote:
>> >> Both clock_gettime (CLOCK_BOOTIME, ... sysinfo fail with AVC denial
>> >> errors and errno set to EACCESS.
>> >
>> > Was this inside Termux, or inside the Emacs app?
>>
>> Inside the Emacs app.
>
> Emacs does not have the following in AndroidManifest.xml, which Termux has:
> <uses-permission android:name="android.permission.READ_LOGS"/>
> <uses-permission android:name="android.permission.DUMP"/>
>
> Maybe one of these makes the difference?
>
> Bruno
Alas, no. The test program still doesn't work, either in the Termux app
or in the Emacs app with those two permissions listed.
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2023-08-11 8:27 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[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
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).