unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: boot-time: straighten code
       [not found] <4536176.VaOIPsP7d9@nimes>
@ 2023-08-13  2:49 ` Paul Eggert
  2023-08-13  3:26   ` Po Lu
                     ` (2 more replies)
  0 siblings, 3 replies; 24+ messages in thread
From: Paul Eggert @ 2023-08-13  2:49 UTC (permalink / raw)
  To: Bruno Haible; +Cc: bug-gnulib, Emacs Development

[-- Attachment #1: Type: text/plain, Size: 927 bytes --]

On 2023-08-11 14:49, Bruno Haible wrote:
> Paul: With this simplification, you may consider using the 'boot-time' module
> in Emacs. I bet that it produces a better result than Emacs' src/filelock.c
> on many platforms. (I haven't tested it, but I could test it if you give me
> a manual testing recipe.)

Thanks for doing all that. I installed the attached patch into Emacs 
master, which you should be able to test via:

	git clone https://git.savannah.gnu.org/git/emacs.git
	cd emacs
	./autogen.sh
	./configure
	make
	src/emacs

Please give it a try, especially on any MS-Windows platform you happen 
to have. I have tested only on Ubuntu 23.04 so far.

A simple way to test is to use Emacs to start editing a file (without 
saving) and then inspect the symbolic link .#* that Emacs uses as a lock 
file. The trailing digits of that link's contents should be the boot 
time. These symlinks are Emacs's only use of boot time.

[-- Attachment #2: 0001-Improve-boot-time-gathering.patch --]
[-- Type: text/x-patch, Size: 51156 bytes --]

From 5e736ca6ccfa131736ab0b3a298de2cb319e7dfb Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sat, 12 Aug 2023 19:39:11 -0700
Subject: [PATCH] Improve boot-time gathering
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Simplify Emacs proper by using Gnulib’s boot-time module
instead of doing it all by hand.  This should port Emacs
better to obscurish hosts, as Bruno Haible has merged the
best of Emacs’s and Gnulib’s boot-time gathering.
* lib/boot-time-aux.h, lib/boot-time.c, lib/boot-time.h:
* lib/readutmp.h, m4/readutmp.m4: New files, copied from Gnulib.
* admin/merge-gnulib (GNULIB_MODULES): Add boot-time.
* configure.ac: Do not check for utmp.h;
the boot-time module now does this.
(BOOT_TIME_FILE): Remove; no longer used.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
* src/filelock.c [__FreeBSD__]: Do not include <sys/sysctl.h>.
[HAVE_UTMP_H]: Do not include utmp.h.
Include boot-time instead: boot-time does the work now.
(BOOT_TIME) [HAVE_ANDROID && !ANDROID_STUBIFY]: Don’t undef.
(WTMP_FILE): Don’t define.
(boot_time, boot_time_initialized, get_boot_time_1, get_boot_time):
Remove.
(get_boot_sec): New function that simply calls Gnulib get_boot_time.
(lock_file_1, current_lock_owner): Use get_boot_sec instead
of get_boot_time.
---
 admin/merge-gnulib  |   2 +-
 configure.ac        |  47 +------
 lib/boot-time-aux.h | 315 ++++++++++++++++++++++++++++++++++++++++++
 lib/boot-time.c     | 285 ++++++++++++++++++++++++++++++++++++++
 lib/boot-time.h     |  44 ++++++
 lib/gnulib.mk.in    |  11 ++
 lib/readutmp.h      | 325 ++++++++++++++++++++++++++++++++++++++++++++
 m4/gnulib-comp.m4   |   7 +
 m4/readutmp.m4      | 117 ++++++++++++++++
 src/filelock.c      | 172 ++---------------------
 10 files changed, 1116 insertions(+), 209 deletions(-)
 create mode 100644 lib/boot-time-aux.h
 create mode 100644 lib/boot-time.c
 create mode 100644 lib/boot-time.h
 create mode 100644 lib/readutmp.h
 create mode 100644 m4/readutmp.m4

diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index 2a713beb01a..fe88d1106ae 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -26,7 +26,7 @@
 GNULIB_URL=https://git.savannah.gnu.org/git/gnulib.git
 
 GNULIB_MODULES='
-  alignasof alloca-opt binary-io byteswap c-ctype c-strcase
+  alignasof alloca-opt binary-io boot-time byteswap c-ctype c-strcase
   canonicalize-lgpl
   careadlinkat close-stream copy-file-range
   count-leading-zeros count-one-bits count-trailing-zeros
diff --git a/configure.ac b/configure.ac
index 35dfed247d0..0234a82b92f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2539,7 +2539,7 @@ AC_DEFUN
   sys/sysinfo.h
   coff.h pty.h
   sys/resource.h
-  sys/utsname.h pwd.h utmp.h util.h
+  sys/utsname.h pwd.h util.h
   sanitizer/lsan_interface.h
   sanitizer/asan_interface.h
   sanitizer/common_interface_defs.h])
@@ -2635,51 +2635,6 @@ AC_DEFUN
 fi
 AC_SUBST([AUTO_DEPEND])
 
-BOOT_TIME_FILE=
-AC_CACHE_CHECK([for old but post-boot file],
-  [emacs_cv_boot_time_file],
-  [AS_CASE([$opsys],
-     [gnu-linux],
-     [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])],
-     # This isn't perfect, as some systems might have the page file in
-     # another place.  Also, I suspect that the time stamp of that
-     # file might also change when Windows enlarges the file due to
-     # insufficient VM.  Still, this seems to be the most reliable
-     # way; the alternative (of using GetSystemTimes) won't work on
-     # laptops that hibernate, because the system clock is stopped
-     # then.  Other possibility would be to run "net statistics
-     # workstation" and parse 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.
-     [mingw32], [emacs_cv_boot_time_file=C:/pagefile.sys],
-     [*], [emacs_cv_boot_time_file=not-needed])])
-
-AS_CASE([$emacs_cv_boot_time_file],
-  [/*|*:*], [BOOT_TIME_FILE=\"$emacs_cv_boot_time_file\"],
-  [not-needed], [BOOT_TIME_FILE=],
-  [# Guess systemd if unknown.
-   # If guess is wrong, Emacs falls back on something else.
-   BOOT_TIME_FILE=\"/var/lib/systemd/random-seed\"])
-
-AS_IF([test -n "$BOOT_TIME_FILE"],
-  [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/lib/boot-time-aux.h b/lib/boot-time-aux.h
new file mode 100644
index 00000000000..348611fc85c
--- /dev/null
+++ b/lib/boot-time-aux.h
@@ -0,0 +1,315 @@
+/* Auxiliary functions for determining the time when the machine last booted.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation, either version 3 of the License,
+   or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>.  */
+
+#define SIZEOF(a) (sizeof(a)/sizeof(a[0]))
+
+#if defined __linux__ || defined __ANDROID__
+
+/* Store the uptime counter, as managed by the Linux kernel, in *P_UPTIME.
+   Return 0 upon success, -1 upon failure.  */
+_GL_ATTRIBUTE_MAYBE_UNUSED
+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, Android, or musl libc.
+     In glibc < 2.17 it required linking with librt.  */
+# if !defined __GLIBC__ || 2 < __GLIBC__ + (17 <= __GLIBC_MINOR__)
+  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.  */
+          time_t s = 0;
+          char *p;
+          for (p = buf; '0' <= *p && *p <= '9'; p++)
+            s = 10 * s + (*p - '0');
+          if (buf < p)
+            {
+              long ns = 0;
+              if (*p++ == '.')
+                for (int i = 0; i < 9; i++)
+                  ns = 10 * ns + ('0' <= *p && *p <= '9' ? *p++ - '0' : 0);
+              p_uptime->tv_sec = s;
+              p_uptime->tv_nsec = ns;
+              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 defined __linux__ && !defined __ANDROID__
+
+static int
+get_linux_boot_time_fallback (struct timespec *p_boot_time)
+{
+  /* On Alpine Linux, UTMP_FILE is not filled.  It is always empty.
+     So, get the time stamp of a file that gets touched only during the
+     boot process.  */
+
+  const char * const boot_touched_files[] =
+    {
+      "/var/lib/systemd/random-seed", /* seen on distros with systemd */
+      "/var/run/utmp",                /* seen on distros with OpenRC */
+      "/var/lib/random-seed"          /* seen on older distros */
+    };
+  for (idx_t i = 0; i < SIZEOF (boot_touched_files); i++)
+    {
+      const char *filename = boot_touched_files[i];
+      struct stat statbuf;
+      if (stat (filename, &statbuf) >= 0)
+        {
+          *p_boot_time = get_stat_mtime (&statbuf);
+          return 0;
+        }
+    }
+  return -1;
+}
+
+/* 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 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_linux_boot_time_final_fallback (struct timespec *p_boot_time)
+{
+  struct timespec uptime;
+  if (get_linux_uptime (&uptime) >= 0)
+    {
+      struct timespec result;
+# if !defined __GLIBC__ || 2 < __GLIBC__ + (16 <= __GLIBC_MINOR__)
+      /* Better than:
+      if (0 <= clock_gettime (CLOCK_REALTIME, &result))
+         because timespec_get does not need -lrt in glibc 2.16.
+      */
+      if (! timespec_get (&result, TIME_UTC))
+        return -1;
+#  else
+      /* Fall back on lower-res approach that does not need -lrt.
+         This is good enough; on these hosts UPTIME is even lower-res.  */
+      struct timeval tv;
+      int r = gettimeofday (&tv, NULL);
+      if (r < 0)
+        return r;
+      result.tv_sec = tv.tv_sec;
+      result.tv_nsec = tv.tv_usec * 1000;
+#  endif
+
+      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;
+      *p_boot_time = result;
+      return 0;
+    }
+  return -1;
+}
+
+#endif
+
+#if defined __ANDROID__
+
+static int
+get_android_boot_time (struct timespec *p_boot_time)
+{
+  /* 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;
+          *p_boot_time = result;
+          return 0;
+        }
+    }
+  return -1;
+}
+
+#endif
+
+#if defined __OpenBSD__
+
+static int
+get_openbsd_boot_time (struct timespec *p_boot_time)
+{
+  /* On OpenBSD, UTMP_FILE is not filled.  It contains only dummy entries.
+     So, get the time stamp of a file that gets touched only during the
+     boot process.  */
+  const char * const boot_touched_files[] =
+    {
+      "/var/db/host.random",
+      "/var/run/utmp"
+    };
+  for (idx_t i = 0; i < SIZEOF (boot_touched_files); i++)
+    {
+      const char *filename = boot_touched_files[i];
+      struct stat statbuf;
+      if (stat (filename, &statbuf) >= 0)
+        {
+          *p_boot_time = get_stat_mtime (&statbuf);
+          return 0;
+        }
+    }
+  return -1;
+}
+
+#endif
+
+#if HAVE_SYS_SYSCTL_H && HAVE_SYSCTL \
+    && defined CTL_KERN && defined KERN_BOOTTIME \
+    && !defined __minix
+/* macOS, FreeBSD, GNU/kFreeBSD, NetBSD, OpenBSD */
+/* On Minix 3.3 this sysctl produces garbage results.  Therefore avoid it.  */
+
+/* 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_bsd_boot_time_final_fallback (struct timespec *p_boot_time)
+{
+  static int request[2] = { CTL_KERN, KERN_BOOTTIME };
+  struct timeval result;
+  size_t result_len = sizeof result;
+
+  if (sysctl (request, 2, &result, &result_len, NULL, 0) >= 0)
+    {
+      p_boot_time->tv_sec = result.tv_sec;
+      p_boot_time->tv_nsec = result.tv_usec * 1000;
+      return 0;
+    }
+  return -1;
+}
+
+#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
+get_windows_boot_time (struct timespec *p_boot_time)
+{
+  /* On Cygwin, /var/run/utmp is empty.
+     On native Windows, <utmpx.h> and <utmp.h> don't exist.
+     Instead, on Windows, the boot time can be retrieved by looking at the
+     time stamp of a file that (normally) gets touched only during the boot
+     process, namely C:\pagefile.sys.  */
+  const char * const boot_touched_file =
+    #if defined __CYGWIN__ && !defined _WIN32
+    "/cygdrive/c/pagefile.sys"
+    #else
+    "C:\\pagefile.sys"
+    #endif
+    ;
+  struct stat statbuf;
+  if (stat (boot_touched_file, &statbuf) >= 0)
+    {
+      *p_boot_time = get_stat_mtime (&statbuf);
+      return 0;
+    }
+  return -1;
+}
+
+#endif
diff --git a/lib/boot-time.c b/lib/boot-time.c
new file mode 100644
index 00000000000..d813bfa5825
--- /dev/null
+++ b/lib/boot-time.c
@@ -0,0 +1,285 @@
+/* Determine the time when the machine last booted.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation, either version 3 of the License,
+   or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "boot-time.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined __linux__ || defined __ANDROID__
+# include <sys/sysinfo.h>
+# include <time.h>
+#endif
+
+#if HAVE_SYS_SYSCTL_H && !defined __minix
+# if HAVE_SYS_PARAM_H
+#  include <sys/param.h>
+# endif
+# include <sys/sysctl.h>
+#endif
+
+#if HAVE_OS_H
+# include <OS.h>
+#endif
+
+#include "idx.h"
+#include "readutmp.h"
+#include "stat-time.h"
+
+/* Each of the FILE streams in this file is only used in a single thread.  */
+#include "unlocked-io.h"
+
+/* Some helper functions.  */
+#include "boot-time-aux.h"
+
+/* The following macros describe the 'struct UTMP_STRUCT_NAME',
+   *not* 'struct gl_utmp'.  */
+#undef UT_USER
+
+/* Accessor macro for the member named ut_user or ut_name.  */
+#if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_NAME \
+     : HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_NAME)
+# define UT_USER(UT) ((UT)->ut_name)
+#else
+# define UT_USER(UT) ((UT)->ut_user)
+#endif
+
+#if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION && !HAVE_DECL_GETUTENT
+struct utmp *getutent (void);
+#endif
+
+#if defined __linux__ || HAVE_UTMPX_H || HAVE_UTMP_H || defined __CYGWIN__ || defined _WIN32
+
+static int
+get_boot_time_uncached (struct timespec *p_boot_time)
+{
+  struct timespec found_boot_time = {0};
+
+# if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE)
+
+  /* Try to find the boot time in the /var/run/utmp file.  */
+
+#  if defined UTMP_NAME_FUNCTION /* glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, IRIX, Solaris, Cygwin, Android */
+
+  /* Ignore the return value for now.
+     Solaris' utmpname returns 1 upon success -- which is contrary
+     to what the GNU libc version does.  In addition, older GNU libc
+     versions are actually void.   */
+  UTMP_NAME_FUNCTION ((char *) UTMP_FILE);
+
+  SET_UTMP_ENT ();
+
+#   if (defined __linux__ && !defined __ANDROID__) || defined __minix
+  /* Timestamp of the "runlevel" entry, if any.  */
+  struct timespec runlevel_ts = {0};
+#   endif
+
+  void const *entry;
+
+  while ((entry = GET_UTMP_ENT ()) != NULL)
+    {
+      struct UTMP_STRUCT_NAME const *ut = (struct UTMP_STRUCT_NAME const *) entry;
+
+      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
+
+      if (ut->ut_type == BOOT_TIME)
+        found_boot_time = ts;
+
+#   if defined __linux__ && !defined __ANDROID__
+      if (memcmp (UT_USER (ut), "runlevel", strlen ("runlevel") + 1) == 0
+          && memcmp (ut->ut_line, "~", strlen ("~") + 1) == 0)
+        runlevel_ts = ts;
+#   endif
+#   if defined __minix
+      if (UT_USER (ut)[0] == '\0'
+          && memcmp (ut->ut_line, "run-level ", strlen ("run-level ")) == 0)
+        runlevel_ts = ts;
+#   endif
+    }
+
+  END_UTMP_ENT ();
+
+#   if defined __linux__ && !defined __ANDROID__
+  /* 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, get the time from the "runlevel" entry.  */
+
+  /* Workaround for Raspbian:  */
+  if (found_boot_time.tv_sec <= 60 && runlevel_ts.tv_sec != 0)
+    found_boot_time = runlevel_ts;
+  if (found_boot_time.tv_sec == 0)
+    {
+      /* Workaround for Alpine Linux:  */
+      get_linux_boot_time_fallback (&found_boot_time);
+    }
+#   endif
+
+#   if defined __ANDROID__
+  if (found_boot_time.tv_sec == 0)
+    {
+      /* Workaround for Android:  */
+      get_android_boot_time (&found_boot_time);
+    }
+#   endif
+
+#   if defined __minix
+  /* On Minix, during boot,
+       1. an entry gets written into /var/run/utmp, with ut_type = BOOT_TIME,
+          ut_user = "", ut_line = "system boot", time = 1970-01-01 00:00:00,
+       2. an entry gets written into /var/run/utmp, with
+          ut_user = "", ut_line = "run-level m", time = correct value.
+     In this case, copy the time from the "run-level m" entry to the
+     "system boot" entry.  */
+  if (found_boot_time.tv_sec <= 60 && runlevel_ts.tv_sec != 0)
+    found_boot_time = runlevel_ts;
+#   endif
+
+#  else /* HP-UX, Haiku */
+
+  FILE *f = fopen (UTMP_FILE, "re");
+
+  if (f != NULL)
+    {
+      for (;;)
+        {
+          struct UTMP_STRUCT_NAME ut;
+
+          if (fread (&ut, sizeof ut, 1, f) == 0)
+            break;
+
+          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
+
+          if (ut.ut_type == BOOT_TIME)
+            found_boot_time = ts;
+        }
+
+      fclose (f);
+    }
+
+#  endif
+
+#  if defined __linux__ && !defined __ANDROID__
+  if (found_boot_time.tv_sec == 0)
+    {
+      get_linux_boot_time_final_fallback (&found_boot_time);
+    }
+#  endif
+
+# else /* old FreeBSD, OpenBSD, native Windows */
+
+#  if defined __OpenBSD__
+  /* Workaround for OpenBSD:  */
+  get_openbsd_boot_time (&found_boot_time);
+#  endif
+
+# endif
+
+# if HAVE_SYS_SYSCTL_H && HAVE_SYSCTL \
+     && defined CTL_KERN && defined KERN_BOOTTIME \
+     && !defined __minix
+  if (found_boot_time.tv_sec == 0)
+    {
+      get_bsd_boot_time_final_fallback (&found_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)
+    {
+      /* Workaround for Windows:  */
+      get_windows_boot_time (&found_boot_time);
+    }
+# endif
+
+  if (found_boot_time.tv_sec != 0)
+    {
+      *p_boot_time = found_boot_time;
+      return 0;
+    }
+  else
+    return -1;
+}
+
+int
+get_boot_time (struct timespec *p_boot_time)
+{
+  /* Cache the result from get_boot_time_uncached.  */
+  static int volatile cached_result = -1;
+  static struct timespec volatile cached_boot_time;
+
+  if (cached_result < 0)
+    {
+      struct timespec boot_time;
+      int result = get_boot_time_uncached (&boot_time);
+      cached_boot_time = boot_time;
+      cached_result = result;
+    }
+
+  if (cached_result == 0)
+    {
+      *p_boot_time = cached_boot_time;
+      return 0;
+    }
+  else
+    return -1;
+}
+
+#else
+
+int
+get_boot_time (struct timespec *p_boot_time)
+{
+  return -1;
+}
+
+#endif
diff --git a/lib/boot-time.h b/lib/boot-time.h
new file mode 100644
index 00000000000..401e854adbb
--- /dev/null
+++ b/lib/boot-time.h
@@ -0,0 +1,44 @@
+/* Determine the time when the machine last booted.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation, either version 3 of the License,
+   or (at your option) any later version.
+
+   This file is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>.  */
+
+#ifndef _BOOT_TIME_H
+#define _BOOT_TIME_H
+
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Store the approximate time when the machine last booted in *P_BOOT_TIME,
+   and return 0.  If it cannot be determined, return -1.
+
+   This function is not multithread-safe, since on many platforms it
+   invokes the functions setutxent, getutxent, endutxent.  These
+   functions are needed because they may lock FILE (so that we don't
+   read garbage when a concurrent process writes to FILE), but their
+   drawback is that they have a common global state.  */
+extern int get_boot_time (struct timespec *p_boot_time);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BOOT_TIME_H */
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 785bdc70c5c..3b33f39f73b 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -76,6 +76,7 @@
 #  alignasof \
 #  alloca-opt \
 #  binary-io \
+#  boot-time \
 #  byteswap \
 #  c-ctype \
 #  c-strcase \
@@ -1601,6 +1602,16 @@ libgnu_a_SOURCES += binary-io.h binary-io.c
 endif
 ## end   gnulib module binary-io
 
+## begin gnulib module boot-time
+ifeq (,$(OMIT_GNULIB_MODULE_boot-time))
+
+libgnu_a_SOURCES += boot-time.c
+
+EXTRA_DIST += boot-time-aux.h boot-time.h readutmp.h
+
+endif
+## end   gnulib module boot-time
+
 ## begin gnulib module byteswap
 ifeq (,$(OMIT_GNULIB_MODULE_byteswap))
 
diff --git a/lib/readutmp.h b/lib/readutmp.h
new file mode 100644
index 00000000000..1cf588d265b
--- /dev/null
+++ b/lib/readutmp.h
@@ -0,0 +1,325 @@
+/* Declarations for GNU's read utmp module.
+
+   Copyright (C) 1992-2007, 2009-2023 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by jla; revised by djm */
+
+#ifndef __READUTMP_H__
+#define __READUTMP_H__
+
+/* This file uses _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_RETURNS_NONNULL,
+   HAVE_UTMP_H, HAVE_UTMPX_H, HAVE_STRUCT_UTMP_*, HAVE_STRUCT_UTMPX_*,
+   HAVE_UTMPNAME, HAVE_UTMPXNAME.  */
+#if !_GL_CONFIG_H_INCLUDED
+# error "Please include config.h first."
+#endif
+
+#include "idx.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+
+/* AIX 4.3.3 has both utmp.h and utmpx.h, but only struct utmp
+   has the ut_exit member.  */
+#if (HAVE_UTMPX_H && HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_EXIT \
+     && ! HAVE_STRUCT_UTMPX_UT_EXIT)
+# undef HAVE_UTMPX_H
+#endif
+
+/* HPUX 10.20 needs utmp.h, for the definition of e.g., UTMP_FILE.  */
+#if HAVE_UTMP_H
+# include <utmp.h>
+#endif
+
+/* Needed for BOOT_TIME and USER_PROCESS.  */
+#if HAVE_UTMPX_H
+# if defined _THREAD_SAFE && defined UTMP_DATA_INIT
+    /* When including both utmp.h and utmpx.h on AIX 4.3, with _THREAD_SAFE
+       defined, work around the duplicate struct utmp_data declaration.  */
+#  define utmp_data gl_aix_4_3_workaround_utmp_data
+# endif
+# include <utmpx.h>
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Type of entries returned by read_utmp on all platforms.  */
+struct gl_utmp
+{
+  /* All 'char *' here are of arbitrary length and point to storage
+     with lifetime equal to that of this struct.  */
+  char *ut_user;                /* User name */
+  char *ut_id;                  /* Session ID */
+  char *ut_line;                /* seat / device */
+  char *ut_host;                /* for remote sessions: user@host or host,
+                                   for local sessions: the X11 display :N */
+  struct timespec ut_ts;        /* time */
+  pid_t ut_pid;                 /* process ID of ? */
+  pid_t ut_session;             /* process ID of session leader */
+  short ut_type;                /* BOOT_TIME, USER_PROCESS, or other */
+  struct { int e_termination; int e_exit; } ut_exit;
+};
+
+/* The following types, macros, and constants describe the 'struct gl_utmp'.  */
+#define UT_USER(UT) ((UT)->ut_user)
+#define UT_TIME_MEMBER(UT) ((UT)->ut_ts.tv_sec)
+#define UT_PID(UT) ((UT)->ut_pid)
+#define UT_TYPE_EQ(UT, V) ((UT)->ut_type == (V))
+#define UT_TYPE_NOT_DEFINED 0
+#define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.e_termination)
+#define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.e_exit)
+
+/* Type of entry returned by read_utmp().  */
+typedef struct gl_utmp STRUCT_UTMP;
+
+/* Size of the UT_USER (ut) member, or -1 if unbounded.  */
+enum { UT_USER_SIZE = -1 };
+
+/* Size of the ut->ut_id member, or -1 if unbounded.  */
+enum { UT_ID_SIZE = -1 };
+
+/* Size of the ut->ut_line member, or -1 if unbounded.  */
+enum { UT_LINE_SIZE = -1 };
+
+/* Size of the ut->ut_host member, or -1 if unbounded.  */
+enum { UT_HOST_SIZE = -1 };
+
+
+/* When read_utmp accesses a file (as opposed to fetching the information
+   from systemd), it uses the following low-level types and macros.
+   Keep them here, rather than moving them into readutmp.c, for backward
+   compatibility.  */
+
+#if HAVE_UTMPX_H
+
+/* <utmpx.h> defines 'struct utmpx' with the following fields:
+
+     Field        Type                       Platforms
+     ----------   ------                     ---------
+   ⎡ ut_user      char[]                     glibc, musl, macOS, FreeBSD, AIX, HP-UX, IRIX, Solaris, Cygwin
+   ⎣ ut_name      char[]                     NetBSD, Minix
+     ut_id        char[]                     glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+     ut_line      char[]                     glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+     ut_pid       pid_t                      glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+     ut_type      short                      glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+   ⎡ ut_tv        struct                     glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+   ⎢              { tv_sec; tv_usec; }
+   ⎣ ut_time      time_t                     Cygwin
+     ut_host      char[]                     glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+     ut_exit      struct                     glibc, musl, NetBSD, Minix, HP-UX, IRIX, Solaris
+                  { e_termination; e_exit; }
+     ut_session   [long] int                 glibc, musl, NetBSD, Minix, IRIX, Solaris
+   ⎡ ut_addr      [long] int                 HP-UX, Cygwin
+   ⎢ ut_addr_v6   [u]int[4]                  glibc, musl
+   ⎣ ut_ss        struct sockaddr_storage    NetBSD, Minix
+ */
+
+# if __GLIBC__ && _TIME_BITS == 64
+/* This is a near-copy of glibc's struct utmpx, which stops working
+   after the year 2038.  Unlike the glibc version, struct utmpx32
+   describes the file format even if time_t is 64 bits.  */
+struct utmpx32
+{
+  short int ut_type;               /* Type of login.  */
+  pid_t ut_pid;                    /* Process ID of login process.  */
+  char ut_line[__UT_LINESIZE];     /* Devicename.  */
+  char ut_id[4];                   /* Inittab ID.  */
+  char ut_user[__UT_USERSIZE];     /* Username.  */
+  char ut_host[__UT_HOSTSIZE];     /* Hostname for remote login. */
+  struct __exit_status ut_exit;    /* Exit status of a process marked
+                                      as DEAD_PROCESS.  */
+  /* The fields ut_session and ut_tv must be the same size when compiled
+     32- and 64-bit.  This allows files and shared memory to be shared
+     between 32- and 64-bit applications.  */
+  int ut_session;                  /* Session ID, used for windowing.  */
+  struct
+  {
+    /* Seconds.  Unsigned not signed, as glibc did not exist before 1970,
+       and if the format is still in use after 2038 its timestamps
+       will surely have the sign bit on.  This hack stops working
+       at 2106-02-07 06:28:16 UTC.  */
+    unsigned int tv_sec;
+    int tv_usec;                   /* Microseconds.  */
+  } ut_tv;                         /* Time entry was made.  */
+  int ut_addr_v6[4];               /* Internet address of remote host.  */
+  char ut_reserved[20];            /* Reserved for future use.  */
+};
+#  define UTMP_STRUCT_NAME utmpx32
+# else
+#  define UTMP_STRUCT_NAME utmpx
+# endif
+# define SET_UTMP_ENT setutxent
+# define GET_UTMP_ENT getutxent
+# define END_UTMP_ENT endutxent
+# ifdef HAVE_UTMPXNAME /* glibc, musl, macOS, NetBSD, Minix, IRIX, Solaris, Cygwin */
+#  define UTMP_NAME_FUNCTION utmpxname
+# elif defined UTXDB_ACTIVE /* FreeBSD */
+#  define UTMP_NAME_FUNCTION(x) setutxdb (UTXDB_ACTIVE, x)
+# endif
+
+#elif HAVE_UTMP_H
+
+/* <utmp.h> defines 'struct utmp' with the following fields:
+
+     Field        Type                       Platforms
+     ----------   ------                     ---------
+   ⎡ ut_user      char[]                     glibc, musl, AIX, HP-UX, IRIX, Solaris, Cygwin, Android
+   ⎣ ut_name      char[]                     macOS, old FreeBSD, NetBSD, OpenBSD, Minix
+     ut_id        char[]                     glibc, musl, AIX, HP-UX, IRIX, Solaris, Cygwin, Android
+     ut_line      char[]                     glibc, musl, macOS, old FreeBSD, NetBSD, OpenBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin, Android
+     ut_pid       pid_t                      glibc, musl, AIX, HP-UX, IRIX, Solaris, Cygwin, Android
+     ut_type      short                      glibc, musl, AIX, HP-UX, IRIX, Solaris, Cygwin, Android
+   ⎡ ut_tv        struct                     glibc, musl, Android
+   ⎢              { tv_sec; tv_usec; }
+   ⎣ ut_time      time_t                     macOS, old FreeBSD, NetBSD, OpenBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin
+     ut_host      char[]                     glibc, musl, macOS, old FreeBSD, NetBSD, OpenBSD, Minix, AIX, HP-UX, Cygwin, Android
+     ut_exit      struct                     glibc, musl, AIX, HP-UX, IRIX, Solaris, Android
+                  { e_termination; e_exit; }
+     ut_session   [long] int                 glibc, musl, Android
+   ⎡ ut_addr      [long] int                 HP-UX, Cygwin
+   ⎣ ut_addr_v6   [u]int[4]                  glibc, musl, Android
+ */
+
+# define UTMP_STRUCT_NAME utmp
+# define SET_UTMP_ENT setutent
+# define GET_UTMP_ENT getutent
+# define END_UTMP_ENT endutent
+# ifdef HAVE_UTMPNAME /* glibc, musl, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin, Android */
+#  define UTMP_NAME_FUNCTION utmpname
+# endif
+
+#endif
+
+/* Evaluates to 1 if gl_utmp's ut_id field may ever have a non-zero value.  */
+#define HAVE_STRUCT_XTMP_UT_ID \
+  (READUTMP_USE_SYSTEMD \
+   || (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID))
+
+/* Evaluates to 1 if gl_utmp's ut_pid field may ever have a non-zero value.  */
+#define HAVE_STRUCT_XTMP_UT_PID \
+  (READUTMP_USE_SYSTEMD \
+   || (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID))
+
+/* Evaluates to 1 if gl_utmp's ut_host field may ever be non-empty.  */
+#define HAVE_STRUCT_XTMP_UT_HOST \
+  (READUTMP_USE_SYSTEMD \
+   || (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_HOST : HAVE_STRUCT_UTMP_UT_HOST))
+
+/* Definition of UTMP_FILE.
+   On glibc systems, UTMP_FILE is "/var/run/utmp".  */
+#if !defined UTMP_FILE && defined _PATH_UTMP
+# define UTMP_FILE _PATH_UTMP
+#endif
+#ifdef UTMPX_FILE /* Solaris, SysVr4 */
+# undef UTMP_FILE
+# define UTMP_FILE UTMPX_FILE
+#endif
+#ifndef UTMP_FILE
+# define UTMP_FILE "/etc/utmp"
+#endif
+
+/* Definition of WTMP_FILE.
+   On glibc systems, UTMP_FILE is "/var/log/wtmp".  */
+#if !defined WTMP_FILE && defined _PATH_WTMP
+# define WTMP_FILE _PATH_WTMP
+#endif
+#ifdef WTMPX_FILE /* Solaris, SysVr4 */
+# undef WTMP_FILE
+# define WTMP_FILE WTMPX_FILE
+#endif
+#ifndef WTMP_FILE
+# define WTMP_FILE "/etc/wtmp"
+#endif
+
+/* Some platforms, such as OpenBSD, don't have an ut_type field and don't have
+   the BOOT_TIME and USER_PROCESS macros.  But we want to support them in
+   'struct gl_utmp'.  */
+#if !(HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE)
+# define BOOT_TIME 2
+# define USER_PROCESS 0
+#endif
+
+/* Macros that test (UT)->ut_type.  */
+#ifdef BOOT_TIME
+# define UT_TYPE_BOOT_TIME(UT) UT_TYPE_EQ (UT, BOOT_TIME)
+#else
+# define UT_TYPE_BOOT_TIME(UT) 0
+#endif
+#ifdef USER_PROCESS
+# define UT_TYPE_USER_PROCESS(UT) UT_TYPE_EQ (UT, USER_PROCESS)
+#else
+# define UT_TYPE_USER_PROCESS(UT) 0
+#endif
+
+/* Determines whether an entry *UT corresponds to a user process.  */
+#define IS_USER_PROCESS(UT)                                    \
+  (UT_USER (UT)[0]                                             \
+   && (UT_TYPE_USER_PROCESS (UT)                               \
+       || (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (UT) != 0)))
+
+/* Define if read_utmp is not just a dummy.  */
+#if READUTMP_USE_SYSTEMD || HAVE_UTMPX_H || HAVE_UTMP_H || defined __CYGWIN__ || defined _WIN32
+# define READ_UTMP_SUPPORTED 1
+#endif
+
+/* Options for read_utmp.  */
+enum
+  {
+    READ_UTMP_CHECK_PIDS   = 1,
+    READ_UTMP_USER_PROCESS = 2,
+    READ_UTMP_BOOT_TIME    = 4,
+    READ_UTMP_NO_BOOT_TIME = 8
+  };
+
+/* Return a copy of (UT)->ut_user, without trailing spaces,
+   as a freshly allocated string.  */
+char *extract_trimmed_name (const STRUCT_UTMP *ut)
+  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
+  _GL_ATTRIBUTE_RETURNS_NONNULL;
+
+/* Read the utmp entries corresponding to file FILE into freshly-
+   malloc'd storage, set *UTMP_BUF to that pointer, set *N_ENTRIES to
+   the number of entries, and return zero.  If there is any error,
+   return -1, setting errno, and don't modify the parameters.
+   A good candidate for FILE is UTMP_FILE.
+   If OPTIONS & READ_UTMP_CHECK_PIDS is nonzero, omit entries whose
+   process-IDs do not currently exist.
+   If OPTIONS & READ_UTMP_USER_PROCESS is nonzero, omit entries which
+   do not correspond to a user process.
+   If OPTIONS & READ_UTMP_BOOT_TIME is nonzero, omit all entries except
+   the one that contains the boot time.
+   If OPTIONS & READ_UTMP_NO_BOOT_TIME is nonzero, omit the boot time
+   entries.
+
+   This function is not multithread-safe, since on many platforms it
+   invokes the functions setutxent, getutxent, endutxent.  These
+   functions are needed because they may lock FILE (so that we don't
+   read garbage when a concurrent process writes to FILE), but their
+   drawback is that they have a common global state.  */
+int read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
+               int options);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __READUTMP_H__ */
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 3382e9bc241..14ff92040a4 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -51,6 +51,7 @@ AC_DEFUN
   # Code from module at-internal:
   # Code from module attribute:
   # Code from module binary-io:
+  # Code from module boot-time:
   # Code from module builtin-expect:
   # Code from module byteswap:
   # Code from module c-ctype:
@@ -243,6 +244,7 @@ AC_DEFUN
   gl_ASSERT_H
   gl_CONDITIONAL_HEADER([assert.h])
   AC_PROG_MKDIR_P
+  gl_PREREQ_READUTMP_H
   gl___BUILTIN_EXPECT
   gl_BYTESWAP
   gl_CONDITIONAL_HEADER([byteswap.h])
@@ -1252,6 +1254,9 @@ AC_DEFUN
   lib/attribute.h
   lib/binary-io.c
   lib/binary-io.h
+  lib/boot-time-aux.h
+  lib/boot-time.c
+  lib/boot-time.h
   lib/byteswap.in.h
   lib/c++defs.h
   lib/c-ctype.c
@@ -1383,6 +1388,7 @@ AC_DEFUN
   lib/rawmemchr.valgrind
   lib/readlink.c
   lib/readlinkat.c
+  lib/readutmp.h
   lib/realloc.c
   lib/regcomp.c
   lib/regex.c
@@ -1542,6 +1548,7 @@ AC_DEFUN
   m4/rawmemchr.m4
   m4/readlink.m4
   m4/readlinkat.m4
+  m4/readutmp.m4
   m4/realloc.m4
   m4/regex.m4
   m4/sha1.m4
diff --git a/m4/readutmp.m4 b/m4/readutmp.m4
new file mode 100644
index 00000000000..fff8d4eb7bf
--- /dev/null
+++ b/m4/readutmp.m4
@@ -0,0 +1,117 @@
+# readutmp.m4 serial 28
+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,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_READUTMP],
+[
+  AC_REQUIRE([gl_SYSTEMD_CHOICE])
+
+  dnl Set READUTMP_LIB to '-lsystemd' or '', depending on whether use of
+  dnl systemd APIs is possible and desired (only the systemd login API, here).
+  dnl AC_LIB_LINKFLAGS_BODY would be overkill here, since few people install
+  dnl libsystemd in non-system directories.
+  READUTMP_LIB=
+  if test "$SYSTEMD_CHOICE" = yes; then
+    AC_CHECK_HEADER([systemd/sd-login.h])
+    if test $ac_cv_header_systemd_sd_login_h = yes; then
+      AC_CACHE_CHECK([for libsystemd version >= 254],
+        [gl_cv_lib_readutmp_systemd],
+        [gl_save_LIBS="$LIBS"
+         LIBS="$LIBS -lsystemd"
+         AC_LINK_IFELSE(
+           [AC_LANG_PROGRAM([[
+              #include <stdint.h>
+              #include <systemd/sd-login.h>
+              ]], [[
+              uint64_t st;
+              sd_session_get_start_time ("1", &st);
+              ]])
+           ],
+           [gl_cv_lib_readutmp_systemd=yes],
+           [gl_cv_lib_readutmp_systemd=no])
+         LIBS="$gl_save_LIBS"
+        ])
+      if test $gl_cv_lib_readutmp_systemd = yes; then
+        AC_DEFINE([READUTMP_USE_SYSTEMD], [1],
+          [Define if the readutmp module should use the systemd login API.])
+        READUTMP_LIB='-lsystemd'
+      fi
+    fi
+  fi
+  AC_SUBST([READUTMP_LIB])
+
+  gl_PREREQ_READUTMP_H
+])
+
+# Prerequisites of readutmp.h and boot-time-aux.h.
+AC_DEFUN_ONCE([gl_PREREQ_READUTMP_H],
+[
+  dnl Persuade utmpx.h to declare utmpxname
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_HEADERS_ONCE([utmp.h utmpx.h])
+  if test $ac_cv_header_utmp_h = yes || test $ac_cv_header_utmpx_h = yes; then
+    dnl Prerequisites of lib/readutmp.h and lib/readutmp.c.
+    AC_CHECK_FUNCS_ONCE([utmpname utmpxname])
+    AC_CHECK_DECLS([getutent],,,[[
+/* <sys/types.h> is a prerequisite of <utmp.h> on FreeBSD 8.0, OpenBSD 4.6.  */
+#include <sys/types.h>
+#ifdef HAVE_UTMP_H
+# include <utmp.h>
+#endif
+]])
+    utmp_includes="\
+AC_INCLUDES_DEFAULT
+#ifdef HAVE_UTMPX_H
+# include <utmpx.h>
+#endif
+#ifdef HAVE_UTMP_H
+# if defined _THREAD_SAFE && defined UTMP_DATA_INIT
+   /* When including both utmp.h and utmpx.h on AIX 4.3, with _THREAD_SAFE
+      defined, work around the duplicate struct utmp_data declaration.  */
+#  define utmp_data gl_aix_4_3_workaround_utmp_data
+# endif
+# include <utmp.h>
+#endif
+"
+    AC_CHECK_MEMBERS([struct utmpx.ut_user],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_user],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_name],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_name],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_type],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_type],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_pid],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_pid],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_tv],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_host],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_host],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_id],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_id],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_session],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_session],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_exit],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_exit],,,[$utmp_includes])
+
+    AC_CHECK_MEMBERS([struct utmpx.ut_exit.ut_exit],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_exit.e_exit],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_exit.e_exit],,,[$utmp_includes])
+
+    AC_CHECK_MEMBERS([struct utmpx.ut_exit.ut_termination],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmpx.ut_exit.e_termination],,,[$utmp_includes])
+    AC_CHECK_MEMBERS([struct utmp.ut_exit.e_termination],,,[$utmp_includes])
+  fi
+
+  AC_CHECK_HEADERS_ONCE([sys/param.h])
+  dnl <sys/sysctl.h> requires <sys/param.h> on OpenBSD 4.0.
+  AC_CHECK_HEADERS([sys/sysctl.h],,,
+    [AC_INCLUDES_DEFAULT
+     #if HAVE_SYS_PARAM_H
+     # include <sys/param.h>
+     #endif
+    ])
+  AC_CHECK_FUNCS([sysctl])
+
+  AC_CHECK_HEADERS_ONCE([OS.h])
+])
diff --git a/src/filelock.c b/src/filelock.c
index 3b1ff8ad566..d2161f1e58a 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -36,13 +36,9 @@ Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2023 Free Software
 #include <sys/file.h>
 #include <fcntl.h>
 #include <unistd.h>
-
-#ifdef __FreeBSD__
-#include <sys/sysctl.h>
-#endif /* __FreeBSD__ */
-
 #include <errno.h>
 
+#include <boot-time.h>
 #include <c-ctype.h>
 
 #include "lisp.h"
@@ -55,20 +51,6 @@ Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2023 Free Software
 
 #ifndef MSDOS
 
-#ifdef HAVE_UTMP_H
-#include <utmp.h>
-#endif
-
-/* Boot time is not available on Android.  */
-
-#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
-#undef BOOT_TIME
-#endif
-
-#if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME
-#define WTMP_FILE "/var/log/wtmp"
-#endif
-
 #ifdef HAVE_ANDROID
 #include "android.h" /* For `android_is_special_directory'.  */
 #endif /* HAVE_ANDROID */
@@ -127,153 +109,19 @@ #define WTMP_FILE "/var/log/wtmp"
 \f
 /* Return the time of the last system boot.  */
 
-static time_t boot_time;
-static bool boot_time_initialized;
-
-#ifdef BOOT_TIME
-static void get_boot_time_1 (const char *, bool);
-#endif
-
 static time_t
-get_boot_time (void)
+get_boot_sec (void)
 {
-  if (boot_time_initialized)
-    return boot_time;
-  boot_time_initialized = 1;
-
-#if defined (CTL_KERN) && defined (KERN_BOOTTIME)
-  {
-    int mib[2];
-    size_t size;
-    struct timeval boottime_val;
-
-    mib[0] = CTL_KERN;
-    mib[1] = KERN_BOOTTIME;
-    size = sizeof (boottime_val);
-
-    if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0 && size != 0)
-      {
-	boot_time = boottime_val.tv_sec;
-	return boot_time;
-      }
-  }
-#endif /* defined (CTL_KERN) && defined (KERN_BOOTTIME) */
-
-#ifdef BOOT_TIME_FILE
-    {
-      struct stat st;
-      if (stat (BOOT_TIME_FILE, &st) == 0)
-	{
-	  boot_time = st.st_mtime;
-	  return boot_time;
-	}
-    }
-#endif /* BOOT_TIME_FILE */
-
-#if defined (BOOT_TIME)
-  /* The utmp routines maintain static state.  Don't touch that state
+  /* get_boot_time maintains static state.  Don't touch that state
      if we are going to dump, since it might not survive dumping.  */
   if (will_dump_p ())
-    return boot_time;
-
-  /* Try to get boot time from utmp before wtmp,
-     since utmp is typically much smaller than wtmp.
-     Passing a null pointer causes get_boot_time_1
-     to inspect the default file, namely utmp.  */
-  get_boot_time_1 (0, 0);
-  if (boot_time)
-    return boot_time;
-
-  /* Try to get boot time from the current wtmp file.  */
-  get_boot_time_1 (WTMP_FILE, 1);
-
-  /* If we did not find a boot time in wtmp, look at wtmp.1,
-     wtmp.1.gz, wtmp.2, wtmp.2.gz, and so on.  */
-  for (int counter = 0; counter < 20 && ! boot_time; counter++)
-    {
-      Lisp_Object filename = Qnil;
-      bool delete_flag = false;
-      char cmd_string[sizeof WTMP_FILE ".19.gz"];
-      AUTO_STRING_WITH_LEN (tempname, cmd_string,
-			    sprintf (cmd_string, "%s.%d", WTMP_FILE, counter));
-      if (! NILP (Ffile_exists_p (tempname)))
-	filename = tempname;
-      else
-	{
-	  tempname = make_formatted_string (cmd_string, "%s.%d.gz",
-					    WTMP_FILE, counter);
-	  if (! NILP (Ffile_exists_p (tempname)))
-	    {
-	      /* The utmp functions on older systems accept only file
-		 names up to 8 bytes long.  Choose a 2 byte prefix, so
-		 the 6-byte suffix does not make the name too long.  */
-	      filename = Fmake_temp_file_internal (build_string ("wt"), Qnil,
-						   empty_unibyte_string, Qnil);
-	      CALLN (Fcall_process, build_string ("gzip"), Qnil,
-		     list2 (QCfile, filename), Qnil,
-		     build_string ("-cd"), tempname);
-	      delete_flag = true;
-	    }
-	}
-
-      if (! NILP (filename))
-	{
-	  get_boot_time_1 (SSDATA (filename), 1);
-	  if (delete_flag)
-	    emacs_unlink (SSDATA (filename));
-	}
-    }
-
-  return boot_time;
-#else
-  return 0;
-#endif
-}
+    return 0;
 
-#ifdef BOOT_TIME
-/* Try to get the boot time from wtmp file FILENAME.
-   This succeeds if that file contains a reboot record.
-
-   If FILENAME is zero, use the same file as before;
-   if no FILENAME has ever been specified, this is the utmp file.
-   Use the newest reboot record if NEWEST,
-   the first reboot record otherwise.
-   Ignore all reboot records on or before BOOT_TIME.
-   Success is indicated by setting BOOT_TIME to a larger value.  */
-
-void
-get_boot_time_1 (const char *filename, bool newest)
-{
-  struct utmp ut, *utp;
-
-  if (filename)
-    utmpname (filename);
-
-  setutent ();
-
-  while (1)
-    {
-      /* Find the next reboot record.  */
-      ut.ut_type = BOOT_TIME;
-      utp = getutid (&ut);
-      if (! utp)
-	break;
-      /* Compare reboot times and use the newest one.  */
-      if (utp->ut_time > boot_time)
-	{
-	  boot_time = utp->ut_time;
-	  if (! newest)
-	    break;
-	}
-      /* Advance on element in the file
-	 so that getutid won't repeat the same one.  */
-      utp = getutent ();
-      if (! utp)
-	break;
-    }
-  endutent ();
+  struct timespec boot_time;
+  boot_time.tv_sec = 0;
+  get_boot_time (&boot_time);
+  return boot_time.tv_sec;
 }
-#endif /* BOOT_TIME */
 \f
 /* An arbitrary limit on lock contents length.  8 K should be plenty
    big enough in practice.  */
@@ -418,7 +266,7 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
 static int
 lock_file_1 (Lisp_Object lfname, bool force)
 {
-  intmax_t boot = get_boot_time ();
+  intmax_t boot = get_boot_sec ();
   Lisp_Object luser_name = Fuser_login_name (Qnil);
   Lisp_Object lhost_name = Fsystem_name ();
 
@@ -604,7 +452,7 @@ current_lock_owner (lock_info_type *owner, Lisp_Object lfname)
                && (kill (pid, 0) >= 0 || errno == EPERM)
 	       && (boot_time == 0
 		   || (boot_time <= TYPE_MAXIMUM (time_t)
-		       && within_one_second (boot_time, get_boot_time ()))))
+		       && within_one_second (boot_time, get_boot_sec ()))))
         return ANOTHER_OWNS_IT;
       /* The owner process is dead or has a strange pid, so try to
          zap the lockfile.  */
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  2:49 ` boot-time: straighten code Paul Eggert
@ 2023-08-13  3:26   ` Po Lu
  2023-08-13  6:35     ` Paul Eggert
                       ` (3 more replies)
  2023-08-14  8:02   ` boot-time: straighten code Andreas Schwab
  2023-08-15 21:12   ` Bruno Haible
  2 siblings, 4 replies; 24+ messages in thread
From: Po Lu @ 2023-08-13  3:26 UTC (permalink / raw)
  To: Paul Eggert; +Cc: Bruno Haible, bug-gnulib, Emacs Development

Paul Eggert <eggert@cs.ucla.edu> writes:

> On 2023-08-11 14:49, Bruno Haible wrote:
>> Paul: With this simplification, you may consider using the 'boot-time' module
>> in Emacs. I bet that it produces a better result than Emacs' src/filelock.c
>> on many platforms. (I haven't tested it, but I could test it if you give me
>> a manual testing recipe.)
>
> Thanks for doing all that. I installed the attached patch into Emacs
> master, which you should be able to test via:
>
> 	git clone https://git.savannah.gnu.org/git/emacs.git
> 	cd emacs
> 	./autogen.sh
> 	./configure
> 	make
> 	src/emacs
>
> Please give it a try, especially on any MS-Windows platform you happen
> to have. I have tested only on Ubuntu 23.04 so far.
>
> A simple way to test is to use Emacs to start editing a file (without
> saving) and then inspect the symbolic link .#* that Emacs uses as a
> lock file. The trailing digits of that link's contents should be the
> boot time. These symlinks are Emacs's only use of boot time.

During the automated build of the Android port, the following errors
were encountered with the Android NDK r10b and __ANDROID_API__ set to 8
(which is the oldest configuration Emacs supports.)  Bruno, would you
please investigate this?

In file included from boot-time.c:54:0:
boot-time-aux.h: In function 'get_linux_uptime':
boot-time-aux.h:70:3: error: implicit declaration of function 'sysinfo' [-Werror=implicit-function-declaration]
   if (sysinfo (&info) >= 0)
   ^
boot-time.c: In function 'get_boot_time_uncached':
boot-time.c:111:26: error: 'BOOT_TIME' undeclared (first use in this function)
       if (ut->ut_type == BOOT_TIME)
                          ^
boot-time.c:111:26: note: each undeclared identifier is reported only once for each function it appears in
boot-time.c:126:3: error: implicit declaration of function 'endutent' [-Werror=implicit-function-declaration]
   END_UTMP_ENT ();
   ^
cc1: some warnings being treated as errors



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  3:26   ` Po Lu
@ 2023-08-13  6:35     ` Paul Eggert
  2023-08-13 13:45     ` Bruno Haible
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 24+ messages in thread
From: Paul Eggert @ 2023-08-13  6:35 UTC (permalink / raw)
  To: Po Lu; +Cc: Bruno Haible, bug-gnulib, Emacs Development

[-- Attachment #1: Type: text/plain, Size: 1224 bytes --]

On 2023-08-12 20:26, Po Lu wrote:

> In file included from boot-time.c:54:0:
> boot-time-aux.h: In function 'get_linux_uptime':
> boot-time-aux.h:70:3: error: implicit declaration of function 'sysinfo' [-Werror=implicit-function-declaration]
>     if (sysinfo (&info) >= 0)
>     ^
> boot-time.c: In function 'get_boot_time_uncached':
> boot-time.c:111:26: error: 'BOOT_TIME' undeclared (first use in this function)
>         if (ut->ut_type == BOOT_TIME)
>                            ^
> boot-time.c:111:26: note: each undeclared identifier is reported only once for each function it appears in
> boot-time.c:126:3: error: implicit declaration of function 'endutent' [-Werror=implicit-function-declaration]
>     END_UTMP_ENT ();
>     ^
> cc1: some warnings being treated as errors

Thanks for reporting that. As I understand it, the utmp/utmpx functions 
are a losing cause on Android since they never return anything. If so, 
it's simpler to bypass these functions on that platform. Also, Gnulib 
should bypass sysinfo unless it's available. Please try the attached 
patch, which I haven't installed onto Emacs master on Savannah. I've 
tested it only on Ubuntu 23.04.

If this patch works we can propagate it to Gnulib.

[-- Attachment #2: 0001-Temp-patch-for-Android.patch --]
[-- Type: text/x-patch, Size: 6598 bytes --]

From d2db6d8e92282de8ffb5293dd1445e3a2e549ed0 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Sat, 12 Aug 2023 23:20:12 -0700
Subject: [PATCH] Temp patch for Android

---
 configure.ac        | 19 -------------------
 lib/boot-time-aux.h | 10 ++++++++++
 lib/boot-time.c     | 26 +++++++++-----------------
 src/conf_post.h     | 34 ----------------------------------
 src/filelock.c      | 14 +++++---------
 5 files changed, 24 insertions(+), 79 deletions(-)

diff --git a/configure.ac b/configure.ac
index 46836073aa0..0234a82b92f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2710,25 +2710,6 @@ AC_DEFUN
 
     # Check for some functions not always present in the NDK.
     AC_CHECK_DECLS([android_get_device_api_level])
-    AC_CHECK_DECLS([endutent, sysinfo], [], [],
-      [[
-#include <sys/sysinfo.h>
-#include <utmp.h>
-]])
-
-    # Establish if BOOT_TIME is defined in utmp.h.
-    AC_CACHE_CHECK([if utmp.h defines BOOT_TIME],
-      [emacs_cv_utmp_h_defines_boot_time],
-      [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-#include <utmp.h>
-#ifndef BOOT_TIME
-BOOT_TIME not defined
-#endif /* BOOT_TIME */
-]], [[]])], [emacs_cv_utmp_h_defines_boot_time=yes],
-      [emacs_cv_utmp_h_defines_boot_time=no])])
-    AS_IF([test x"$emacs_cv_utmp_h_defines_boot_time" = xyes],
-      [AC_DEFINE([UTMP_H_DEFINES_BOOT_TIME], [1],
-        [Define to 1 if building for Android and utmp.h declares BOOT_TIME])])
 
     # Say this build is really for Android.
     REALLY_ANDROID=yes])])
diff --git a/lib/boot-time-aux.h b/lib/boot-time-aux.h
index 348611fc85c..e782ca6eac6 100644
--- a/lib/boot-time-aux.h
+++ b/lib/boot-time-aux.h
@@ -16,6 +16,14 @@
 
 /* Written by Bruno Haible <bruno@clisp.org>.  */
 
+#if defined __linux__ || 9 <= __ANDROID_API__
+# include <sys/sysinfo.h>
+#endif
+#if 9 <= __ANDROID_API__
+/* Absent from some NDK versions, but present in API level 9+.  */
+extern int sysinfo (struct sysinfo *);
+#endif
+
 #define SIZEOF(a) (sizeof(a)/sizeof(a[0]))
 
 #if defined __linux__ || defined __ANDROID__
@@ -65,6 +73,7 @@ get_linux_uptime (struct timespec *p_uptime)
     }
 # endif
 
+# if defined __linux__ || 9 <= __ANDROID_API__
   /* The sysinfo call returns the uptime with a resolution of 1 sec only.  */
   struct sysinfo info;
   if (sysinfo (&info) >= 0)
@@ -73,6 +82,7 @@ get_linux_uptime (struct timespec *p_uptime)
       p_uptime->tv_nsec = 0;
       return 0;
     }
+# endif
 
   return -1;
 }
diff --git a/lib/boot-time.c b/lib/boot-time.c
index d813bfa5825..331711238bc 100644
--- a/lib/boot-time.c
+++ b/lib/boot-time.c
@@ -27,11 +27,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#if defined __linux__ || defined __ANDROID__
-# include <sys/sysinfo.h>
-# include <time.h>
-#endif
-
 #if HAVE_SYS_SYSCTL_H && !defined __minix
 # if HAVE_SYS_PARAM_H
 #  include <sys/param.h>
@@ -76,7 +71,12 @@ get_boot_time_uncached (struct timespec *p_boot_time)
 {
   struct timespec found_boot_time = {0};
 
-# if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE)
+# ifdef __ANDROID__
+
+  /* Workaround for Android:  */
+  get_android_boot_time (&found_boot_time);
+
+# elif (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE)
 
   /* Try to find the boot time in the /var/run/utmp file.  */
 
@@ -90,7 +90,7 @@ get_boot_time_uncached (struct timespec *p_boot_time)
 
   SET_UTMP_ENT ();
 
-#   if (defined __linux__ && !defined __ANDROID__) || defined __minix
+#   if defined __linux__ || defined __minix
   /* Timestamp of the "runlevel" entry, if any.  */
   struct timespec runlevel_ts = {0};
 #   endif
@@ -111,7 +111,7 @@ get_boot_time_uncached (struct timespec *p_boot_time)
       if (ut->ut_type == BOOT_TIME)
         found_boot_time = ts;
 
-#   if defined __linux__ && !defined __ANDROID__
+#   ifdef __linux__
       if (memcmp (UT_USER (ut), "runlevel", strlen ("runlevel") + 1) == 0
           && memcmp (ut->ut_line, "~", strlen ("~") + 1) == 0)
         runlevel_ts = ts;
@@ -125,7 +125,7 @@ get_boot_time_uncached (struct timespec *p_boot_time)
 
   END_UTMP_ENT ();
 
-#   if defined __linux__ && !defined __ANDROID__
+#   ifdef __linux__
   /* 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,
@@ -145,14 +145,6 @@ get_boot_time_uncached (struct timespec *p_boot_time)
     }
 #   endif
 
-#   if defined __ANDROID__
-  if (found_boot_time.tv_sec == 0)
-    {
-      /* Workaround for Android:  */
-      get_android_boot_time (&found_boot_time);
-    }
-#   endif
-
 #   if defined __minix
   /* On Minix, during boot,
        1. an entry gets written into /var/run/utmp, with ut_type = BOOT_TIME,
diff --git a/src/conf_post.h b/src/conf_post.h
index 5f18e5ae4bb..f31e012dc6e 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -471,37 +471,3 @@ #define VFORK() vfork ()
 #undef MB_CUR_MAX
 #define MB_CUR_MAX REPLACEMENT_MB_CUR_MAX
 #endif /* REPLACEMENT_MB_CUR_MAX */
-
-#ifdef __ANDROID__
-
-/* The Android NDK r10b omits the function `endutent' that is actually
-   defined in the C library and used by Gnulib.  Define a prototype
-   for it here.  */
-
-#if !HAVE_DECL_ENDUTENT
-extern void endutent (void);
-#endif /* !HAVE_DECL_ENDUTENT */
-
-/* Now define substitutes for BOOT_TIME if necessary.  */
-
-#ifndef UTMP_H_DEFINES_BOOT_TIME
-#include <utmp.h>
-
-#define BOOT_TIME 2
-#endif /* !UTMP_H_DEFINES_BOOT_TIME */
-
-/* sysinfo is also absent from some versions of the NDK, yet is
-   present on API level 9 and above.  */
-
-#if !HAVE_DECL_SYSINFO
-#include <sys/sysinfo.h>
-
-#if __ANDROID_API__ >= 9
-extern int sysinfo (struct sysinfo *info);
-#else /* __ANDROID_API__ < 8 */
-/* Gnulib uses this function unconditionally.  */
-#define sysinfo(ignored) ((void) ignored, (errno = ENOSYS), -1)
-#endif /* __ANDROID_API >= 9 */
-#endif /* !HAVE_DECL_SYSINFO */
-
-#endif /* __ANDROID__ */
diff --git a/src/filelock.c b/src/filelock.c
index f3075b93322..92be20ad8a0 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -118,16 +118,12 @@ get_boot_sec (void)
   if (will_dump_p ())
     return 0;
 
+  struct timespec boot_time;
+  boot_time.tv_sec = 0;
 #ifndef MSDOS
-  {
-    struct timespec boot_time;
-    boot_time.tv_sec = 0;
-    get_boot_time (&boot_time);
-    return boot_time.tv_sec;
-  }
-#else /* MSDOS */
-  return 0;
-#endif /* MSDOS */
+  get_boot_time (&boot_time);
+#endif
+  return boot_time.tv_sec;
 }
 \f
 /* An arbitrary limit on lock contents length.  8 K should be plenty
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  3:26   ` Po Lu
  2023-08-13  6:35     ` Paul Eggert
@ 2023-08-13 13:45     ` Bruno Haible
  2023-08-13 14:16     ` Bruno Haible
  2023-08-13 14:36     ` Bruno Haible
  3 siblings, 0 replies; 24+ messages in thread
From: Bruno Haible @ 2023-08-13 13:45 UTC (permalink / raw)
  To: Paul Eggert, Po Lu; +Cc: bug-gnulib, Emacs-devel

Po Lu wrote:
> During the automated build of the Android port, the following errors
> were encountered with the Android NDK r10b and __ANDROID_API__ set to 8
> (which is the oldest configuration Emacs supports.)
> ...
> boot-time.c:111:26: note: each undeclared identifier is reported only once for each function it appears in
> boot-time.c:126:3: error: implicit declaration of function 'endutent' [-Werror=implicit-function-declaration]
>    END_UTMP_ENT ();
>    ^

endutent() exists in Android, already in API 8. It's just that its declaration
is missing from <utmp.h> until ca. 2015.

Should be fixed through this patch. Also, it removes a declaration that was
needed only for Ultrix 4.3. Gnulib dropped Ultrix support in 2018.

Paul Eggert wrote:
> As I understand it, the utmp/utmpx functions 
> are a losing cause on Android since they never return anything. If so, 
> it's simpler to bypass these functions on that platform.

It's more future-proof to continue to use the API that they have. Who knows,
they might add useful data into the UTMP_FILE at some point. (E.g. they had a
broken localeconv() function for a long time; then they actually fixed it.)


2023-08-13  Bruno Haible  <bruno@clisp.org>

	readutmp, boot-time: Fix compilation error on old Android.
	Reported by Po Lu in
	<https://lists.gnu.org/archive/html/bug-gnulib/2023-08/msg00108.html>.
	* lib/readutmp.c (endutent): New fallback declaration, for Android.
	(getutent): Remove Ultrix workaround from 2000-04-05.
	* lib/boot-time.c: Likewise.
	* m4/readutmp.m4 (gl_PREREQ_READUTMP_H): Test whether endutent is
	declared, not getutent.
	* doc/glibc-functions/endutent.texi: Mention the Android bug.

diff --git a/doc/glibc-functions/endutent.texi b/doc/glibc-functions/endutent.texi
index 5e12e23c44..b4f3dd397a 100644
--- a/doc/glibc-functions/endutent.texi
+++ b/doc/glibc-functions/endutent.texi
@@ -28,4 +28,7 @@
 @item
 This function is missing on some platforms:
 macOS 11.1, FreeBSD 13.0, OpenBSD 6.7, Minix 3.1.8, mingw, MSVC 14.
+@item
+This function is not declared on some platforms:
+Android before ca.@: 2015.
 @end itemize
diff --git a/lib/boot-time.c b/lib/boot-time.c
index d813bfa582..c359954f19 100644
--- a/lib/boot-time.c
+++ b/lib/boot-time.c
@@ -65,8 +65,10 @@
 # define UT_USER(UT) ((UT)->ut_user)
 #endif
 
-#if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION && !HAVE_DECL_GETUTENT
-struct utmp *getutent (void);
+#if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION
+# if !HAVE_DECL_ENDUTENT /* Android */
+void endutent (void);
+# endif
 #endif
 
 #if defined __linux__ || HAVE_UTMPX_H || HAVE_UTMP_H || defined __CYGWIN__ || defined _WIN32
diff --git a/lib/readutmp.c b/lib/readutmp.c
index ef9f0aff43..0b7732b165 100644
--- a/lib/readutmp.c
+++ b/lib/readutmp.c
@@ -314,9 +314,11 @@ have_boot_time (struct utmp_alloc a)
   return false;
 }
 
-# if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION && !HAVE_DECL_GETUTENT
-struct utmp *getutent (void);
+#if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION
+# if !HAVE_DECL_ENDUTENT /* Android */
+void endutent (void);
 # endif
+#endif
 
 static int
 read_utmp_from_file (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf,
diff --git a/m4/readutmp.m4 b/m4/readutmp.m4
index fff8d4eb7b..9dffe981b8 100644
--- a/m4/readutmp.m4
+++ b/m4/readutmp.m4
@@ -1,4 +1,4 @@
-# readutmp.m4 serial 28
+# readutmp.m4 serial 29
 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,
@@ -55,7 +55,7 @@ AC_DEFUN_ONCE([gl_PREREQ_READUTMP_H]
   if test $ac_cv_header_utmp_h = yes || test $ac_cv_header_utmpx_h = yes; then
     dnl Prerequisites of lib/readutmp.h and lib/readutmp.c.
     AC_CHECK_FUNCS_ONCE([utmpname utmpxname])
-    AC_CHECK_DECLS([getutent],,,[[
+    AC_CHECK_DECLS([endutent],,,[[
 /* <sys/types.h> is a prerequisite of <utmp.h> on FreeBSD 8.0, OpenBSD 4.6.  */
 #include <sys/types.h>
 #ifdef HAVE_UTMP_H






^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  3:26   ` Po Lu
  2023-08-13  6:35     ` Paul Eggert
  2023-08-13 13:45     ` Bruno Haible
@ 2023-08-13 14:16     ` Bruno Haible
  2023-08-13 14:36     ` Bruno Haible
  3 siblings, 0 replies; 24+ messages in thread
From: Bruno Haible @ 2023-08-13 14:16 UTC (permalink / raw)
  To: Paul Eggert, Po Lu; +Cc: bug-gnulib, Emacs-devel

Po Lu wrote:
> During the automated build of the Android port, the following errors
> were encountered with the Android NDK r10b and __ANDROID_API__ set to 8
> (which is the oldest configuration Emacs supports.)...
> 
> In file included from boot-time.c:54:0:
> boot-time-aux.h: In function 'get_linux_uptime':
> boot-time-aux.h:70:3: error: implicit declaration of function 'sysinfo' [-Werror=implicit-function-declaration]
>    if (sysinfo (&info) >= 0)
>    ^

Should be fixed by the patch below.

Paul Eggert wrote:
> Gnulib should bypass sysinfo unless it's available.

Yes. Note that it's available in Android libc already at API level 3. It's only
the declaration that was added in API level 9.

Also, if we write '#if HAVE_DECL_SYSINFO' instead of '9 <= __ANDROID_API__',
the change might be helpful also with other Linux-based libcs that may be
developed in the future.


2023-08-13  Bruno Haible  <bruno@clisp.org>

	readutmp, boot-time: Fix compilation error on Android API 8.
	Reported by Po Lu in
	<https://lists.gnu.org/archive/html/bug-gnulib/2023-08/msg00108.html>.
	* m4/readutmp.m4 (gl_PREREQ_READUTMP_H): Test whether sysinfo is
	declared.
	* lib/boot-time-aux.h (get_linux_uptime): Invoke sysinfo only if it is
	declared.
	* doc/glibc-functions/sysinfo.texi: Mention the Android problem.

diff --git a/doc/glibc-functions/sysinfo.texi b/doc/glibc-functions/sysinfo.texi
index 3b1ade31a6..16e12b12ac 100644
--- a/doc/glibc-functions/sysinfo.texi
+++ b/doc/glibc-functions/sysinfo.texi
@@ -17,4 +17,7 @@
 @item
 This function is missing on some platforms:
 macOS 11.1, FreeBSD 13.0, NetBSD 9.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, Cygwin 1.7.9, mingw, MSVC 14.
+@item
+This function is not declared and thus not part of the Android API
+for Android API levels < 9.
 @end itemize
diff --git a/lib/boot-time-aux.h b/lib/boot-time-aux.h
index 348611fc85..e59a0fd03c 100644
--- a/lib/boot-time-aux.h
+++ b/lib/boot-time-aux.h
@@ -65,6 +65,7 @@ get_linux_uptime (struct timespec *p_uptime)
     }
 # endif
 
+# if HAVE_DECL_SYSINFO /* not available in Android API < 9 */
   /* The sysinfo call returns the uptime with a resolution of 1 sec only.  */
   struct sysinfo info;
   if (sysinfo (&info) >= 0)
@@ -73,6 +74,7 @@ get_linux_uptime (struct timespec *p_uptime)
       p_uptime->tv_nsec = 0;
       return 0;
     }
+# endif
 
   return -1;
 }
diff --git a/m4/readutmp.m4 b/m4/readutmp.m4
index 9dffe981b8..0a47f4bb77 100644
--- a/m4/readutmp.m4
+++ b/m4/readutmp.m4
@@ -1,4 +1,4 @@
-# readutmp.m4 serial 29
+# readutmp.m4 serial 30
 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,
@@ -103,6 +103,10 @@ AC_DEFUN_ONCE([gl_PREREQ_READUTMP_H]
     AC_CHECK_MEMBERS([struct utmp.ut_exit.e_termination],,,[$utmp_includes])
   fi
 
+  AC_CHECK_DECLS([sysinfo],,,[[
+    #include <sys/sysinfo.h>
+    ]])
+
   AC_CHECK_HEADERS_ONCE([sys/param.h])
   dnl <sys/sysctl.h> requires <sys/param.h> on OpenBSD 4.0.
   AC_CHECK_HEADERS([sys/sysctl.h],,,






^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  3:26   ` Po Lu
                       ` (2 preceding siblings ...)
  2023-08-13 14:16     ` Bruno Haible
@ 2023-08-13 14:36     ` Bruno Haible
  2023-08-13 23:44       ` Po Lu
  3 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-13 14:36 UTC (permalink / raw)
  To: Paul Eggert, Po Lu; +Cc: bug-gnulib, Emacs-devel

Po Lu wrote:
> During the automated build of the Android port, the following errors
> were encountered with the Android NDK r10b and __ANDROID_API__ set to 8
> (which is the oldest configuration Emacs supports.)
> ...
> boot-time.c: In function 'get_boot_time_uncached':
> boot-time.c:111:26: error: 'BOOT_TIME' undeclared (first use in this function)
>        if (ut->ut_type == BOOT_TIME)
>                           ^

Unlike USER_PROCESS, which is defined in all versions of Android's <utmp.h>,
BOOT_TIME is only defined in newer versions.

When compiling against an older version, we need to use the value from the
newer versions — otherwise a binary built against an older version might
not work right when running on a newer Android.

This patch does it.


2023-08-13  Bruno Haible  <bruno@clisp.org>

	readutmp, boot-time: Fix compilation error on old Android.
	Reported by Po Lu in
	<https://lists.gnu.org/archive/html/bug-gnulib/2023-08/msg00108.html>.
	* lib/readutmp.h (BOOT_TIME): Add fallback.

diff --git a/lib/readutmp.h b/lib/readutmp.h
index 1cf588d265..f7cad36d44 100644
--- a/lib/readutmp.h
+++ b/lib/readutmp.h
@@ -249,6 +249,13 @@ struct utmpx32
 # define WTMP_FILE "/etc/wtmp"
 #endif
 
+/* In early versions of Android, <utmp.h> did not define BOOT_TIME, only
+   USER_PROCESS.  We need to use the value that is defined in newer versions
+   of Android.  */
+#if defined __ANDROID__ && !defined BOOT_TIME
+# define BOOT_TIME 2
+#endif
+
 /* Some platforms, such as OpenBSD, don't have an ut_type field and don't have
    the BOOT_TIME and USER_PROCESS macros.  But we want to support them in
    'struct gl_utmp'.  */






^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13 14:36     ` Bruno Haible
@ 2023-08-13 23:44       ` Po Lu
  2023-08-13 23:59         ` Bruno Haible
  0 siblings, 1 reply; 24+ messages in thread
From: Po Lu @ 2023-08-13 23:44 UTC (permalink / raw)
  To: Bruno Haible; +Cc: Paul Eggert, bug-gnulib, Emacs-devel

Bruno Haible <bruno@clisp.org> writes:

> Po Lu wrote:
>> During the automated build of the Android port, the following errors
>> were encountered with the Android NDK r10b and __ANDROID_API__ set to 8
>> (which is the oldest configuration Emacs supports.)
>> ...
>> boot-time.c: In function 'get_boot_time_uncached':
>> boot-time.c:111:26: error: 'BOOT_TIME' undeclared (first use in this function)
>>        if (ut->ut_type == BOOT_TIME)
>>                           ^
>
> Unlike USER_PROCESS, which is defined in all versions of Android's <utmp.h>,
> BOOT_TIME is only defined in newer versions.
>
> When compiling against an older version, we need to use the value from the
> newer versions — otherwise a binary built against an older version might
> not work right when running on a newer Android.
>
> This patch does it.
>
>
> 2023-08-13  Bruno Haible  <bruno@clisp.org>
>
> 	readutmp, boot-time: Fix compilation error on old Android.
> 	Reported by Po Lu in
> 	<https://lists.gnu.org/archive/html/bug-gnulib/2023-08/msg00108.html>.
> 	* lib/readutmp.h (BOOT_TIME): Add fallback.
>
> diff --git a/lib/readutmp.h b/lib/readutmp.h
> index 1cf588d265..f7cad36d44 100644
> --- a/lib/readutmp.h
> +++ b/lib/readutmp.h
> @@ -249,6 +249,13 @@ struct utmpx32
>  # define WTMP_FILE "/etc/wtmp"
>  #endif
>  
> +/* In early versions of Android, <utmp.h> did not define BOOT_TIME, only
> +   USER_PROCESS.  We need to use the value that is defined in newer versions
> +   of Android.  */
> +#if defined __ANDROID__ && !defined BOOT_TIME
> +# define BOOT_TIME 2
> +#endif
> +
>  /* Some platforms, such as OpenBSD, don't have an ut_type field and don't have
>     the BOOT_TIME and USER_PROCESS macros.  But we want to support them in
>     'struct gl_utmp'.  */

Both of your patches appear to work.
Thanks.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13 23:44       ` Po Lu
@ 2023-08-13 23:59         ` Bruno Haible
  2023-08-14  1:07           ` Po Lu
  0 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-13 23:59 UTC (permalink / raw)
  To: Po Lu; +Cc: Paul Eggert, bug-gnulib, Emacs-devel

Po Lu wrote:
> Both of your patches appear to work.

Thanks for the confirmation. As you know, I'm using a Termux environment
for testing on Android. This has only approximately, not exactly, the same
include files and libc as what you are using when you compile with some
Android NDK. Therefore I'm relying on your reports for the (few) portability
problems that arise because of differences between Android API levels
or between Android versions.

Bruno






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13 23:59         ` Bruno Haible
@ 2023-08-14  1:07           ` Po Lu
  2023-08-14  2:14             ` Corwin Brust
  0 siblings, 1 reply; 24+ messages in thread
From: Po Lu @ 2023-08-14  1:07 UTC (permalink / raw)
  To: Bruno Haible; +Cc: Paul Eggert, bug-gnulib, Emacs-devel

Bruno Haible <bruno@clisp.org> writes:

> Po Lu wrote:
>> Both of your patches appear to work.
>
> Thanks for the confirmation. As you know, I'm using a Termux environment
> for testing on Android. This has only approximately, not exactly, the same
> include files and libc as what you are using when you compile with some
> Android NDK. Therefore I'm relying on your reports for the (few) portability
> problems that arise because of differences between Android API levels
> or between Android versions.
>
> Bruno

Regular merges from Gnulib into Emacs should facilitate that, since I've
set aside a machine for the express purpose of building the Android port
automatically in response to every large change to the branch.

And thanks again for your help.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14  1:07           ` Po Lu
@ 2023-08-14  2:14             ` Corwin Brust
  2023-08-15 19:57               ` Windows port binaries Bruno Haible
  0 siblings, 1 reply; 24+ messages in thread
From: Corwin Brust @ 2023-08-14  2:14 UTC (permalink / raw)
  To: Po Lu; +Cc: Bruno Haible, Paul Eggert, bug-gnulib, Emacs-devel

On Sun, Aug 13, 2023 at 8:07 PM Po Lu <luangruo@yahoo.com> wrote:
>
> Bruno Haible <bruno@clisp.org> writes:
>
> > Po Lu wrote:
> >> Both of your patches appear to work.
> >
> > Thanks for the confirmation. As you know, I'm using a Termux environment
>
> Regular merges from Gnulib into Emacs should facilitate that, since I've
> set aside a machine for the express purpose of building the Android port
> automatically in response to every large change to the branch.
>

In case it helps others to assist with testing, for the moment I am
aggressively rebuilding the Windows port also, from (not quite every)
commit to emacs-29 or master, posting to:

  https://corwin.bru.st/emacs-29
  https://corwin.bru.st/emacs-30

Note, older release sets get all but the no-deps and source archives
removed; unpack the no-deps archive atop an existing install of the
same version of Emacs to use them for testing purposes after the
installer and full-zip have been pruned.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  2:49 ` boot-time: straighten code Paul Eggert
  2023-08-13  3:26   ` Po Lu
@ 2023-08-14  8:02   ` Andreas Schwab
  2023-08-14  9:15     ` Bruno Haible
  2023-08-15 21:12   ` Bruno Haible
  2 siblings, 1 reply; 24+ messages in thread
From: Andreas Schwab @ 2023-08-14  8:02 UTC (permalink / raw)
  To: Paul Eggert; +Cc: Bruno Haible, bug-gnulib, Emacs Development

In file included from boot-time.c:47:
readutmp.h:145:16: error: ‘__UT_USERSIZE’ undeclared here (not in a function); did you mean ‘UT_USER_SIZE’?
  145 |   char ut_user[__UT_USERSIZE];     /* Username.  */
      |                ^~~~~~~~~~~~~
      |                UT_USER_SIZE
make[3]: *** [Makefile:102: boot-time.o] Error 1

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14  8:02   ` boot-time: straighten code Andreas Schwab
@ 2023-08-14  9:15     ` Bruno Haible
  2023-08-14  9:20       ` Andreas Schwab
  0 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-14  9:15 UTC (permalink / raw)
  To: Paul Eggert, Andreas Schwab; +Cc: bug-gnulib, Emacs Development

Andreas Schwab wrote:
> In file included from boot-time.c:47:
> readutmp.h:145:16: error: ‘__UT_USERSIZE’ undeclared here (not in a function); did you mean ‘UT_USER_SIZE’?
>   145 |   char ut_user[__UT_USERSIZE];     /* Username.  */
>       |                ^~~~~~~~~~~~~
>       |                UT_USER_SIZE
> make[3]: *** [Makefile:102: boot-time.o] Error 1

On which distro or glibc version, please?

Bruno






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14  9:15     ` Bruno Haible
@ 2023-08-14  9:20       ` Andreas Schwab
  2023-08-14 10:19         ` Bruno Haible
  0 siblings, 1 reply; 24+ messages in thread
From: Andreas Schwab @ 2023-08-14  9:20 UTC (permalink / raw)
  To: Bruno Haible; +Cc: Paul Eggert, bug-gnulib, Emacs Development

On Aug 14 2023, Bruno Haible wrote:

> Andreas Schwab wrote:
>> In file included from boot-time.c:47:
>> readutmp.h:145:16: error: ‘__UT_USERSIZE’ undeclared here (not in a function); did you mean ‘UT_USER_SIZE’?
>>   145 |   char ut_user[__UT_USERSIZE];     /* Username.  */
>>       |                ^~~~~~~~~~~~~
>>       |                UT_USER_SIZE
>> make[3]: *** [Makefile:102: boot-time.o] Error 1
>
> On which distro or glibc version, please?

Any.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14  9:20       ` Andreas Schwab
@ 2023-08-14 10:19         ` Bruno Haible
  2023-08-14 10:33           ` Andreas Schwab
  0 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-14 10:19 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Paul Eggert, bug-gnulib, Emacs-devel

Andreas Schwab wrote:
> >> In file included from boot-time.c:47:
> >> readutmp.h:145:16: error: ‘__UT_USERSIZE’ undeclared here (not in a function); did you mean ‘UT_USER_SIZE’?
> >>   145 |   char ut_user[__UT_USERSIZE];     /* Username.  */
> >>       |                ^~~~~~~~~~~~~
> >>       |                UT_USER_SIZE
> >> make[3]: *** [Makefile:102: boot-time.o] Error 1
> >
> > On which distro or glibc version, please?
> 
> Any.

Ah, you mean: on any 32-bit build with glibc.

Fixed through this patch:


2023-08-14  Bruno Haible  <bruno@clisp.org>

	readutmp, boot-time: Fix build on 32-bit glibc (regression 2023-08-11).
	Reported by Andreas Schwab <schwab@suse.de> in
	<https://lists.gnu.org/archive/html/bug-gnulib/2023-08/msg00125.html>.
	* lib/readutmp.h (struct utmpx32): Reference __UT_NAMESIZE, not
	__UT_USERSIZE.

diff --git a/lib/readutmp.h b/lib/readutmp.h
index f7cad36d44..1fbe29d86f 100644
--- a/lib/readutmp.h
+++ b/lib/readutmp.h
@@ -142,7 +142,7 @@ struct utmpx32
   pid_t ut_pid;                    /* Process ID of login process.  */
   char ut_line[__UT_LINESIZE];     /* Devicename.  */
   char ut_id[4];                   /* Inittab ID.  */
-  char ut_user[__UT_USERSIZE];     /* Username.  */
+  char ut_user[__UT_NAMESIZE];     /* Username.  */
   char ut_host[__UT_HOSTSIZE];     /* Hostname for remote login. */
   struct __exit_status ut_exit;    /* Exit status of a process marked
                                       as DEAD_PROCESS.  */






^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14 10:19         ` Bruno Haible
@ 2023-08-14 10:33           ` Andreas Schwab
  2023-08-14 13:51             ` Bruno Haible
  0 siblings, 1 reply; 24+ messages in thread
From: Andreas Schwab @ 2023-08-14 10:33 UTC (permalink / raw)
  To: Bruno Haible; +Cc: Paul Eggert, bug-gnulib, Emacs-devel

On Aug 14 2023, Bruno Haible wrote:

> diff --git a/lib/readutmp.h b/lib/readutmp.h
> index f7cad36d44..1fbe29d86f 100644
> --- a/lib/readutmp.h
> +++ b/lib/readutmp.h
> @@ -142,7 +142,7 @@ struct utmpx32
>    pid_t ut_pid;                    /* Process ID of login process.  */
>    char ut_line[__UT_LINESIZE];     /* Devicename.  */
>    char ut_id[4];                   /* Inittab ID.  */
> -  char ut_user[__UT_USERSIZE];     /* Username.  */
> +  char ut_user[__UT_NAMESIZE];     /* Username.  */
>    char ut_host[__UT_HOSTSIZE];     /* Hostname for remote login. */

That's still using reserved symbols.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14 10:33           ` Andreas Schwab
@ 2023-08-14 13:51             ` Bruno Haible
  2023-08-15 23:03               ` Paul Eggert
  0 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-14 13:51 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Paul Eggert, bug-gnulib, Emacs-devel

Andreas Schwab wrote:
> >    char ut_host[__UT_HOSTSIZE];     /* Hostname for remote login. */
> 
> That's still using reserved symbols.

Fixed through the patch below.

But that is just a workaround. Is someone among the glibc people looking at the
original glibc bug https://sourceware.org/bugzilla/show_bug.cgi?id=30701 ?


2023-08-14  Bruno Haible  <bruno@clisp.org>

	readutmp, boot-time: Don't use __UT_* symbols (regression 2023-08-11).
	* lib/readutmp.h (_GL_UT_USER_SIZE, _GL_UT_ID_SIZE, _GL_UT_LINE_SIZE,
	_GL_UT_HOST_SIZE): New macros.
	(struct utmpx32): Use them.

diff --git a/lib/readutmp.h b/lib/readutmp.h
index 1fbe29d86f..3ddecf3727 100644
--- a/lib/readutmp.h
+++ b/lib/readutmp.h
@@ -136,14 +136,18 @@ enum { UT_HOST_SIZE = -1 };
 /* This is a near-copy of glibc's struct utmpx, which stops working
    after the year 2038.  Unlike the glibc version, struct utmpx32
    describes the file format even if time_t is 64 bits.  */
+#define _GL_UT_USER_SIZE  sizeof (((struct utmpx *) 0)->ut_user)
+#define _GL_UT_ID_SIZE    sizeof (((struct utmpx *) 0)->ut_id)
+#define _GL_UT_LINE_SIZE  sizeof (((struct utmpx *) 0)->ut_line)
+#define _GL_UT_HOST_SIZE  sizeof (((struct utmpx *) 0)->ut_host)
 struct utmpx32
 {
   short int ut_type;               /* Type of login.  */
   pid_t ut_pid;                    /* Process ID of login process.  */
-  char ut_line[__UT_LINESIZE];     /* Devicename.  */
-  char ut_id[4];                   /* Inittab ID.  */
-  char ut_user[__UT_NAMESIZE];     /* Username.  */
-  char ut_host[__UT_HOSTSIZE];     /* Hostname for remote login. */
+  char ut_line[_GL_UT_LINE_SIZE];  /* Devicename.  */
+  char ut_id[_GL_UT_ID_SIZE];      /* Inittab ID.  */
+  char ut_user[_GL_UT_USER_SIZE];  /* Username.  */
+  char ut_host[_GL_UT_HOST_SIZE];  /* Hostname for remote login. */
   struct __exit_status ut_exit;    /* Exit status of a process marked
                                       as DEAD_PROCESS.  */
   /* The fields ut_session and ut_tv must be the same size when compiled






^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: Windows port binaries
  2023-08-14  2:14             ` Corwin Brust
@ 2023-08-15 19:57               ` Bruno Haible
  2023-08-16  6:45                 ` Po Lu
  2023-08-16 11:36                 ` Eli Zaretskii
  0 siblings, 2 replies; 24+ messages in thread
From: Bruno Haible @ 2023-08-15 19:57 UTC (permalink / raw)
  To: Corwin Brust, Emacs-devel; +Cc: Po Lu, Paul Eggert

Corwin Brust wrote:
> In case it helps others to assist with testing, for the moment I am
> aggressively rebuilding the Windows port also, from (not quite every)
> commit to emacs-29 or master, posting to:
> 
>   https://corwin.bru.st/emacs-29
>   https://corwin.bru.st/emacs-30

Thanks. I tried to use the
https://corwin.bru.st/emacs-30/emacs-30-latest-no-deps.zip
binary from today, but they don't work for me (on Windows 10), because
they rely on two DLLs which are not contained in the 'bin' directory:
  - libgmp-10.dll
  - libwinpthread-1.dll

Find below the output of "dumpbin.exe /imports emacs.exe".

Additionally, I find it strange:

  1) Why are the imports from libgmp all prefixed with '__'? That's
     a bit unusual.

  2) emacs/nt/mingw-cfg.site contains this comment:
       # We don't want to check for these functions
       # because they are implemented in libwinpthread.
     corresponding to this ChangeLog entry:

       2016-04-21  Fabrice Popineau  <fabrice.popineau@gmail.com>

               Avoid run-time dependency on libwinpthread DLL on MS-Windows

               * nt/mingw-cfg.site (ac_cv_search_clock_gettime)
               (ac_cv_func_clock_gettime, ac_cv_func_clock_settime): Force to not
               present, so that MinGW64 builds don't depend on libwinpthread.
               (Bug#22959)

     However, the binaries rely on nanosleep() from libwinpthread.
     Is it intended or unintended?
     If it is unintended, does it come from Gnulib? In this case, I'll gladly
     help to do anything needed in Gnulib to help avoid this import.

Bruno

==================== dumpbin /imports ==============================
Microsoft (R) COFF/PE Dumper Version 14.00.24210.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file emacs.exe

File Type: EXECUTABLE IMAGE

  Section contains the following imports:

    ADVAPI32.dll
             400810540 Import Address Table
             40080F140 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                         407 AdjustTokenPrivileges
                         4A9 CryptAcquireContextA
                         4BA CryptGenRandom
                         563 GetUserNameA
                         596 LookupPrivilegeValueA
                         643 RegCloseKey
                         664 RegEnumValueA
                         673 RegOpenKeyExA
                         680 RegQueryValueExA

    COMCTL32.dll
             400810590 Import Address Table
             40080F190 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          68 InitCommonControls

    comdlg32.dll
             4008105A0 Import Address Table
             40080F1A0 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                           3 ChooseFontA
                           5 CommDlgExtendedError
                           A GetOpenFileNameA
                           B GetOpenFileNameW

    GDI32.dll
             4008105C8 Import Address Table
             40080F1C8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          14 BitBlt
                          23 CombineRgn
                          2A CreateBitmap
                          31 CreateCompatibleBitmap
                          32 CreateCompatibleDC
                          33 CreateDCA
                          38 CreateDIBSection
                          41 CreateFontIndirectA
                          4E CreatePalette
                          50 CreatePen
                          54 CreateRectRgn
                          55 CreateRectRgnIndirect
                          5B CreateSolidBrush
                         181 DeleteDC
                         184 DeleteObject
                         1C4 EnumFontFamiliesExA
                         1CD EqualRgn
                         1D7 ExtTextOutA
                         1D8 ExtTextOutW
                         270 GetClipBox
                         271 GetClipRgn
                         275 GetCurrentObject
                         27D GetDeviceCaps
                         28B GetFontData
                         2AD GetObjectA
                         2B6 GetPixel
                         2D0 GetTextExtentPoint32A
                         2D1 GetTextExtentPoint32W
                         2D5 GetTextFaceA
                         2D8 GetTextMetricsA
                         2EB LineTo
                         2FF MoveToEx
                         30B PatBlt
                         321 RealizePalette
                         324 Rectangle
                         32E RestoreDC
                         335 SaveDC
                         364 SelectClipRgn
                         366 SelectObject
                         367 SelectPalette
                         36D SetBkColor
                         36E SetBkMode
                         371 SetBrushOrgEx
                         391 SetStretchBltMode
                         393 SetTextAlign
                         395 SetTextColor
                         3A2 StretchBlt
                         3A9 TranslateCharsetInfo

    libgmp-10.dll
             400810750 Import Address Table
             40080F350 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          3D __gmp_set_memory_functions
                         1F8 __gmpn_popcount
                         2DC __gmpz_add
                         2DD __gmpz_add_ui
                         2DE __gmpz_addmul
                         2DF __gmpz_addmul_ui
                         2E0 __gmpz_and
                         2E5 __gmpz_cdiv_q
                         2EE __gmpz_clear
                         2F1 __gmpz_cmp
                         2F2 __gmpz_cmp_d
                         2F4 __gmpz_cmp_ui
                         2F5 __gmpz_cmpabs
                         2F8 __gmpz_com
                         2FD __gmpz_divexact
                         304 __gmpz_export
                         306 __gmpz_fdiv_q
                         307 __gmpz_fdiv_q_2exp
                         308 __gmpz_fdiv_q_ui
                         309 __gmpz_fdiv_qr
                         30B __gmpz_fdiv_r
                         317 __gmpz_gcd
                         31A __gmpz_get_d
                         31D __gmpz_get_str
                         321 __gmpz_import
                         322 __gmpz_init
                         328 __gmpz_init_set_ui
                         32E __gmpz_ior
                         335 __gmpz_limbs_finish
                         337 __gmpz_limbs_read
                         338 __gmpz_limbs_write
                         33F __gmpz_mul
                         340 __gmpz_mul_2exp
                         342 __gmpz_mul_ui
                         34C __gmpz_pow_ui
                         358 __gmpz_roinit_n
                         35D __gmpz_scan1
                         35E __gmpz_set
                         35F __gmpz_set_d
                         362 __gmpz_set_si
                         363 __gmpz_set_str
                         364 __gmpz_set_ui
                         368 __gmpz_sizeinbase
                         36C __gmpz_sub
                         36D __gmpz_sub_ui
                         36E __gmpz_submul
                         370 __gmpz_swap
                         371 __gmpz_tdiv_q
                         374 __gmpz_tdiv_qr
                         376 __gmpz_tdiv_r
                         379 __gmpz_tdiv_ui
                         37C __gmpz_ui_pow_ui
                         380 __gmpz_xor

    KERNEL32.dll
             400810900 Import Address Table
             40080F500 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          29 BackupWrite
                          6B Beep
                          78 CancelIo
                          8D CloseHandle
                          9E CompareFileTime
                          A2 CompareStringW
                          B1 CopyFileA
                          B6 CopyFileW
                          C5 CreateEventA
                          CC CreateFileA
                          CD CreateFileMappingA
                          D4 CreateFileW
                          EA CreateProcessA
                          FC CreateThread
                         111 DebugBreak
                         11B DeleteCriticalSection
                         12B DeviceIoControl
                         12C DisableThreadLibraryCalls
                         139 DuplicateHandle
                         13F EnterCriticalSection
                         15A EnumSystemCodePagesA
                         161 EnumSystemLocalesA
                         171 ExpandEnvironmentStringsA
                         17B FillConsoleOutputAttribute
                         17C FillConsoleOutputCharacterA
                         185 FindClose
                         189 FindFirstFileA
                         190 FindFirstFileW
                         19A FindNextFileA
                         19C FindNextFileW
                         1AE FlushConsoleInputBuffer
                         1B6 FormatMessageA
                         1BB FreeLibrary
                         1C1 GenerateConsoleCtrlEvent
                         1C2 GetACP
                         1D2 GetCPInfo
                         1E5 GetCommState
                         1E6 GetCommTimeouts
                         1E7 GetCommandLineA
                         1ED GetComputerNameA
                         1FB GetConsoleCP
                         201 GetConsoleCursorInfo
                         20D GetConsoleMode
                         211 GetConsoleOutputCP
                         213 GetConsoleScreenBufferInfo
                         217 GetConsoleTitleW
                         221 GetCurrentDirectoryA
                         222 GetCurrentDirectoryW
                         228 GetCurrentProcess
                         229 GetCurrentProcessId
                         22C GetCurrentThread
                         22D GetCurrentThreadId
                         239 GetDiskFreeSpaceA
                         23C GetDiskFreeSpaceW
                         241 GetDriveTypeA
                         24C GetEnvironmentVariableA
                         250 GetExitCodeProcess
                         251 GetExitCodeThread
                         256 GetFileAttributesA
                         25B GetFileAttributesW
                         25D GetFileInformationByHandle
                         261 GetFileSize
                         264 GetFileType
                         26C GetFullPathNameA
                         26F GetFullPathNameW
                         276 GetLastError
                         279 GetLocaleInfoA
                         289 GetModuleFileNameA
                         28A GetModuleFileNameW
                         28B GetModuleHandleA
                         298 GetNamedPipeInfo
                         2AD GetNumberOfConsoleInputEvents
                         2AF GetOEMCP
                         2B0 GetOverlappedResult
                         2C6 GetProcAddress
                         2CC GetProcessHeap
                         2E0 GetProfileStringA
                         2E4 GetShortPathNameA
                         2E5 GetShortPathNameW
                         2E7 GetStartupInfoA
                         2EA GetStdHandle
                         2F3 GetSystemDefaultLCID
                         2FB GetSystemInfo
                         2FC GetSystemPowerStatus
                         301 GetSystemTimeAsFileTime
                         317 GetThreadLocale
                         31F GetTickCount
                         32C GetUserDefaultLCID
                         333 GetVersion
                         334 GetVersionExA
                         336 GetVolumeInformationA
                         338 GetVolumeInformationW
                         347 GlobalAlloc
                         34E GlobalFree
                         351 GlobalHandle
                         352 GlobalLock
                         359 GlobalUnlock
                         35F HeapAlloc
                         361 HeapCreate
                         365 HeapFree
                         369 HeapReAlloc
                         37C InitializeCriticalSection
                         397 IsDBCSLeadByteEx
                         3A5 IsValidCodePage
                         3A7 IsValidLocale
                         3D8 LeaveCriticalSection
                         3DC LoadLibraryA
                         3DF LoadLibraryW
                         3EA LocalFree
                         3FB MapViewOfFile
                         3FC MapViewOfFileEx
                         40C MultiByteToWideChar
                         42D OpenProcess
                         436 OutputDebugStringA
                         440 PeekNamedPipe
                         45B PulseEvent
                         45C PurgeComm
                         475 QueueUserAPC
                         481 RaiseException
                         486 ReadConsoleInputA
                         489 ReadConsoleInputW
                         491 ReadDirectoryChangesW
                         492 ReadFile
                         495 ReadProcessMemory
                         4BE ResetEvent
                         4C5 ResumeThread
                         4D7 ScrollConsoleScreenBufferA
                         4E3 SetCommState
                         4E4 SetCommTimeouts
                         4EA SetConsoleActiveScreenBuffer
                         4EB SetConsoleCP
                         4ED SetConsoleCtrlHandler
                         4EF SetConsoleCursorInfo
                         4F1 SetConsoleCursorPosition
                         4FD SetConsoleMode
                         502 SetConsoleOutputCP
                         505 SetConsoleScreenBufferSize
                         508 SetConsoleTitleW
                         509 SetConsoleWindowInfo
                         514 SetEndOfFile
                         519 SetErrorMode
                         51A SetEvent
                         51F SetFileAttributesA
                         522 SetFileAttributesW
                         527 SetFilePointer
                         52B SetFileTime
                         536 SetLastError
                         53F SetNamedPipeHandleState
                         540 SetPriorityClass
                         54E SetStdHandle
                         560 SetThreadLocale
                         562 SetThreadPriority
                         572 SetUnhandledExceptionFilter
                         582 Sleep
                         58A SuspendThread
                         58D SystemTimeToFileTime
                         591 TerminateProcess
                         592 TerminateThread
                         5A5 TlsGetValue
                         5B6 UnmapViewOfFile
                         5CE VirtualAlloc
                         5D1 VirtualFree
                         5D4 VirtualProtect
                         5D6 VirtualQuery
                         5DD WaitForMultipleObjects
                         5DF WaitForSingleObject
                         5E0 WaitForSingleObjectEx
                         60B WideCharToMultiByte
                         615 WriteConsoleInputA
                         618 WriteConsoleInputW
                         61B WriteConsoleOutputCharacterA
                         61F WriteFile
                         642 lstrcmpiA
                         64C lstrlenW

    MPR.dll
             400810E78 Import Address Table
             40080FA78 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                           E WNetAddConnection2A
                           F WNetAddConnection2W
                          19 WNetCloseEnum
                          24 WNetEnumResourceA
                          25 WNetEnumResourceW
                          48 WNetOpenEnumA
                          49 WNetOpenEnumW

    msvcrt.dll
             400810EB8 Import Address Table
             40080FAB8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          38 __C_specific_handler
                          40 ___lc_codepage_func
                          43 ___mb_cur_max_func
                          52 __getmainargs
                          53 __initenv
                          54 __iob_func
                          62 __set_app_type
                          64 __setusermatherr
                          74 _acmdln
                          7C _amsg_exit
                          89 _beginthread
                          8E _cexit
                          91 _chdir
                          97 _chmod
                          9B _close
                          9D _commit
                          9E _commode
                          A7 _chdir
                          AA _creat
                          B0 _ctime64
                          BF _difftime64
                          C1 _dup
                          C2 _dup2
                          C9 _environ
                          CB _errno
                          FB _exit
                          DE _fdopen
                          E8 _fileno
                          FF _fmode
                         11C _futime64
                         127 _get_osfhandle
                         135 _getmbcp
                         136 _getpid
                         13E _gmtime64
                         14B _initterm
                         153 _hypot
                         150 _isatty
                         1BA _localtime64
                         1BB _lock
                         1C6 _lseeki64
                         1ED _mbschr
                         1FF _mbsinc
                         203 _mbslwr
                         227 _mbsncpy
                         22B _mbsnextc
                         239 _mbspbrk
                         23B _mbsrchr
                         258 _memccpy
                         25D _mkdir
                         261 _mktime64
                         267 _onexit
                         269 _open
                         26A _open_osfhandle
                         271 _pipe
                         27A _putenv
                         281 _read
                         284 _rmdir
                         29E _setjmp
                         2A2 _setmode
                         2A6 _snprintf
                         2C0 _spawnlp
                         2DA _stricmp
                         2D8 _strdup
                         2E4 _strlwr
                         2F1 _strnicmp
                         313 _sys_errlist
                         314 _sys_nerr
                         319 _time64
                         324 _tzname
                         325 _tzset
                         32F _umask
                         333 _unlink
                         334 _unlock
                         373 _wchdir
                         374 _wchmod
                         376 _wcreat
                         3C7 _wgetenv
                         3CF _wmkdir
                         3D1 _wopen
                         3DE _wrename
                         3E0 _write
                         3E1 _wrmdir
                         406 _wunlink
                         41F abort
                         41D acos
                         410 asin
                         412 atan
                         417 atof
                         418 atoi
                         421 calloc
                         424 clearerr
                         426 clock
                         42E exit
                         432 fclose
                         433 feof
                         434 ferror
                         435 fflush
                         437 fgetpos
                         439 fgets
                         442 fprintf
                         444 fputc
                         445 fputs
                         448 fread
                         449 free
                         451 fseek
                         456 fwrite
                         45A getc
                         45B getchar
                         45C getenv
                         464 isalpha
                         469 islower
                         46C isspace
                         46D isupper
                         47B isxdigit
                         47F localeconv
                         482 log10
                         485 longjmp
                         486 malloc
                         48C memchr
                         48D memcmp
                         48E memcpy
                         48F memmove
                         490 memset
                         49A putc
                         49B putchar
                         49F qsort
                         4A1 raise
                         4A3 realloc
                         4A2 rand
                         4A6 rename
                         4AC setlocale
                         4AD setvbuf
                         4AE signal
                         4B7 srand
                         4BB strcat
                         4BD strchr
                         4BE strcmp
                         4C0 strcpy
                         4C3 strerror
                         4C4 strftime
                         4C5 strlen
                         4C6 strncat
                         4C8 strncmp
                         4C9 strncpy
                         4CB strpbrk
                         4CC strrchr
                         4CD strspn
                         4CE strstr
                         4D1 strtok
                         4D3 strtol
                         4D4 strtoul
                         4DD tan
                         4E5 tolower
                         4E6 toupper
                         4E9 ungetc
                         4EC vfprintf
                         4FC wcscat
                         501 wcscpy
                         505 wcslen
                         509 wcsncpy

    ole32.dll
             4008113C0 Import Address Table
             40080FFC0 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          1E CoCreateGuid
                          55 CoInitialize
                          85 CoUninitialize
                         1FA StringFromGUID2

    libwinpthread-1.dll
             4008113E8 Import Address Table
             40080FFE8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          10 nanosleep

    SHELL32.dll
             4008113F8 Import Address Table
             40080FFF8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          20 DragAcceptFiles
                          21 DragFinish
                          23 DragQueryFileA
                          25 DragQueryFileW
                          26 DragQueryPoint
                          BD SHFileOperationA
                          BE SHFileOperationW
                         152 ShellExecuteExA
                         153 ShellExecuteExW
                         160 Shell_NotifyIconW

    USER32.dll
             400811450 Import Address Table
             400810050 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                           1 ActivateKeyboardLayout
                           3 AdjustWindowRect
                           B AppendMenuA
                           F AttachThreadInput
                          10 BeginDeferWindowPos
                          11 BeginPaint
                          13 BringWindowToTop
                          1F CallNextHookEx
                          31 CharLowerW
                          32 CharNextA
                          33 CharNextExA
                          35 CharPrevA
                          48 ChildWindowFromPoint
                          4C ClientToScreen
                          4E CloseClipboard
                          5E CreateCaret
                          70 CreateMenu
                          71 CreatePopupMenu
                          73 CreateWindowExA
                          A4 DefWindowProcA
                          A5 DefWindowProcW
                          A6 DeferWindowPos
                          A8 DeleteMenu
                          AB DestroyCaret
                          AE DestroyIcon
                          AF DestroyMenu
                          B1 DestroyWindow
                          B9 DispatchMessageA
                          BA DispatchMessageW
                          DB DrawTextW
                          E6 EmptyClipboard
                          EC EnableWindow
                          ED EndDeferWindowPos
                          F1 EndPaint
                          F5 EnumClipboardFormats
                         107 EnumWindows
                         10D FillRect
                         10E FindWindowA
                         111 FindWindowW
                         112 FlashWindow
                         114 FrameRect
                         11E GetAsyncKeyState
                         12D GetClassNameA
                         130 GetClientRect
                         133 GetClipboardData
                         134 GetClipboardFormatNameA
                         13E GetCursorPos
                         13F GetDC
                         142 GetDesktopWindow
                         147 GetDlgItem
                         14B GetDoubleClickTime
                         14F GetFocus
                         150 GetForegroundWindow
                         15E GetKeyNameTextA
                         160 GetKeyState
                         161 GetKeyboardLayout
                         162 GetKeyboardLayoutList
                         165 GetKeyboardState
                         16E GetMenu
                         16F GetMenuBarInfo
                         174 GetMenuItemCount
                         17C GetMessageA
                         17F GetMessageTime
                         180 GetMessageW
                         187 GetParent
                         1AF GetScrollInfo
                         1B8 GetSystemMetrics
                         1C1 GetTopWindow
                         1C4 GetUpdateRect
                         1CB GetWindow
                         1D0 GetWindowDC
                         1D4 GetWindowInfo
                         1D5 GetWindowLongA
                         1DD GetWindowPlacement
                         1DE GetWindowRect
                         1E6 GetWindowThreadProcessId
                         1EB HideCaret
                         20A InvalidateRect
                         238 KillTimer
                         241 LoadIconA
                         243 LoadImageA
                         244 LoadImageW
                         25C MapVirtualKeyA
                         260 MapWindowPoints
                         264 MessageBeep
                         265 MessageBoxA
                         273 MsgWaitForMultipleObjects
                         27D OpenClipboard
                         28A PeekMessageA
                         28B PeekMessageW
                         28E PostMessageA
                         291 PostThreadMessageA
                         2B8 RegisterClassA
                         2BB RegisterClassW
                         2C4 RegisterHotKey
                         2D6 RegisterWindowMessageA
                         2D8 ReleaseCapture
                         2D9 ReleaseDC
                         2E3 ScreenToClient
                         2E7 ScrollWindowEx
                         2EC SendInput
                         2ED SendMessageA
                         2F0 SendMessageTimeoutA
                         2F2 SendMessageW
                         2F6 SetCapture
                         2F8 SetCaretPos
                         2FE SetClipboardData
                         302 SetCursor
                         304 SetCursorPos
                         30E SetFocus
                         30F SetForegroundWindow
                         313 SetKeyboardState
                         31B SetMenu
                         325 SetParent
                         331 SetRectEmpty
                         332 SetScrollInfo
                         340 SetTimer
                         34B SetWindowLongA
                         34F SetWindowPlacement
                         350 SetWindowPos
                         354 SetWindowTextA
                         355 SetWindowTextW
                         358 SetWindowsHookExA
                         35B ShowCaret
                         35C ShowCursor
                         361 ShowWindow
                         36F SystemParametersInfoA
                         371 SystemParametersInfoW
                         376 ToAscii
                         378 ToUnicode
                         37B TrackPopupMenu
                         381 TranslateMessage
                         385 UnhookWindowsHookEx
                         386 UnionRect
                         38D UnregisterHotKey
                         3AB VkKeyScanW
                         3B8 WindowFromPoint
                         3BC keybd_event

    USP10.dll
             4008118A8 Import Address Table
             4008104A8 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                           7 ScriptFreeCache
                           8 ScriptGetCMap
                           E ScriptGetGlyphABCWidth
                          12 ScriptItemize
                          16 ScriptPlace
                          1A ScriptShape

    WINMM.dll
             4008118E0 Import Address Table
             4008104E0 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          3B mciGetErrorStringA
                          41 mciSendStringA
                          42 mciSendStringW
                          BB waveOutGetErrorTextA
                          C2 waveOutGetVolume
                          CB waveOutSetVolume

    WINSPOOL.DRV
             400811918 Import Address Table
             400810518 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                          1E ClosePrinter
                          81 GetPrinterA
                          8E GetPrinterW
                          96 OpenPrinterA

  Summary

        1000 .CRT
       9B000 .bss
      476000 .data
        7000 .debug_abbrev
        1000 .debug_aranges
        4000 .debug_frame
       1F000 .debug_info
        F000 .debug_line
        6000 .debug_line_str
       13000 .debug_loclists
        1000 .debug_rnglists
        1000 .debug_str
        6000 .idata
        F000 .pdata
       3B000 .rdata
        4000 .reloc
       5C000 .rsrc
       23000 .subrs
      280000 .text
        1000 .tls
       10000 .xdata






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-13  2:49 ` boot-time: straighten code Paul Eggert
  2023-08-13  3:26   ` Po Lu
  2023-08-14  8:02   ` boot-time: straighten code Andreas Schwab
@ 2023-08-15 21:12   ` Bruno Haible
  2023-08-16 10:13     ` Bruno Haible
  2 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-15 21:12 UTC (permalink / raw)
  To: Paul Eggert; +Cc: bug-gnulib, Emacs-devel

Paul Eggert wrote:
> I installed the attached patch into Emacs 
> master, which you should be able to test via:
> 
> 	git clone https://git.savannah.gnu.org/git/emacs.git
> 	cd emacs
> 	./autogen.sh
> 	./configure
> 	make
> 	src/emacs
> 
> Please give it a try, especially on any MS-Windows platform you happen 
> to have. I have tested only on Ubuntu 23.04 so far.
> 
> A simple way to test is to use Emacs to start editing a file (without 
> saving) and then inspect the symbolic link .#* that Emacs uses as a lock 
> file. The trailing digits of that link's contents should be the boot 
> time. These symlinks are Emacs's only use of boot time.

Here are my test results. On each of the following platforms, after
regenerating the current 'configure' file and then building the 'emacs'
directory from today, with the configure options
  --disable-silent-rules --without-all --without-x
then running "./emacs $HOME/hello.c", editing that buffer, opening
a 'M-x shell' buffer, and looking at the $HOME/.#hello.c symlink,
I can see that its last component is exactly the time_t value of the
boot time, as displayed by the gnulib 'test-readutmp' test. So, the
test passes on all these platforms:
  - Linux: Ubuntu 22.04, Alpine Linux
  - Debian GNU/Hurd 2022
  - Debian GNU/kFreeBSD 7
  - NetBSD 9.3
  - OpenBSD 7.2
  - Cygwin 2.9.0

I could not test the Windows binaries from corwin, due to problems mentioned in
<https://lists.gnu.org/archive/html/emacs-devel/2023-08/msg00543.html>.

Also, I could not test on Android (in Termux), due to a build failure, cf.
<https://github.com/termux/termux-packages/issues/6592>.

Bruno






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-14 13:51             ` Bruno Haible
@ 2023-08-15 23:03               ` Paul Eggert
  0 siblings, 0 replies; 24+ messages in thread
From: Paul Eggert @ 2023-08-15 23:03 UTC (permalink / raw)
  To: Bruno Haible, Andreas Schwab; +Cc: bug-gnulib, Emacs-devel

On 2023-08-14 06:51, Bruno Haible wrote:
> But that is just a workaround. Is someone among the glibc people looking at the
> original glibc bughttps://sourceware.org/bugzilla/show_bug.cgi?id=30701  ?

As far as I know, nobody is looking into it other than you and me. I 
think it's low priority as people are assuming that until 2038 nobody 
should use both _TIME_BITS=64 and utmp/utmpx on 32-bit x86 or arm, and 
by 2038 (when things also stop working on 64-bit x86-64 and arm64) 
utmp/utmpx will be gone anyway.

Given the slow rate of progress in the Y2038 area I'm not sure this 
assumption is correct.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Windows port binaries
  2023-08-15 19:57               ` Windows port binaries Bruno Haible
@ 2023-08-16  6:45                 ` Po Lu
  2023-08-16 11:36                 ` Eli Zaretskii
  1 sibling, 0 replies; 24+ messages in thread
From: Po Lu @ 2023-08-16  6:45 UTC (permalink / raw)
  To: Bruno Haible; +Cc: Corwin Brust, Emacs-devel, Paul Eggert

Bruno Haible <bruno@clisp.org> writes:

> Corwin Brust wrote:
>> In case it helps others to assist with testing, for the moment I am
>> aggressively rebuilding the Windows port also, from (not quite every)
>> commit to emacs-29 or master, posting to:
>> 
>>   https://corwin.bru.st/emacs-29
>>   https://corwin.bru.st/emacs-30
>
> Thanks. I tried to use the
> https://corwin.bru.st/emacs-30/emacs-30-latest-no-deps.zip
> binary from today, but they don't work for me (on Windows 10), because
> they rely on two DLLs which are not contained in the 'bin' directory:
>   - libgmp-10.dll
>   - libwinpthread-1.dll
>
> Find below the output of "dumpbin.exe /imports emacs.exe".
>
> Additionally, I find it strange:
>
>   1) Why are the imports from libgmp all prefixed with '__'? That's
>      a bit unusual.

GMP prefers such a naming convention for their exported symbols.  These
symbols are defined to their programmer-facing names in gmp.h.

>   2) emacs/nt/mingw-cfg.site contains this comment:
>        # We don't want to check for these functions
>        # because they are implemented in libwinpthread.
>      corresponding to this ChangeLog entry:
>
>        2016-04-21  Fabrice Popineau  <fabrice.popineau@gmail.com>
>
>                Avoid run-time dependency on libwinpthread DLL on MS-Windows
>
>                * nt/mingw-cfg.site (ac_cv_search_clock_gettime)
>                (ac_cv_func_clock_gettime, ac_cv_func_clock_settime): Force to not
>                present, so that MinGW64 builds don't depend on libwinpthread.
>                (Bug#22959)
>
>      However, the binaries rely on nanosleep() from libwinpthread.
>      Is it intended or unintended?
>      If it is unintended, does it come from Gnulib? In this case, I'll gladly
>      help to do anything needed in Gnulib to help avoid this import.

I was under the impression that Emacs is supposed to use the nanosleep
from MinGW, so this should be investigated.



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: boot-time: straighten code
  2023-08-15 21:12   ` Bruno Haible
@ 2023-08-16 10:13     ` Bruno Haible
  0 siblings, 0 replies; 24+ messages in thread
From: Bruno Haible @ 2023-08-16 10:13 UTC (permalink / raw)
  To: Paul Eggert; +Cc: bug-gnulib, Emacs-devel

I wrote:
> So, the test passes on all these platforms:
>   - Linux: Ubuntu 22.04, Alpine Linux
>   - Debian GNU/Hurd 2022
>   - Debian GNU/kFreeBSD 7
>   - NetBSD 9.3
>   - OpenBSD 7.2
>   - Cygwin 2.9.0

It passes also on Android 11, within the Termux app.
(I now got past the build failure.)

Bruno






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Windows port binaries
  2023-08-15 19:57               ` Windows port binaries Bruno Haible
  2023-08-16  6:45                 ` Po Lu
@ 2023-08-16 11:36                 ` Eli Zaretskii
  2023-08-17 14:01                   ` Bruno Haible
  1 sibling, 1 reply; 24+ messages in thread
From: Eli Zaretskii @ 2023-08-16 11:36 UTC (permalink / raw)
  To: Bruno Haible; +Cc: corwin, Emacs-devel, luangruo, eggert

> From: Bruno Haible <bruno@clisp.org>
> Cc: Po Lu <luangruo@yahoo.com>, Paul Eggert <eggert@cs.ucla.edu>
> Date: Tue, 15 Aug 2023 21:57:47 +0200
> 
> >   https://corwin.bru.st/emacs-29
> >   https://corwin.bru.st/emacs-30
> 
> Thanks. I tried to use the
> https://corwin.bru.st/emacs-30/emacs-30-latest-no-deps.zip
> binary from today, but they don't work for me (on Windows 10), because
> they rely on two DLLs which are not contained in the 'bin' directory:
>   - libgmp-10.dll
>   - libwinpthread-1.dll

libwinpthread-1.dll shouldn't be there.  But maybe there's no way to
avoid that with MinGW64 ports of GCC.  See below.

> Find below the output of "dumpbin.exe /imports emacs.exe".

A more GNU-friendly way is

  objdump -p emacs.exe | fgrep "DLL Name:"

> Additionally, I find it strange:
> 
>   1) Why are the imports from libgmp all prefixed with '__'? That's
>      a bit unusual.

Why are you asking us?  The Emacs project doesn't build libgmp, it
only uses it.  This question shouldf go to the GMP developers, IMO.

>   2) emacs/nt/mingw-cfg.site contains this comment:
>        # We don't want to check for these functions
>        # because they are implemented in libwinpthread.
>      corresponding to this ChangeLog entry:
> 
>        2016-04-21  Fabrice Popineau  <fabrice.popineau@gmail.com>
> 
>                Avoid run-time dependency on libwinpthread DLL on MS-Windows
> 
>                * nt/mingw-cfg.site (ac_cv_search_clock_gettime)
>                (ac_cv_func_clock_gettime, ac_cv_func_clock_settime): Force to not
>                present, so that MinGW64 builds don't depend on libwinpthread.
>                (Bug#22959)
> 
>      However, the binaries rely on nanosleep() from libwinpthread.
>      Is it intended or unintended?

I guess this is some kind of regression.  But I'm not sure we can
avoid this, when MinGW64 is used.  (I use mingw.org's MinGW, and my
Emacs on Windows doesn't have the libwinpthread dependency.)



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Windows port binaries
  2023-08-16 11:36                 ` Eli Zaretskii
@ 2023-08-17 14:01                   ` Bruno Haible
  2023-08-17 14:14                     ` Eli Zaretskii
  0 siblings, 1 reply; 24+ messages in thread
From: Bruno Haible @ 2023-08-17 14:01 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: corwin, Emacs-devel, luangruo, eggert

Eli Zaretskii wrote:
> > they rely on two DLLs which are not contained in the 'bin' directory:
> >   - libgmp-10.dll
> >   - libwinpthread-1.dll
> 
> libwinpthread-1.dll shouldn't be there. ...
> But I'm not sure we can avoid this, when MinGW64 is used.

The dependency comes from Gnulib. Emacs uses the gnulib module 'nanosleep',
and it picks the nanosleep function from libwinpthread-1.dll. I can reproduce
this directly in Gnulib.

Since this DLL dependency is an annoyance also for other people who produce
Windows binaries (I'm thinking of gettext and others), I'll change Gnulib
to avoid this dependency.

> A more GNU-friendly way is
> 
>   objdump -p emacs.exe | fgrep "DLL Name:"

Thanks; that's a nice shortcut, because I usually have 'objdump' in my $PATH.

Bruno






^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Windows port binaries
  2023-08-17 14:01                   ` Bruno Haible
@ 2023-08-17 14:14                     ` Eli Zaretskii
  0 siblings, 0 replies; 24+ messages in thread
From: Eli Zaretskii @ 2023-08-17 14:14 UTC (permalink / raw)
  To: Bruno Haible; +Cc: corwin, Emacs-devel, luangruo, eggert

> From: Bruno Haible <bruno@clisp.org>
> Cc: corwin@bru.st, Emacs-devel@gnu.org, luangruo@yahoo.com, eggert@cs.ucla.edu
> Date: Thu, 17 Aug 2023 16:01:23 +0200
> 
> Eli Zaretskii wrote:
> > > they rely on two DLLs which are not contained in the 'bin' directory:
> > >   - libgmp-10.dll
> > >   - libwinpthread-1.dll
> > 
> > libwinpthread-1.dll shouldn't be there. ...
> > But I'm not sure we can avoid this, when MinGW64 is used.
> 
> The dependency comes from Gnulib. Emacs uses the gnulib module 'nanosleep',
> and it picks the nanosleep function from libwinpthread-1.dll. I can reproduce
> this directly in Gnulib.
> 
> Since this DLL dependency is an annoyance also for other people who produce
> Windows binaries (I'm thinking of gettext and others), I'll change Gnulib
> to avoid this dependency.

Thanks, but please allow MinGW to use its own implementation if time.h
declares it and a test program calling it links without pthreads.  At
least mingw.org's MinGW does have nanosleep which doesn't need
pthreads.



^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2023-08-17 14:14 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <4536176.VaOIPsP7d9@nimes>
2023-08-13  2:49 ` boot-time: straighten code Paul Eggert
2023-08-13  3:26   ` Po Lu
2023-08-13  6:35     ` Paul Eggert
2023-08-13 13:45     ` Bruno Haible
2023-08-13 14:16     ` Bruno Haible
2023-08-13 14:36     ` Bruno Haible
2023-08-13 23:44       ` Po Lu
2023-08-13 23:59         ` Bruno Haible
2023-08-14  1:07           ` Po Lu
2023-08-14  2:14             ` Corwin Brust
2023-08-15 19:57               ` Windows port binaries Bruno Haible
2023-08-16  6:45                 ` Po Lu
2023-08-16 11:36                 ` Eli Zaretskii
2023-08-17 14:01                   ` Bruno Haible
2023-08-17 14:14                     ` Eli Zaretskii
2023-08-14  8:02   ` boot-time: straighten code Andreas Schwab
2023-08-14  9:15     ` Bruno Haible
2023-08-14  9:20       ` Andreas Schwab
2023-08-14 10:19         ` Bruno Haible
2023-08-14 10:33           ` Andreas Schwab
2023-08-14 13:51             ` Bruno Haible
2023-08-15 23:03               ` Paul Eggert
2023-08-15 21:12   ` Bruno Haible
2023-08-16 10:13     ` 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).