]> Savannah Git Hosting - gnulib.git/commitdiff
readutmp: work around glibc utmpx bug
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 30 Jul 2023 00:06:42 +0000 (17:06 -0700)
committerBruno Haible <bruno@clisp.org>
Wed, 16 Aug 2023 17:29:57 +0000 (19:29 +0200)
When compiled with _TIME_BITS=64, glibc <utmpx.h> does not work,
because the files use 32-bit time_t and the code passes this to
the user unmodified, but <utmpx.h> defines a struct with 64-bit
time_t.  Work around this compatibility bug.  Problem reported
by Jakub Wilk via Sven Joachim <https://bugs.gnu.org/64937>.
* lib/readutmp.c (copy_utmp_entry): New function.
(read_utmp): Use it.

ChangeLog
lib/readutmp.c

index 4d5dfe1e597cfec857d66ba9dbf5ce8290cb87bc..4d64fa65721849337fa838894127fd6beed59f05 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2023-07-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+       readutmp: work around glibc utmpx bug
+       When compiled with _TIME_BITS=64, glibc <utmpx.h> does not work,
+       because the files use 32-bit time_t and the code passes this to
+       the user unmodified, but <utmpx.h> defines a struct with 64-bit
+       time_t.  Work around this compatibility bug.
+       * lib/readutmp.c (copy_utmp_entry): New function.
+       (read_utmp): Use it.
+
 2023-07-29  Bruno Haible  <bruno@clisp.org>
 
        time-h: Obey GNULIB_POSIXCHECK, not GNULIB_PORTCHECK.
index d282254cdce1715c8a2156ea78da4410b9f23757..cfc8b69c038b9163c9f6f033597f6ab74bc52cbb 100644 (file)
@@ -86,6 +86,51 @@ desirable_utmp_entry (STRUCT_UTMP const *u, int options)
 
 #ifdef UTMP_NAME_FUNCTION
 
+static void
+copy_utmp_entry (STRUCT_UTMP *dst, STRUCT_UTMP *src)
+{
+#if __GLIBC__ && _TIME_BITS == 64
+  /* Convert from external form in SRC to internal form in DST.
+     It is OK to convert now, rather than earlier, before
+     desirable_utmp_entry was invoked, because desirable_utmp_entry
+     inspects only the leading prefix of the entry, which is the
+     same in both external and internal forms.  */
+
+  /* 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[sizeof src->ut_line]; /* Devicename.  */
+    char ut_id[sizeof src->ut_id];     /* Inittab ID.  */
+    char ut_user[sizeof src->ut_user];  /* Username.  */
+    char ut_host[sizeof src->ut_host]; /* 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
+    {
+      int tv_sec;                      /* Seconds.  */
+      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.  */
+  } *s = (struct utmpx32 *) src;
+  memcpy (dst, s, offsetof (struct utmpx32, ut_session));
+  dst->ut_session = s->ut_session;
+  dst->ut_tv.tv_sec = s->ut_tv.tv_sec;
+  dst->ut_tv.tv_usec = s->ut_tv.tv_usec;
+  memcpy (&dst->ut_addr_v6, s->ut_addr_v6, sizeof dst->ut_addr_v6);
+#else
+  *dst = *src;
+#endif
+}
+
 int
 read_utmp (char const *file, size_t *n_entries, STRUCT_UTMP **utmp_buf,
            int options)
@@ -109,7 +154,7 @@ read_utmp (char const *file, size_t *n_entries, STRUCT_UTMP **utmp_buf,
         if (n_read == n_alloc)
           utmp = xpalloc (utmp, &n_alloc, 1, -1, sizeof *utmp);
 
-        utmp[n_read++] = *u;
+        copy_utmp_entry (&utmp[n_read++], u);
       }
 
   END_UTMP_ENT ();