> Here are the changes I committed in gnulib.

And here are the proposed changes for coreutils. Tested on a Fedora Rawhide
system, prepared from
https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-Rawhide-20230729.n.0.iso

The user-visible changes introduced by this change (when linking with
libsystemd) are, as far as I can see:

* "uptime", "users", "who -q" reports fewer users (because ptys without login
  are not counted).
* "who -d" does not report anything any more.
* "who -r" does not report anything any more.
* "who -t" does not report anything any more.
* "who -u" does not report ptys without login any more. The order is arbitrary. 
Example:
Without systemd:

bruno    seat0        2023-07-30 11:25   ?          1663 (login screen)
bruno    tty2         2023-07-30 11:25  old         1663 (tty2)
bruno    pts/3        2023-08-01 01:36 22:33       30619 (:0)
other    pts/4        2023-08-01 17:19 06:50       40513 (::1)

With systemd:

other    sshd pts/4   2023-08-01 17:19 06:50       40513 (::1)
bruno    seat0        2023-07-30 11:25   ?          1593
bruno    tty2         2023-07-30 11:25  old         1593

* pinky $USER
does not report a host any more (and thus does not spend time trying
to do a DNS lookup of "login screen" and "tty2"). Example:
Without systemd:

Login    Name                 TTY      Idle   When             Where
bruno    Bruno Haible        ?seat0    ?????  2023-07-30 11:25 login screen
bruno    Bruno Haible         tty2     2d     2023-07-30 11:25 tty2
bruno    Bruno Haible         pts/3    22:39  2023-08-01 01:36 :0

With systemd:

Login    Name                 TTY      Idle   When             Where
bruno    Bruno Haible        ?seat0    ?????  2023-07-30 11:25
bruno    Bruno Haible         tty2     2d     2023-07-30 11:25


The proposed patch is attached.

Note: Instead of the idiom

   #ifdef UT_HOST_SIZE
     (code for bounded ut_host)
   #else
     (code for unbounded ut_host)
   #endif

one could also write

   if (UT_HOST_SIZE >= 0)
     {
       (code for bounded ut_host)
     }
   else
     {
       (code for unbounded ut_host)
     }

It's just a matter of style whether one prefers #ifs or implicit dead code.

>From d80eea8fb087e9504a6dad27e1a880227f67915a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Wed, 2 Aug 2023 01:32:55 +0200
Subject: [PATCH] maint: Update after gnulib module 'readutmp' changed

For year-2038 safety on Linux/{x86,arm}, use systemd APIs.

* configure.ac: Don't test whether 'struct utmp' and 'struct utmpx' have
the ut_host field; this is now done in gnulib's readutmp module.
* src/system.h (STREQ_LEN): Allow passing a third argument with value
-1.
* src/pinky.c: Test HAVE_STRUCT_XTMP_UT_HOST instead of HAVE_UT_HOST.
(print_entry): Support the situation where ut_line is a 'char *' rather
than a 'char[]' of fixed size. Likewise for ut_user and ut_host.
* src/who.c: Test HAVE_STRUCT_XTMP_UT_HOST instead of HAVE_UT_HOST.
(print_user): Support the situation where ut_line is a 'char *' rather
than a 'char[]' of fixed size. Likewise for ut_user and ut_host.
(print_deadprocs, print_login, print_initspawn, scan_entries): Likewise.
(who): Free resources before returning.
* src/users.c (users): Free resources before returning.
* src/local.mk: Link the programs 'pinky', 'uptime', 'users', 'who' with
$(READUTMP_LIB).
---
 configure.ac | 30 ------------------------------
 src/local.mk |  6 ++++++
 src/pinky.c  | 41 ++++++++++++++++++++++++++++++-----------
 src/system.h |  6 +++++-
 src/users.c  |  1 +
 src/who.c    | 44 ++++++++++++++++++++++++++++++--------------
 6 files changed, 72 insertions(+), 56 deletions(-)

diff --git a/configure.ac b/configure.ac
index 33441a82f..afc1098f7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -406,36 +406,6 @@ AC_DEFUN([coreutils_DUMMY_1],
 ])
 coreutils_DUMMY_1
 
-AC_MSG_CHECKING([ut_host in struct utmp])
-AC_CACHE_VAL([su_cv_func_ut_host_in_utmp],
-[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
-                                   #include <utmp.h>
-                                   struct utmp ut;
-                                   int s = sizeof ut.ut_host;]])],
-  [su_cv_func_ut_host_in_utmp=yes],
-  [su_cv_func_ut_host_in_utmp=no])])
-AC_MSG_RESULT([$su_cv_func_ut_host_in_utmp])
-if test $su_cv_func_ut_host_in_utmp = yes; then
-  have_ut_host=1
-  AC_DEFINE([HAVE_UT_HOST], [1], [FIXME])
-fi
-
-if test -z "$have_ut_host"; then
-  AC_MSG_CHECKING([ut_host in struct utmpx])
-  AC_CACHE_VAL([su_cv_func_ut_host_in_utmpx],
-  [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
-                                     #include <utmpx.h>
-                                     struct utmpx ut;
-                                     int s = sizeof ut.ut_host;]])],
-    [su_cv_func_ut_host_in_utmpx=yes],
-    [su_cv_func_ut_host_in_utmpx=no])])
-  AC_MSG_RESULT([$su_cv_func_ut_host_in_utmpx])
-  if test $su_cv_func_ut_host_in_utmpx = yes; then
-    AC_DEFINE([HAVE_UTMPX_H], [1], [FIXME])
-    AC_DEFINE([HAVE_UT_HOST], [1], [FIXME])
-  fi
-fi
-
 GNULIB_BOOT_TIME([gl_ADD_PROG([optional_bin_progs], [uptime])])
 
 AC_SYS_POSIX_TERMIOS()
diff --git a/src/local.mk b/src/local.mk
index cb9b39274..4d7df2789 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -317,6 +317,12 @@ src_who_LDADD += $(GETADDRINFO_LIB)
 src_hostname_LDADD += $(GETHOSTNAME_LIB)
 src_uname_LDADD += $(GETHOSTNAME_LIB)
 
+# for read_utmp
+src_pinky_LDADD += $(READUTMP_LIB)
+src_uptime_LDADD += $(READUTMP_LIB)
+src_users_LDADD += $(READUTMP_LIB)
+src_who_LDADD += $(READUTMP_LIB)
+
 # for strsignal
 src_kill_LDADD += $(LIBTHREAD)
 
diff --git a/src/pinky.c b/src/pinky.c
index 381e753b6..47abd7758 100644
--- a/src/pinky.c
+++ b/src/pinky.c
@@ -62,7 +62,7 @@ static bool include_home_and_shell = true;
 static bool do_short_format = true;
 
 /* if true, display the ut_host field. */
-#ifdef HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
 static bool include_where = true;
 #endif
 
@@ -206,7 +206,8 @@ print_entry (const STRUCT_UTMP *utmp_ent)
 #define DEV_DIR_WITH_TRAILING_SLASH "/dev/"
 #define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1)
 
-  char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1];
+#ifdef UT_LINE_SIZE
+  char line[DEV_DIR_LEN + UT_LINE_SIZE + 1];
   char *p = line;
 
   /* Copy ut_line into LINE, prepending '/dev/' if ut_line is not
@@ -214,7 +215,18 @@ print_entry (const STRUCT_UTMP *utmp_ent)
      absolute file name in ut_line.  */
   if ( ! IS_ABSOLUTE_FILE_NAME (utmp_ent->ut_line))
     p = stpcpy (p, DEV_DIR_WITH_TRAILING_SLASH);
-  stzncpy (p, utmp_ent->ut_line, sizeof (utmp_ent->ut_line));
+  stzncpy (p, utmp_ent->ut_line, UT_LINE_SIZE);
+#else
+  /* If ut_line contains a space, the device name starts after the space,
+     else at the beginning.  */
+  char *line = xmalloc (DEV_DIR_LEN + strlen (utmp_ent->ut_line) + 1);
+  char *space = strchr (utmp_ent->ut_line, ' ');
+  char *device = (space != NULL ? space + 1 : utmp_ent->ut_line);
+  if ( ! IS_ABSOLUTE_FILE_NAME (device))
+    stpcpy (stpcpy (line, DEV_DIR_WITH_TRAILING_SLASH), device);
+  else
+    stpcpy (line, device);
+#endif
 
   if (stat (line, &stats) == 0)
     {
@@ -232,9 +244,13 @@ print_entry (const STRUCT_UTMP *utmp_ent)
   if (include_fullname)
     {
       struct passwd *pw;
+#ifdef UT_USER_SIZE
       char name[UT_USER_SIZE + 1];
 
       stzncpy (name, UT_USER (utmp_ent), UT_USER_SIZE);
+#else
+      const char *name = UT_USER (utmp_ent);
+#endif
       pw = getpwnam (name);
       if (pw == nullptr)
         /* TRANSLATORS: Real name is unknown; at most 19 characters. */
@@ -253,8 +269,7 @@ print_entry (const STRUCT_UTMP *utmp_ent)
         }
     }
 
-  printf (" %c%-8.*s",
-          mesg, (int) sizeof (utmp_ent->ut_line), utmp_ent->ut_line);
+  printf (" %c%-8.*s", mesg, UT_LINE_SIZE, utmp_ent->ut_line);
 
   if (include_idle)
     {
@@ -267,15 +282,19 @@ print_entry (const STRUCT_UTMP *utmp_ent)
 
   printf (" %s", time_string (utmp_ent));
 
-#ifdef HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
   if (include_where && utmp_ent->ut_host[0])
     {
-      char ut_host[sizeof (utmp_ent->ut_host) + 1];
       char *host = nullptr;
       char *display = nullptr;
+# ifdef UT_HOST_SIZE
+      char ut_host[UT_HOST_SIZE + 1];
 
       /* Copy the host name into UT_HOST, and ensure it's nul terminated. */
-      stzncpy (ut_host, utmp_ent->ut_host, sizeof (utmp_ent->ut_host));
+      stzncpy (ut_host, utmp_ent->ut_host, UT_HOST_SIZE);
+# else
+      char *ut_host = utmp_ent->ut_host;
+# endif
 
       /* Look for an X display.  */
       display = strchr (ut_host, ':');
@@ -408,7 +427,7 @@ print_heading (void)
   if (include_idle)
     printf (" %-6s", _("Idle"));
   printf (" %-*s", time_format_width, _("When"));
-#ifdef HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
   if (include_where)
     printf (" %s", _("Where"));
 #endif
@@ -550,14 +569,14 @@ main (int argc, char **argv)
 
         case 'i':
           include_fullname = false;
-#ifdef HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
           include_where = false;
 #endif
           break;
 
         case 'q':
           include_fullname = false;
-#ifdef HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
           include_where = false;
 #endif
           include_idle = false;
diff --git a/src/system.h b/src/system.h
index b5ec074e7..60b67ba1a 100644
--- a/src/system.h
+++ b/src/system.h
@@ -192,7 +192,11 @@ select_plural (uintmax_t n)
 }
 
 #define STREQ(a, b) (strcmp (a, b) == 0)
-#define STREQ_LEN(a, b, n) (strncmp (a, b, n) == 0)
+
+/* n < 0 means that a and b are unbounded.  */
+#define STREQ_LEN(a, b, n) \
+  ((n) >= 0 ? strncmp (a, b, n) == 0 : strcmp (a, b) == 0)
+
 #define STRPREFIX(a, b) (strncmp (a, b, strlen (b)) == 0)
 
 /* Just like strncmp, but the second argument must be a literal string
diff --git a/src/users.c b/src/users.c
index e14f3fc3e..d7c02cf98 100644
--- a/src/users.c
+++ b/src/users.c
@@ -90,6 +90,7 @@ users (char const *filename, int options)
 
   list_entries_users (n_users, utmp_buf);
 
+  free_utmp (n_users, utmp_buf);
   free (utmp_buf);
 }
 
diff --git a/src/who.c b/src/who.c
index ec0dff792..ae526ae57 100644
--- a/src/who.c
+++ b/src/who.c
@@ -333,24 +333,36 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime)
   time_t last_change;
   char mesg;
   char idlestr[IDLESTR_LEN + 1];
+  PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
   static char *hoststr;
-#if HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
   static size_t hostlen;
 #endif
 
 #define DEV_DIR_WITH_TRAILING_SLASH "/dev/"
 #define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1)
 
-  char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1];
+#ifdef UT_LINE_SIZE
+  char line[DEV_DIR_LEN + UT_LINE_SIZE + 1];
   char *p = line;
-  PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
 
   /* Copy ut_line into LINE, prepending '/dev/' if ut_line is not
      already an absolute file name.  Some systems may put the full,
      absolute file name in ut_line.  */
   if ( ! IS_ABSOLUTE_FILE_NAME (utmp_ent->ut_line))
     p = stpcpy (p, DEV_DIR_WITH_TRAILING_SLASH);
-  stzncpy (p, utmp_ent->ut_line, sizeof (utmp_ent->ut_line));
+  stzncpy (p, utmp_ent->ut_line, UT_LINE_SIZE);
+#else
+  /* If ut_line contains a space, the device name starts after the space,
+     else at the beginning.  */
+  char *line = xmalloc (DEV_DIR_LEN + strlen (utmp_ent->ut_line) + 1);
+  char *space = strchr (utmp_ent->ut_line, ' ');
+  char *device = (space != NULL ? space + 1 : utmp_ent->ut_line);
+  if ( ! IS_ABSOLUTE_FILE_NAME (device))
+    stpcpy (stpcpy (line, DEV_DIR_WITH_TRAILING_SLASH), device);
+  else
+    stpcpy (line, device);
+#endif
 
   if (stat (line, &stats) == 0)
     {
@@ -368,15 +380,19 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime)
   else
     sprintf (idlestr, "  ?");
 
-#if HAVE_UT_HOST
+#if HAVE_STRUCT_XTMP_UT_HOST
   if (utmp_ent->ut_host[0])
     {
-      char ut_host[sizeof (utmp_ent->ut_host) + 1];
       char *host = nullptr;
       char *display = nullptr;
+# ifdef UT_HOST_SIZE
+      char ut_host[UT_HOST_SIZE + 1];
 
       /* Copy the host name into UT_HOST, and ensure it's nul terminated. */
-      stzncpy (ut_host, utmp_ent->ut_host, sizeof (utmp_ent->ut_host));
+      stzncpy (ut_host, utmp_ent->ut_host, UT_HOST_SIZE);
+# else
+      char *ut_host = utmp_ent->ut_host;
+# endif
 
       /* Look for an X display.  */
       display = strchr (ut_host, ':');
@@ -428,8 +444,8 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime)
     }
 #endif
 
-  print_line (sizeof UT_USER (utmp_ent), UT_USER (utmp_ent), mesg,
-              sizeof utmp_ent->ut_line, utmp_ent->ut_line,
+  print_line (UT_USER_SIZE, UT_USER (utmp_ent), mesg,
+              UT_LINE_SIZE, utmp_ent->ut_line,
               time_string (utmp_ent), idlestr, pidstr,
               hoststr ? hoststr : "", "");
 }
@@ -470,7 +486,7 @@ print_deadprocs (const STRUCT_UTMP *utmp_ent)
 
   /* FIXME: add idle time? */
 
-  print_line (-1, "", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line,
+  print_line (-1, "", ' ', UT_LINE_SIZE, utmp_ent->ut_line,
               time_string (utmp_ent), "", pidstr, comment, exitstr);
   free (comment);
 }
@@ -483,7 +499,7 @@ print_login (const STRUCT_UTMP *utmp_ent)
 
   /* FIXME: add idle time? */
 
-  print_line (-1, _("LOGIN"), ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line,
+  print_line (-1, _("LOGIN"), ' ', UT_LINE_SIZE, utmp_ent->ut_line,
               time_string (utmp_ent), "", pidstr, comment, "");
   free (comment);
 }
@@ -494,7 +510,7 @@ print_initspawn (const STRUCT_UTMP *utmp_ent)
   char *comment = make_id_equals_comment (utmp_ent);
   PIDSTR_DECL_AND_INIT (pidstr, utmp_ent);
 
-  print_line (-1, "", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line,
+  print_line (-1, "", ' ', UT_LINE_SIZE, utmp_ent->ut_line,
               time_string (utmp_ent), "", pidstr, comment, "");
   free (comment);
 }
@@ -583,8 +599,7 @@ scan_entries (size_t n, const STRUCT_UTMP *utmp_buf)
   while (n--)
     {
       if (!my_line_only
-          || STREQ_LEN (ttyname_b, utmp_buf->ut_line,
-                        sizeof (utmp_buf->ut_line)))
+          || STREQ_LEN (ttyname_b, utmp_buf->ut_line, UT_LINE_SIZE))
         {
           if (need_users && IS_USER_PROCESS (utmp_buf))
             print_user (utmp_buf, boottime);
@@ -628,6 +643,7 @@ who (char const *filename, int options)
   else
     scan_entries (n_users, utmp_buf);
 
+  free_utmp (n_users, utmp_buf);
   free (utmp_buf);
 }
 
-- 
2.34.1

Reply via email to