From: Paul Eggert Date: Sun, 30 Jul 2023 00:06:42 +0000 (-0700) Subject: readutmp: work around glibc utmpx bug X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=10af618132f48f76ab2a8e3de48eae562032d1b2;p=gnulib.git readutmp: work around glibc utmpx bug When compiled with _TIME_BITS=64, glibc does not work, because the files use 32-bit time_t and the code passes this to the user unmodified, but defines a struct with 64-bit time_t. Work around this compatibility bug. Problem reported by Jakub Wilk via Sven Joachim . * lib/readutmp.c (copy_utmp_entry): New function. (read_utmp): Use it. --- diff --git a/ChangeLog b/ChangeLog index a325f24f49..ddb24f6284 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2023-07-29 Paul Eggert + + readutmp: work around glibc utmpx bug + When compiled with _TIME_BITS=64, glibc does not work, + because the files use 32-bit time_t and the code passes this to + the user unmodified, but 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 time-h: Obey GNULIB_POSIXCHECK, not GNULIB_PORTCHECK. diff --git a/doc/glibc-functions/getutmp.texi b/doc/glibc-functions/getutmp.texi index 2628441e13..b53369a597 100644 --- a/doc/glibc-functions/getutmp.texi +++ b/doc/glibc-functions/getutmp.texi @@ -26,4 +26,17 @@ Portability problems not fixed by Gnulib: @item This function is missing on some platforms: FreeBSD 13.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, HP-UX 11, Cygwin 2.9, mingw, MSVC 14, Android 9.0. +@item +On some platforms, this function does not support timestamps past the +year 2038: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@item +On some platforms, this function misbehaves if the @code{year2038} or +@code{year2038-recommended} modules are used and the program is +configured without the @option{--disable-year2038} option. +The @code{readutmp} module works around this problem: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@xref{Avoiding the year 2038 problem}. @end itemize diff --git a/doc/glibc-functions/getutmpx.texi b/doc/glibc-functions/getutmpx.texi index 0ebc01978b..bee96fc239 100644 --- a/doc/glibc-functions/getutmpx.texi +++ b/doc/glibc-functions/getutmpx.texi @@ -26,4 +26,17 @@ Portability problems not fixed by Gnulib: @item This function is missing on some platforms: FreeBSD 13.0, OpenBSD 6.7, Minix 3.1.8, AIX 5.1, HP-UX 11, Cygwin 2.9, mingw, MSVC 14, Android 9.0. +@item +On some platforms, this function does not support timestamps past the +year 2038: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@item +On some platforms, this function misbehaves if the @code{year2038} or +@code{year2038-recommended} modules are used and the program is +configured without the @option{--disable-year2038} option. +The @code{readutmp} module works around this problem: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@xref{Avoiding the year 2038 problem}. @end itemize diff --git a/doc/glibc-headers/utmp.texi b/doc/glibc-headers/utmp.texi index d7d1091e14..1e9d3757cb 100644 --- a/doc/glibc-headers/utmp.texi +++ b/doc/glibc-headers/utmp.texi @@ -31,4 +31,17 @@ FreeBSD 8.0, OpenBSD 7.2. Portability problems not fixed by Gnulib: @itemize +@item +On some platforms, this API does not support timestamps past the +year 2038: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@item +On some platforms, this header misbehaves if the @code{year2038} or +@code{year2038-recommended} modules are used and the program is +configured without the @option{--disable-year2038} option. +The @code{readutmp} module works around this problem: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@xref{Avoiding the year 2038 problem}. @end itemize diff --git a/doc/posix-headers/utmpx.texi b/doc/posix-headers/utmpx.texi index 812544ad70..fd3d4d6ab7 100644 --- a/doc/posix-headers/utmpx.texi +++ b/doc/posix-headers/utmpx.texi @@ -14,4 +14,17 @@ Portability problems not fixed by Gnulib: @item This header file is missing on some platforms: FreeBSD 6.0, OpenBSD 6.7, Minix 3.1.8, mingw, MSVC 14, Android 9.0. +@item +On some platforms, this API does not support timestamps past the +year 2038: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@item +On some platforms, this header misbehaves if the @code{year2038} or +@code{year2038-recommended} modules are used and the program is +configured without the @option{--disable-year2038} option. +The @code{readutmp} module works around this problem: +glibc 2.38 on 32-bit platforms like x86 and ARM where @code{time_t} +was historically 32 bits. +@xref{Avoiding the year 2038 problem}. @end itemize diff --git a/doc/year2038.texi b/doc/year2038.texi index 5964601831..4d56f323f1 100644 --- a/doc/year2038.texi +++ b/doc/year2038.texi @@ -103,3 +103,11 @@ Cygwin 3.3.6 (2022) and earlier on x86, @item Haiku/x86. @end itemize + +If you use the @samp{year2038} or @samp{year2038-recommended} modules, +and configure to support timestamps after the year 2038, +your code should not include @samp{} or @samp{} +directly, because these include files do not work with 64-bit timestamps +if the platform's @code{time_t} was traditionally 32 bits. +Your code can instead use the @samp{readutmp} module, +which works around this problem. diff --git a/lib/readutmp.c b/lib/readutmp.c index d282254cdc..cfc8b69c03 100644 --- a/lib/readutmp.c +++ b/lib/readutmp.c @@ -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 ();