public inbox for glibc-cvs@sourceware.org
help / color / mirror / Atom feed
* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-02-23 12:37 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-02-23 12:37 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=49942074bcfe14ec9ff0201a5e3bffa394f402fd

commit 49942074bcfe14ec9ff0201a5e3bffa394f402fd
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 509e9b7cb0..77589e9aab 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..6d97d3cd5e 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.33 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 4cc1c6a591..5703811d47 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2171,3 +2171,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 26ad9845e4..556144b40a 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2253,6 +2253,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bb9dfd4daf..3e01139bcc 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1931,3 +1931,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3b0a47e967..ffc3be5255 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -155,6 +155,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 9ab3924888..cca9d7b2d8 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -152,6 +152,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 14a84dac8f..b11eefe55e 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2115,3 +2115,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 5c8502f3d3..f53f9d3dcc 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2074,6 +2074,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index ddc5837059..8604b9ba12 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2241,6 +2241,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e3b345b803..75a8b98445 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2106,6 +2106,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 25f2d1c08f..e293d0e766 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c4891479d3..ef071cd43f 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2186,6 +2186,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 143b0163b4..7861c80ac2 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2166,3 +2166,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 13d374a031..c0aa1dd398 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2163,3 +2163,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b2295f1937..10b83a39e5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2157,6 +2157,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 4c786070d0..51cde431b8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2155,6 +2155,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index aa9c6a4dca..5adbd9019e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2163,6 +2163,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5939588ad5..9870c6d28a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2157,6 +2157,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 92556c4237..49f615353b 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2204,3 +2204,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 26c93dff05..b349bde439 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2213,6 +2213,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f04b167788..43b2aabe84 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2246,6 +2246,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index c2ca00709e..7f02c58ee7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2076,6 +2076,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0ea50dc851..2da63c5a70 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2366,3 +2366,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 0263e284d4..216e14cba2 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1933,3 +1933,18 @@ GLIBC_2.33 wprintf F
 GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 1626c5351f..a34560861b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2133,3 +2133,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 22ceaa3d87..b5b3b6c247 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2081,6 +2081,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d36f228192..a0f1547fbf 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2078,6 +2078,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 59b4313280..c76547d839 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2202,6 +2202,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 266dcdfa08..75a0132c20 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2129,6 +2129,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 2744bba4af..14bbd3450a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2088,6 +2088,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index ce2f4fb72b..95b58039e0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2185,3 +2185,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-03-05 19:19 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-03-05 19:19 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=01edd06347d3130dfc5010db447f8d84564b79b7

commit 01edd06347d3130dfc5010db447f8d84564b79b7
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   9 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 318 ++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2108 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 76529ea62f..5f0d1cf822 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8d6db50c06..d3be1ee1ed 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..794d061604 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,16 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+ifeq ($(have-GLIBC_2.33),yes)
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+endif
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..5cc997f97d
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..d4a356102a
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,318 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <array_length.h>
+
+#include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..3bbfddf5fe
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e10a286d2e..3a657d5e0d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..a64b052368 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bac795262d..4f91e85ba0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..764ea51779 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ebd24f3a6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..5cfcb00ddb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..d140654389 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..11aa688b83 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..14eef860ac 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..e1db1488a9 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..f5b4433142 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..213853a1f1 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..15dda47ba8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..3ffd49cbfb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..2bccbe960a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..209f5f588b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 265a49e74e..45d976790c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index cfa5e1111b..ab3156c917 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c03ac52cd..f8d0534156 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..f56e5ad002 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..cfb457400c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..e1fd74fbad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..5c9cdb33b4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..4dcac4c766 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..69bc04c36c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,18 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..dc4a3223e6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..6deb52d706 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..17a141d5b9 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..b64b351797 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..e3e01c29fc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index f39222d62f..3cbcf24a41 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17ce5dfd58..9995da84a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 17a1c83903..adccf45120 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-03-04 17:36 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-03-04 17:36 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=cd92f882dcae98211ceeedbcf85394d40e874e6c

commit cd92f882dcae98211ceeedbcf85394d40e874e6c
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e10a286d2e..3a657d5e0d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..a64b052368 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bac795262d..4f91e85ba0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..764ea51779 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ebd24f3a6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..5cfcb00ddb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..d140654389 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..11aa688b83 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..14eef860ac 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..e1db1488a9 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..f5b4433142 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..213853a1f1 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..15dda47ba8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..3ffd49cbfb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..2bccbe960a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..209f5f588b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 265a49e74e..45d976790c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index cfa5e1111b..ab3156c917 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c03ac52cd..f8d0534156 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..f56e5ad002 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..cfb457400c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..e1fd74fbad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..5c9cdb33b4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..4dcac4c766 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..69bc04c36c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,18 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..dc4a3223e6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..6deb52d706 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..17a141d5b9 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..b64b351797 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..e3e01c29fc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17ce5dfd58..9995da84a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 17a1c83903..adccf45120 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-03-04 11:29 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-03-04 11:29 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=cd92f882dcae98211ceeedbcf85394d40e874e6c

commit cd92f882dcae98211ceeedbcf85394d40e874e6c
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e10a286d2e..3a657d5e0d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..a64b052368 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bac795262d..4f91e85ba0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..764ea51779 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ebd24f3a6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..5cfcb00ddb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..d140654389 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..11aa688b83 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..14eef860ac 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..e1db1488a9 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..f5b4433142 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..213853a1f1 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..15dda47ba8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..3ffd49cbfb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..2bccbe960a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..209f5f588b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 265a49e74e..45d976790c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index cfa5e1111b..ab3156c917 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c03ac52cd..f8d0534156 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..f56e5ad002 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..cfb457400c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..e1fd74fbad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..5c9cdb33b4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..4dcac4c766 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..69bc04c36c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,18 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..dc4a3223e6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..6deb52d706 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..17a141d5b9 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..b64b351797 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..e3e01c29fc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17ce5dfd58..9995da84a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 17a1c83903..adccf45120 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-03-02 12:31 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-03-02 12:31 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=a932ae5a7a90ee00fed6b65df46ac712ad06b720

commit a932ae5a7a90ee00fed6b65df46ac712ad06b720
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e10a286d2e..3a657d5e0d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..a64b052368 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bac795262d..4f91e85ba0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..764ea51779 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ebd24f3a6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..5cfcb00ddb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..d140654389 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..11aa688b83 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..14eef860ac 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..e1db1488a9 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..f5b4433142 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..213853a1f1 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..15dda47ba8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..3ffd49cbfb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..2bccbe960a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..209f5f588b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 265a49e74e..45d976790c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index cfa5e1111b..ab3156c917 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c03ac52cd..f8d0534156 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..f56e5ad002 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..cfb457400c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..e1fd74fbad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..5c9cdb33b4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..4dcac4c766 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..69bc04c36c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,18 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..dc4a3223e6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..6deb52d706 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..17a141d5b9 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..b64b351797 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..e3e01c29fc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17ce5dfd58..9995da84a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 17a1c83903..adccf45120 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-03-01 17:35 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-03-01 17:35 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=70d905cfad7ccca4ffd5cdddc4e89d546d6b15b6

commit 70d905cfad7ccca4ffd5cdddc4e89d546d6b15b6
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e10a286d2e..3a657d5e0d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..a64b052368 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bac795262d..4f91e85ba0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..764ea51779 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ebd24f3a6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..5cfcb00ddb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..d140654389 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..11aa688b83 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..14eef860ac 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..e1db1488a9 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..f5b4433142 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..213853a1f1 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..15dda47ba8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..3ffd49cbfb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..2bccbe960a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..209f5f588b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 265a49e74e..45d976790c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index cfa5e1111b..ab3156c917 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c03ac52cd..f8d0534156 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..f56e5ad002 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..cfb457400c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..e1fd74fbad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..5c9cdb33b4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..4dcac4c766 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..69bc04c36c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,18 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..dc4a3223e6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..6deb52d706 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..17a141d5b9 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..b64b351797 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..e3e01c29fc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17ce5dfd58..9995da84a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 17a1c83903..adccf45120 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-02-26 20:41 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-02-26 20:41 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=96031f77d8a675b0dfc7adf314d467f311070b26

commit 96031f77d8a675b0dfc7adf314d467f311070b26
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index e10a286d2e..3a657d5e0d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..a64b052368 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index bac795262d..4f91e85ba0 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..764ea51779 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ebd24f3a6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..5cfcb00ddb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..d140654389 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..11aa688b83 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..14eef860ac 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..e1db1488a9 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..f5b4433142 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..213853a1f1 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..15dda47ba8 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..3ffd49cbfb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..2bccbe960a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..209f5f588b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 265a49e74e..45d976790c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index cfa5e1111b..ab3156c917 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c03ac52cd..f8d0534156 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..f56e5ad002 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..cfb457400c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..e1fd74fbad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..5c9cdb33b4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..4dcac4c766 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..69bc04c36c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,18 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..dc4a3223e6 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..6deb52d706 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..17a141d5b9 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..b64b351797 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..e3e01c29fc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 17ce5dfd58..9995da84a8 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,21 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 17a1c83903..adccf45120 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,18 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

* [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx
@ 2021-02-23 20:39 Adhemerval Zanella
  0 siblings, 0 replies; 8+ messages in thread
From: Adhemerval Zanella @ 2021-02-23 20:39 UTC (permalink / raw)
  To: glibc-cvs

https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=f7e491ac74273f6d5c8e5b53af4d8f7a21c264ca

commit f7e491ac74273f6d5c8e5b53af4d8f7a21c264ca
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date:   Wed Jul 29 11:42:42 2020 -0300

    login: Add 64-bit time support to utmp/utmpx
    
    The new struct has the same size for 32-bit and 64-bit architecture with
    two main differences compared to the 32-bit time one:
    
      1. ut_session is now 64-bit and it is mainly to set the ut_tv member
         alignment to be similar on both 32-bit and 64-bit architecture
         (for architectures that support multiple ABIs with different
         wordsize, such as x86 and powerpc).
    
      2. The internal tv_sec and tv_usec for ut_tv are now 64-bit.  Although
         it does not fully fix BZ#17470 nor BZ#18235, it might allow define
         the type as 'struct timeval' for __TIMESIZE=64 (thus fixing the
         aforementioned bug in this build configuration).
    
    Different than laid out on the Y2038 Proofness Design [1], the
    'utmp.trans' strategy is not used.  Instead:
    
      - New file names are defined for _PATH_UTMP, _PATH_WTMP, and
        _PATH_UTMP_DB (if applicable) and used as default for the new 2.34
        utmp{x} symbols.
    
      - The new utmp{x} symbols read/write 64-bit time_t entries as default.
        However if the old _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation read 32-bit utmp{x}
        entries and convert it to 64-bit ones.
    
      - The compat symbols read/write 32-bit time_t entries as default.
        If the default _PATH_UTMP or _PATH_WTMP is passed on
        utm{x}pname or updwtmp, the implementation reads 64-bit entries
        and convert to 32-bit ones.
    
    The idea is not to maintain multiple databases with different formats
    (which has underlying issues due to complexity, how to handle entries
    that might overflow, and increases the security surface of BZ#24492),
    but rather to move new application to use y2038 entries (which currently
    affects 64-bit architecture as well, modulo s390).
    
    If required the system might provide a tool to convert the old format
    to newer one by opening the old file with utmpname and copying the
    entries to the new format with updwtmp.
    
    Also, for new 64-bit databases the path is not redirected to use the
    utmpx one depending of the file existance (utmp_file_name_time32).
    This is undocumented behavior most likely added be compatible with
    Solaris (which defines different utmp dabases for utmpx files).
    
    The s390 is an outlier: the 31-bit ABI added 64-bit time support on
    GLIBC 2.8 and 64-bit has support since its inclusion.  The s390 ABI
    follows the above design, but with a different ABI base version
    (2.8 vs 2.34). The s390x instead does not have support to read/write
    32-bit registers and does not provide compat symbols.
    
    Checked on x86_64-linux-gnu and i686-linux-gnu.
    
    [1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign#utmp_types_and_APIs

Diff:
---
 bits/types/struct_utmp.h                           |  12 +-
 bits/types/struct_utmpx.h                          |  11 +-
 include/utmp.h                                     |   5 +-
 login/Makefile                                     |   7 +-
 login/Versions                                     |  24 ++
 login/getutent.c                                   |   7 +-
 login/getutent_r.c                                 |  48 ++-
 login/getutid.c                                    |   7 +-
 login/getutid_r.c                                  |  33 +-
 login/getutline.c                                  |   7 +-
 login/getutline_r.c                                |  33 +-
 login/getutmp.c                                    |  10 +-
 login/getutxent.c                                  |   9 +-
 login/getutxid.c                                   |   9 +-
 login/getutxline.c                                 |   9 +-
 login/login.c                                      |  10 +-
 .../sysv/linux/s390/s390-32 => login}/login32.c    |  16 +-
 login/pututxline.c                                 |   9 +-
 login/tst-utmp-default.c                           | 292 +++++++++++++
 .../tst-utmp-default.root/tst-utmp-default.script  |  10 +
 login/tst-utmp32.c                                 | 325 +++++++++++++++
 login/tst-utmp32.root/tst-utmp32.script            |   7 +
 login/updwtmp.c                                    |  25 +-
 login/updwtmpx.c                                   |   9 +-
 .../s390-32/utmp-convert.h => login/utmp-convert.c |  59 +--
 .../s390-32/getutent.c => login/utmp-convert.h     |  28 +-
 login/utmp-path.h                                  |   2 +-
 login/utmp-private.h                               |  24 +-
 login/utmp32.c                                     | 247 +++++++++++
 .../sysv/linux/s390/s390-32 => login}/utmp32.h     |   9 +
 login/utmp_file.c                                  | 459 +++++++++++++--------
 login/utmpname.c                                   |   8 +
 login/utmpx32.c                                    | 112 +++++
 .../sysv/linux/s390/s390-32 => login}/utmpx32.h    |   6 +-
 sysdeps/generic/paths.h                            |   7 +-
 sysdeps/generic/utmp-compat.h                      |   3 +
 sysdeps/mach/hurd/i386/libc.abilist                |  15 +
 sysdeps/mach/hurd/i386/libutil.abilist             |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist       |  15 +
 sysdeps/unix/sysv/linux/aarch64/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/alpha/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist           |  15 +
 sysdeps/unix/sysv/linux/arc/libutil.abilist        |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/be/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist        |  15 +
 sysdeps/unix/sysv/linux/arm/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/csky/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/hppa/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/i386/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist          |  15 +
 sysdeps/unix/sysv/linux/ia64/libutil.abilist       |   1 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |  15 +
 .../unix/sysv/linux/m68k/coldfire/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |  15 +
 .../unix/sysv/linux/m68k/m680x0/libutil.abilist    |   1 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/be/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |  15 +
 .../unix/sysv/linux/microblaze/le/libutil.abilist  |   1 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips32/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |  15 +
 .../unix/sysv/linux/mips/mips64/libutil.abilist    |   1 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |  15 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |  15 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/nios2/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/paths.h                    |   5 +-
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |  15 +
 .../sysv/linux/powerpc/powerpc32/libutil.abilist   |   1 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |  15 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/be/libutil.abilist     |   1 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |  15 +
 .../linux/powerpc/powerpc64/le/libutil.abilist     |   1 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist |   1 +
 sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c  |  38 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c   |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline.c   |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c |  34 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c     |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c   |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/login.c       |  35 --
 sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c  |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c     |  32 --
 sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c    |  30 --
 sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h |   2 +-
 sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c      | 184 ---------
 .../unix/sysv/linux/s390/s390-32/utmpx-convert.h   |  85 ----
 sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c     | 139 -------
 sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h |   3 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/be/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist         |  15 +
 sysdeps/unix/sysv/linux/sh/le/libutil.abilist      |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc32/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist |  15 +
 .../unix/sysv/linux/sparc/sparc64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/utmp-path.h                |   3 +-
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |  15 +
 sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist  |   1 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |  15 +
 sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist |   1 +
 115 files changed, 2113 insertions(+), 1117 deletions(-)

diff --git a/bits/types/struct_utmp.h b/bits/types/struct_utmp.h
index 4b05c91515..19b9bca1e7 100644
--- a/bits/types/struct_utmp.h
+++ b/bits/types/struct_utmp.h
@@ -38,18 +38,16 @@ struct utmp
 /* The ut_session and ut_tv fields must be the same size when compiled
    32- and 64-bit.  This allows data files and shared memory to be
    shared between 32- and 64-bit applications.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  int32_t ut_session;		/* Session ID, used for windowing.  */
+  int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    int32_t tv_sec;		/* Seconds.  */
-    int32_t tv_usec;		/* Microseconds.  */
+    int64_t tv_sec;		/* Seconds.  */
+    int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
-
   int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/bits/types/struct_utmpx.h b/bits/types/struct_utmpx.h
index 8bfc786cd8..27ef28e70f 100644
--- a/bits/types/struct_utmpx.h
+++ b/bits/types/struct_utmpx.h
@@ -39,17 +39,16 @@ struct utmpx
 /* 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.  */
-#if __WORDSIZE_TIME64_COMPAT32
-  __int32_t ut_session;		/* Session ID, used for windowing.  */
+  __int64_t ut_session;		/* Session ID, used for windowing.  */
+#if __TIMESIZE != 64
   struct
   {
-    __int32_t tv_sec;		/* Seconds.  */
-    __int32_t tv_usec;		/* Microseconds.  */
+    __int64_t tv_sec;		/* Seconds.  */
+    __int64_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 #else
-  long int ut_session;		/* Session ID, used for windowing.  */
   struct timeval ut_tv;		/* Time entry was made.  */
 #endif
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
-  char __glibc_reserved[20];		/* Reserved for future use.  */
+  char __glibc_reserved[8];	/* Reserved for future use.  */
 };
diff --git a/include/utmp.h b/include/utmp.h
index 374184e9b2..7a205c13e2 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -9,7 +9,7 @@ libc_hidden_proto (__updwtmp)
 extern int __utmpname (const char *__file) attribute_hidden;
 extern struct utmp *__getutent (void);
 libc_hidden_proto (__getutent)
-extern void __setutent (void) attribute_hidden;
+extern void __setutent (void);
 extern void __endutent (void) attribute_hidden;
 extern struct utmp *__getutid (const struct utmp *__id);
 libc_hidden_proto (__getutid)
@@ -26,6 +26,9 @@ extern int __getutline_r (const struct utmp *__line,
 			  struct utmp *__buffer, struct utmp **__result);
 libc_hidden_proto (__getutline_r)
 
+extern void __login (const struct utmp *ut);
+hidden_proto (__login)
+
 libutil_hidden_proto (login_tty)
 
 # endif /* !_ISOMAC */
diff --git a/login/Makefile b/login/Makefile
index 5e2cb1da06..b5569683fa 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -31,7 +31,7 @@ headers	:= utmp.h bits/utmp.h lastlog.h pty.h \
 routines := getlogin getlogin_r setlogin getlogin_r_chk \
 	    getutent getutent_r getutid getutline getutid_r getutline_r \
 	    utmp_file utmpname updwtmp getpt grantpt unlockpt ptsname \
-	    ptsname_r_chk
+	    ptsname_r_chk utmp32 utmpx32 utmp-convert
 
 CFLAGS-grantpt.c += -DLIBEXECDIR='"$(libexecdir)"'
 
@@ -49,11 +49,14 @@ vpath %.c programs
 tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
   tst-pututxline-lockfail tst-pututxline-cache
 
+tests-container-internal := tst-utmp32
+tests-container := tst-utmp-default
+
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
 extra-libs-others := $(extra-libs)
 
-libutil-routines:= login login_tty logout logwtmp openpty forkpty
+libutil-routines:= login login_tty logout logwtmp openpty forkpty login32
 
 include ../Rules
 
diff --git a/login/Versions b/login/Versions
index 475fcf063f..d28ecdca9f 100644
--- a/login/Versions
+++ b/login/Versions
@@ -45,10 +45,34 @@ libc {
     __getlogin_r_chk;
     __ptsname_r_chk;
   }
+  GLIBC_2.34 {
+    getutent;
+    getutent_r;
+    getutid;
+    getutid_r;
+    getutline;
+    getutline_r;
+    getutmp;
+    getutmpx;
+    getutxent;
+    getutxid;
+    getutxline;
+    pututline;
+    pututxline;
+    updwtmp;
+    updwtmpx;
+  }
+  GLIBC_PRIVATE {
+    # Used on compat login from libutil.
+    __utmp_convert32to64;
+  }
 }
 
 libutil {
   GLIBC_2.0 {
     forkpty; login; login_tty; logout; logwtmp; openpty;
   }
+  GLIBC_2.34 {
+    login;
+  }
 }
diff --git a/login/getutent.c b/login/getutent.c
index c2428bfb3e..57cbe76506 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -42,4 +43,8 @@ __getutent (void)
   return result;
 }
 libc_hidden_def (__getutent)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent, getutent, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent, getutent)
+#endif
diff --git a/login/getutent_r.c b/login/getutent_r.c
index 0af48acec8..72e9e0d070 100644
--- a/login/getutent_r.c
+++ b/login/getutent_r.c
@@ -20,8 +20,11 @@
 #include <libc-lock.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
-#include "utmp-private.h"
 
 /* We need to protect the opening of the file.  */
 __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
@@ -32,7 +35,12 @@ __setutent (void)
 {
   __libc_lock_lock (__libc_utmp_lock);
 
-  __libc_setutent ();
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    __libc_setutent32 ();
+  else
+#endif
+    __libc_setutent ();
 
   __libc_lock_unlock (__libc_utmp_lock);
 }
@@ -46,14 +54,32 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutent_r (buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+      retval = __libc_getutent32_r (&out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+#endif
+    retval = __libc_getutent_r (buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutent_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutent_r, getutent_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutent_r, getutent_r)
+#endif
 
 
 struct utmp *
@@ -63,14 +89,28 @@ __pututline (const struct utmp *data)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  buffer = __libc_pututline (data);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      __utmp_convert64to32 (data, &in32);
+      struct utmp32 *out32p = __libc_pututline32 (&in32);
+      buffer = out32p != NULL ? (struct utmp *) data : NULL;
+    }
+  else
+#endif
+    buffer = __libc_pututline (data);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return buffer;
 }
 libc_hidden_def (__pututline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututline, pututline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__pututline, pututline)
+#endif
 
 
 void
diff --git a/login/getutid.c b/login/getutid.c
index d986b9d892..ace3e840b7 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <shlib-compat.h>
+#include <utmp-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -40,4 +41,8 @@ __getutid (const struct utmp *id)
   return result;
 }
 libc_hidden_def (__getutid)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid, getutid, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid, getutid)
+#endif
diff --git a/login/getutid_r.c b/login/getutid_r.c
index 68f40a6e24..f763a0f748 100644
--- a/login/getutid_r.c
+++ b/login/getutid_r.c
@@ -21,9 +21,10 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -48,11 +49,35 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutid_r (id, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+    {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (id, &in32);
+
+      retval =  __libc_getutid32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutid_r (id, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutid_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutid_r, getutid_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutid_r, getutid_r)
+#endif
diff --git a/login/getutline.c b/login/getutline.c
index 2c8320c9a9..59a56d1ff8 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -18,7 +18,8 @@
 
 #include <stdlib.h>
 #include <utmp.h>
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 /* Local buffer to store the result.  */
 libc_freeres_ptr (static struct utmp *buffer);
@@ -41,4 +42,8 @@ __getutline (const struct utmp *line)
   return result;
 }
 libc_hidden_def (__getutline)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline, getutline, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline, getutline)
+#endif
diff --git a/login/getutline_r.c b/login/getutline_r.c
index 39b8a5830f..0f04f9eaa0 100644
--- a/login/getutline_r.c
+++ b/login/getutline_r.c
@@ -20,9 +20,10 @@
 #include <errno.h>
 #include <libc-lock.h>
 #include <utmp.h>
-
-#include "utmp-private.h"
-
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+#include <utmp-private.h>
+#include <utmp-convert.h>
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -36,11 +37,35 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
 
   __libc_lock_lock (__libc_utmp_lock);
 
-  retval = __libc_getutline_r (line, buffer, result);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (__libc_utmpname_mode == UTMPNAME_TIME32)
+   {
+      struct utmp32 in32;
+      struct utmp32 out32;
+      struct utmp32 *out32p;
+
+      __utmp_convert64to32 (line, &in32);
+
+      retval =  __libc_getutline32_r (&in32, &out32, &out32p);
+      if (retval == 0)
+	{
+	  __utmp_convert32to64 (out32p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+#endif
+    retval = __libc_getutline_r (line, buffer, result);
 
   __libc_lock_unlock (__libc_utmp_lock);
 
   return retval;
 }
 libc_hidden_def (__getutline_r)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutline_r, getutline_r, UTMP_COMPAT_BASE);
+#else
 weak_alias (__getutline_r, getutline_r)
+#endif
diff --git a/login/getutmp.c b/login/getutmp.c
index 60aafb5067..f2873cc9cd 100644
--- a/login/getutmp.c
+++ b/login/getutmp.c
@@ -21,6 +21,8 @@
 #define getutmpx __redirect_getutmpx
 #include <utmpx.h>
 #undef getutmpx
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #define CHECK_SIZE_AND_OFFSET(field) \
   _Static_assert (sizeof ((struct utmp){0}.field)		\
@@ -59,5 +61,11 @@ __getutmp (const struct utmpx *utmpx, struct utmp *utmp)
   utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
 }
 
-weak_alias (__getutmp, getutmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutmp, getutmp, UTMP_COMPAT_BASE);
+strong_alias (__getutmp, __getutmpx)
+versioned_symbol (libc, __getutmpx, getutmpx, UTMP_COMPAT_BASE);
+#else
+strong_alias (__getutmp, getutmp)
 strong_alias (__getutmp, getutmpx)
+#endif
diff --git a/login/getutxent.c b/login/getutxent.c
index a6794bac70..bd5a62b5fe 100644
--- a/login/getutxent.c
+++ b/login/getutxent.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxent (void)
+__getutxent (void)
 {
   return (struct utmpx *) __getutent ();
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxent, getutxent, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxent, getutxent)
+#endif
diff --git a/login/getutxid.c b/login/getutxid.c
index ae3b9fe7b0..ec33512eb4 100644
--- a/login/getutxid.c
+++ b/login/getutxid.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxid (const struct utmpx *id)
+__getutxid (const struct utmpx *id)
 {
   return (struct utmpx *) __getutid ((const struct utmp *) id);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxid, getutxid, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxid, getutxid)
+#endif
diff --git a/login/getutxline.c b/login/getutxline.c
index 274716bf7a..6baac67fc3 100644
--- a/login/getutxline.c
+++ b/login/getutxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-getutxline (const struct utmpx *line)
+__getutxline (const struct utmpx *line)
 {
   return (struct utmpx *) __getutline ((const struct utmp *) line);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __getutxline, getutxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__getutxline, getutxline)
+#endif
diff --git a/login/login.c b/login/login.c
index d280c13f1f..56cbf37dfe 100644
--- a/login/login.c
+++ b/login/login.c
@@ -23,6 +23,8 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <utmp.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Return the result of ttyname in the buffer pointed to by TTY, which should
@@ -78,7 +80,7 @@ tty_name (int fd, char **tty, size_t buf_len)
 }
 \f
 void
-login (const struct utmp *ut)
+__login (const struct utmp *ut)
 {
 #ifdef PATH_MAX
   char _tty[PATH_MAX + UT_LINESIZE];
@@ -137,3 +139,9 @@ login (const struct utmp *ut)
   /* Update the WTMP file.  Here we have to add a new entry.  */
   updwtmp (_PATH_WTMP, &copy);
 }
+hidden_def (__login)
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libutil, __login, login, UTMP_COMPAT_BASE);
+#else
+weak_alias (__login, login)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c b/login/login32.c
similarity index 72%
rename from sysdeps/unix/sysv/linux/s390/s390-32/login32.c
rename to login/login32.c
index 45419bc092..29fd77d566 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login32.c
+++ b/login/login32.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Write utmp and wtmp entries, 32-bit time compat version.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,21 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
 #include <utmp.h>
-#include <libc-symbols.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 #include "utmp32.h"
 #include "utmp-convert.h"
 
+#if SHLIB_COMPAT(libutil, GLIBC_2_0, UTMP_COMPAT_BASE)
 /* Write the given entry into utmp and wtmp.  */
 void
 login32 (const struct utmp32 *entry)
 {
   struct utmp in64;
 
-  utmp_convert32to64 (entry, &in64);
-  login (&in64);
+  __utmp_convert32to64 (entry, &in64);
+  __login (&in64);
 }
 
-symbol_version (login32, login, GLIBC_2.0);
+compat_symbol (libutil, login32, login, GLIBC_2_0);
+#endif
diff --git a/login/pututxline.c b/login/pututxline.c
index 8b38f1fd97..2b49dfe767 100644
--- a/login/pututxline.c
+++ b/login/pututxline.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 struct utmpx *
-pututxline (const struct utmpx *utmpx)
+__pututxline (const struct utmpx *utmpx)
 {
   return (struct utmpx *) __pututline ((const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __pututxline, pututxline, UTMP_COMPAT_BASE);
+#else
+weak_alias (__pututxline, pututxline)
+#endif
diff --git a/login/tst-utmp-default.c b/login/tst-utmp-default.c
new file mode 100644
index 0000000000..2bc84404e3
--- /dev/null
+++ b/login/tst-utmp-default.c
@@ -0,0 +1,292 @@
+/* Tests for UTMP functions using default and old UTMP_FILE.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <utmp.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+/* The default utmp{x} functions read and write the exported 64-bit time_t
+   utmp/utmpx struct as default with the only exception when the old
+   UTMP_FILE ('/var/run/utmp') or WUTMP_FILE ('/var/run/wtmp') is set
+   explicitly with utmpname or updwtmp.  In this case old 32-bit time_t
+   entries are read / write instead.  */
+
+static struct utmp entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+const size_t entry_size = sizeof (entry) / sizeof (entry[0]);
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp (const struct utmp *left, const struct utmp *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  struct utmp *ut;
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while ((ut = getutent ()))
+    {
+      TEST_VERIFY (n <= entry_size);
+      compare_utmp (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, entry_size);
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline (&entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = getutline (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline (&ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp *up;
+  struct utmp ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < entry_size; n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp *up;
+  struct utmp ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = getutid (&ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < entry_size; n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+
+static int
+do_test (void)
+{
+  utmpname (UTMP_FILE);
+  run_test ();
+
+  utmpname ("/var/run/utmp");
+  run_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp-default.root/tst-utmp-default.script b/login/tst-utmp-default.root/tst-utmp-default.script
new file mode 100644
index 0000000000..26ef984f5f
--- /dev/null
+++ b/login/tst-utmp-default.root/tst-utmp-default.script
@@ -0,0 +1,10 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+# Same for the old files as well
+touch  0664 /var/run/utmp
+touch  0664 /var/run/wtmp
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/tst-utmp32.c b/login/tst-utmp32.c
new file mode 100644
index 0000000000..09f21eace9
--- /dev/null
+++ b/login/tst-utmp32.c
@@ -0,0 +1,325 @@
+/* Tests for UTMP compat mode.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <shlib-compat.h>
+#include <support/test-driver.h>
+#include <stdio.h>
+
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+/* The test check the compat utmp/utmpx routines for the two operation modes:
+
+   1. Use the default UTMP_FILE which uses the default code path which
+      read/write 64-bit entries and converts to 32-bit time_t utmp/utmpx
+      entries.
+
+   2. Set a non default path with utmpname, which uses the compat code
+      path to read/write 32-bit time_t utmp/utmpx entries.  */
+
+# include <stdlib.h>
+# include <string.h>
+# include <utmp.h>
+
+# include <support/check.h>
+# include <support/temp_file.h>
+# include <array_length.h>
+
+# include <utmp32.h>
+
+compat_symbol_reference (libc, setutent,  setutent,  GLIBC_2_0);
+compat_symbol_reference (libc, pututline, pututline, GLIBC_2_0);
+compat_symbol_reference (libc, getutline, getutline, GLIBC_2_0);
+compat_symbol_reference (libc, getutent,  getutent,  GLIBC_2_0);
+compat_symbol_reference (libc, getutid,   getutid,   GLIBC_2_0);
+
+static struct utmp32 entry[] =
+{
+#define UT(a)  .ut_tv = { .tv_sec = (a)}
+
+  { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
+  { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
+  { .ut_type = INIT_PROCESS, .ut_pid = 5, .ut_id = "si", UT(3000) },
+  { .ut_type = LOGIN_PROCESS, .ut_pid = 23, .ut_line = "tty1", .ut_id = "1",
+    .ut_user = "LOGIN", UT(4000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 24, .ut_line = "tty2", .ut_id = "2",
+    .ut_user = "albert", UT(8000) },
+  { .ut_type = USER_PROCESS, .ut_pid = 196, .ut_line = "ttyp0", .ut_id = "p0",
+    .ut_user = "niels", UT(10000) },
+  { .ut_type = DEAD_PROCESS, .ut_line = "ttyp1", .ut_id = "p1", UT(16000) },
+  { .ut_type = EMPTY },
+  { .ut_type = EMPTY }
+};
+
+static time_t entry_time = 20000;
+static pid_t entry_pid = 234;
+
+static void
+compare_utmp32 (const struct utmp32 *left, const struct utmp32 *right)
+{
+  TEST_COMPARE (left->ut_type, right->ut_type);
+  TEST_COMPARE (left->ut_pid, right->ut_pid);
+  TEST_COMPARE_BLOB (left->ut_line, sizeof (left->ut_line),
+		     right->ut_line, sizeof (right->ut_line));
+  TEST_COMPARE_BLOB (left->ut_id, sizeof (left->ut_id),
+		     right->ut_id, sizeof (right->ut_id));
+  TEST_COMPARE_BLOB (left->ut_user, sizeof (left->ut_user),
+		     right->ut_user, sizeof (right->ut_user));
+  TEST_COMPARE_BLOB (left->ut_host, sizeof (left->ut_host),
+		     right->ut_host, sizeof (right->ut_host));
+  TEST_COMPARE (left->ut_exit.e_termination, right->ut_exit.e_termination);
+  TEST_COMPARE (left->ut_exit.e_exit, right->ut_exit.e_exit);
+  TEST_COMPARE (left->ut_tv.tv_sec, right->ut_tv.tv_sec);
+  TEST_COMPARE (left->ut_tv.tv_usec, right->ut_tv.tv_usec);
+  TEST_COMPARE_BLOB (left->ut_addr_v6, sizeof (left->ut_addr_v6),
+		     right->ut_addr_v6, sizeof (right->ut_addr_v6));
+}
+
+static void
+do_init (void)
+{
+  setutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+  endutent ();
+}
+
+static void
+do_check (void)
+{
+  int n;
+
+  setutent ();
+
+  n = 0;
+  while (1)
+    {
+      struct utmp32 *ut = (struct utmp32 *) getutent ();
+      if (ut == NULL)
+	break;
+      TEST_VERIFY (n <= array_length (entry));
+      compare_utmp32 (ut, &entry[n]);
+      n++;
+    }
+  TEST_COMPARE (n, array_length (entry));
+
+  endutent ();
+}
+
+static void
+simulate_login (const char *line, const char *user)
+{
+  for (int n = 0; n <array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0
+	  || entry[n].ut_type == DEAD_PROCESS)
+	{
+	  if (entry[n].ut_pid == DEAD_PROCESS)
+	    entry[n].ut_pid = (entry_pid += 27);
+	  entry[n].ut_type = USER_PROCESS;
+	  strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
+	  entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+simulate_logout (const char *line)
+{
+  int n;
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  entry[n].ut_type = DEAD_PROCESS;
+	  strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
+          entry[n].ut_tv.tv_sec = (entry_time += 1000);
+	  setutent ();
+
+	  TEST_VERIFY (pututline ((const struct utmp *) &entry[n]) != NULL);
+
+	  endutent ();
+
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("no entries available");
+}
+
+static void
+check_login (const char *line)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  up = (struct utmp32 *) getutline ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (line, entry[n].ut_line) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for line `%s'", line);
+}
+
+static void
+check_logout (const char *line)
+{
+  struct utmp32 ut;
+
+  setutent ();
+
+  strcpy (ut.ut_line, line);
+  TEST_VERIFY (getutline ((const struct utmp *) &ut) == NULL);
+
+  endutent ();
+}
+
+static void
+check_id (const char *id)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+
+  setutent ();
+
+  ut.ut_type = USER_PROCESS;
+  strcpy (ut.ut_id, id);
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (int n = 0; n < array_length (entry); n++)
+    {
+      if (strcmp (id, entry[n].ut_id) == 0)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for ID `%s'", id);
+}
+
+static void
+check_type (int type)
+{
+  struct utmp32 *up;
+  struct utmp32 ut;
+  int n;
+
+  setutent ();
+
+  ut.ut_type = type;
+  up = (struct utmp32 *) getutid ((const struct utmp *) &ut);
+  TEST_VERIFY (up != NULL);
+
+  endutent ();
+
+  for (n = 0; n < array_length (entry); n++)
+    {
+      if (type == entry[n].ut_type)
+	{
+	  compare_utmp32 (up, &entry[n]);
+	  return;
+	}
+    }
+
+  FAIL_EXIT1 ("bogus entry for type `%d'", type);
+}
+
+static char *name;
+
+static void
+do_prepare (int argc, char **argv)
+{
+  int fd = create_temp_file ("tst-utmp32.", &name);
+  TEST_VERIFY_EXIT (fd != -1);
+}
+#define PREPARE do_prepare
+
+static void
+run_test (void)
+{
+  do_init ();
+  do_check ();
+
+  simulate_login ("tty1", "erwin");
+  do_check ();
+
+  simulate_login ("ttyp1", "paul");
+  do_check ();
+
+  simulate_logout ("tty2");
+  do_check ();
+
+  simulate_logout ("ttyp0");
+  do_check ();
+
+  simulate_login ("ttyp2", "richard");
+  do_check ();
+
+  check_login ("tty1");
+  check_logout ("ttyp0");
+  check_id ("p1");
+  check_id ("2");
+  check_id ("si");
+  check_type (BOOT_TIME);
+  check_type (RUN_LVL);
+}
+#endif
+
+static int
+do_test (void)
+{
+#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  run_test ();
+
+  utmpname (name);
+  run_test ();
+
+  return 0;
+#else
+  return EXIT_UNSUPPORTED;
+#endif
+}
+
+#include <support/test-driver.c>
diff --git a/login/tst-utmp32.root/tst-utmp32.script b/login/tst-utmp32.root/tst-utmp32.script
new file mode 100644
index 0000000000..4aadc63335
--- /dev/null
+++ b/login/tst-utmp32.root/tst-utmp32.script
@@ -0,0 +1,7 @@
+# We create empty UTMP_FILE and WTMP_FILE
+mkdirp 0755 /var/run
+touch  0664 /var/run/utmp.v2
+touch  0664 /var/run/wtmp.v2
+
+# Must run localedef as root to write into default paths.
+su
diff --git a/login/updwtmp.c b/login/updwtmp.c
index e67a9cf2d9..e61d933aa3 100644
--- a/login/updwtmp.c
+++ b/login/updwtmp.c
@@ -19,16 +19,31 @@
 #include <utmp.h>
 #include <string.h>
 #include <unistd.h>
-
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <utmp-convert.h>
+#include <shlib-compat.h>
 
 void
 __updwtmp (const char *wtmp_file, const struct utmp *utmp)
 {
-  const char *file_name = utmp_file_name_time32 (wtmp_file);
-
-  __libc_updwtmp (file_name, utmp);
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+  if (strcmp (wtmp_file, _PATH_WTMP_BASE) == 0
+      || strcmp (wtmp_file, _PATH_WTMP_BASE) == 0)
+    {
+      const char *file_name = utmp_file_name_time32 (wtmp_file);
+      struct utmp32 in32;
+      __utmp_convert64to32 (utmp, &in32);
+      __libc_updwtmp32 (file_name, &in32);
+    }
+  else
+#endif
+    __libc_updwtmp (wtmp_file, utmp);
 }
 libc_hidden_def (__updwtmp)
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmp, updwtmp, UTMP_COMPAT_BASE);
+#else
 weak_alias (__updwtmp, updwtmp)
+#endif
diff --git a/login/updwtmpx.c b/login/updwtmpx.c
index ba06645dfd..93c3fd3f2d 100644
--- a/login/updwtmpx.c
+++ b/login/updwtmpx.c
@@ -18,9 +18,16 @@
 
 #include <utmp.h>
 #include <utmpx.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 void
-updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
+__updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
 {
   __updwtmp (wtmpx_file, (const struct utmp *) utmpx);
 }
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+versioned_symbol (libc, __updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
+#else
+weak_alias (__updwtmpx, updwtmpx)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h b/login/utmp-convert.c
similarity index 58%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
rename to login/utmp-convert.c
index 9418afb0f4..8d55ddfa4f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-convert.h
+++ b/login/utmp-convert.c
@@ -1,5 +1,5 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
+/* Converto to/from 64-bit to 32-bit time_t utmp/utmpx struct.
+   Copyright (C) 2008-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -16,71 +16,42 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMP_CONVERT_H
-#define _UTMP_CONVERT_H 1
-
 #include <string.h>
-
-#include "utmp32.h"
+#include <utmp-convert.h>
 
 /* Convert the 64 bit struct utmp value in FROM to the 32 bit version
    returned in TO.  */
-static inline void
-utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+void
+__utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
   memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
 }
 
 /* Convert the 32 bit struct utmp value in FROM to the 64 bit version
    returned in TO.  */
-static inline void
-utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
+void
+__utmp_convert32to64 (const struct utmp32 *from, struct utmp *to)
 {
-#if _HAVE_UT_TYPE - 0
   to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
   to->ut_pid = from->ut_pid;
-#endif
   memcpy (to->ut_line, from->ut_line, UT_LINESIZE);
   memcpy (to->ut_user, from->ut_user, UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
   memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
   memcpy (to->ut_host, from->ut_host, UT_HOSTSIZE);
-#endif
   to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
+  to->ut_session = from->ut_session;
+  to->ut_tv.tv_sec = from->ut_tv.tv_sec;
+  to->ut_tv.tv_usec = from->ut_tv.tv_usec;
+  memcpy (to->ut_addr_v6, from->ut_addr_v6, sizeof (to->ut_addr_v6));
 }
-
-#endif /* utmp-convert.h */
+libc_hidden_def (__utmp_convert32to64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c b/login/utmp-convert.h
similarity index 59%
rename from sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
rename to login/utmp-convert.h
index 7774a59580..43125f249d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent.c
+++ b/login/utmp-convert.h
@@ -16,17 +16,23 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdlib.h>
-#include <utmp.h>
 
-#include "utmp-compat.h"
+/* This file provides functions converting between the 32 and 64 bit
+   struct utmp variants.  */
 
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent.c"
+#ifndef _UTMP_CONVERT_H
+#define _UTMP_CONVERT_H 1
 
-#if defined SHARED
-default_symbol_version (__getutent, getutent, UTMP_COMPAT_BASE);
-#endif
+#include <utmp32.h>
+
+/* Convert the 64 bit struct utmp value in FROM to the 32 bit version
+   returned in TO.  */
+void __utmp_convert64to32 (const struct utmp *from, struct utmp32 *to)
+  attribute_hidden;
+
+/* Convert the 32 bit struct utmp value in FROM to the 64 bit version
+   returned in TO.  */
+void __utmp_convert32to64 (const struct utmp32 *from, struct utmp *to);
+libc_hidden_proto (__utmp_convert32to64);
+
+#endif /* utmp-convert.h */
diff --git a/login/utmp-path.h b/login/utmp-path.h
index 351a932862..27191b23a4 100644
--- a/login/utmp-path.h
+++ b/login/utmp-path.h
@@ -19,8 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME.  If the argument ends with 'x' and the file does not
diff --git a/login/utmp-private.h b/login/utmp-private.h
index 00632ce51d..689ee82273 100644
--- a/login/utmp-private.h
+++ b/login/utmp-private.h
@@ -22,23 +22,43 @@
 #define _UTMP_PRIVATE_H	1
 
 #include <utmp.h>
+#include <utmp32.h>
+#include <sys/param.h>
 #include <libc-lock.h>
 
 /* These functions check for initialization, but not perform any
    locking.  */
-int __libc_setutent (void) attribute_hidden;
+void __libc_setutent (void) attribute_hidden;
+void __libc_endutent (void) attribute_hidden;
+
 int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
 int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
   attribute_hidden;
 struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
-void __libc_endutent (void) attribute_hidden;
 int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
 
+void __libc_setutent32 (void) attribute_hidden;
+int __libc_getutent32_r (struct utmp32 *, struct utmp32 **) attribute_hidden;
+int __libc_getutid32_r (const struct utmp32 *, struct utmp32 *,
+			struct utmp32 **) attribute_hidden;
+int __libc_getutline32_r (const struct utmp32 *, struct utmp32 *,
+			  struct utmp32 **) attribute_hidden;
+struct utmp32 *__libc_pututline32 (const struct utmp32 *) attribute_hidden;
+int __libc_updwtmp32 (const char *, const struct utmp32 *) attribute_hidden;
+
 /* Current file name.  */
 extern const char *__libc_utmp_file_name attribute_hidden;
 
+enum __libc_utmpname_mode_t
+{
+  UTMPNAME_TIME64,
+  UTMPNAME_TIME32,
+  UTMPNAME_UNDEF
+};
+extern enum __libc_utmpname_mode_t __libc_utmpname_mode attribute_hidden;
+
 /* Locks access to the global data.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
 
diff --git a/login/utmp32.c b/login/utmp32.c
new file mode 100644
index 0000000000..427bd97449
--- /dev/null
+++ b/login/utmp32.c
@@ -0,0 +1,247 @@
+/* Compability symbols for utmp with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-lock.h>
+
+#include <utmp32.h>
+#include <utmp-convert.h>
+#include <utmp-private.h>
+#include <utmp-path.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+
+/* The compat utmp{x} functions are used for 32-bit time_t utmp/utmpx struct
+   and they use two operation modes:
+
+   1. Read/write 64-bit utmp{x} entries and convert them to/from 32-bit utmp.
+      This is done for the exported UTMP_FILE / WUTMP_FILE
+      (__libc_utmpname_mode equal to UTMPNAME_TIME64).
+
+   2. Read/write 32-bit utmp if the target file is any other than the default
+      UTMP_FILE / WUTMP_FILE ones.
+
+   It allows maintaining the already set file format for old records, while
+   also allowing reading newer ones (which might be created with call to the
+   default utmp/utmpx symbol version).  */
+
+int
+__getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+	       struct utmp32 **result)
+{
+  int r;
+
+  switch (id->ut_type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+    case INIT_PROCESS:
+    case LOGIN_PROCESS:
+    case USER_PROCESS:
+    case DEAD_PROCESS:
+      break;
+    default:
+      __set_errno (EINVAL);
+      *result = NULL;
+      return -1;
+    }
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (id, &in64);
+
+      r =  __libc_getutid_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutid32_r (id, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutid32_r, getutid_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutid32 (const struct utmp32 *id)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutid32_r (id, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutid32, getutid, GLIBC_2_0);
+
+int
+__getutline32_r (const struct utmp32 *line,
+		 struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      struct utmp out64;
+      struct utmp *out64p;
+
+      __utmp_convert32to64 (line, &in64);
+
+      r =  __libc_getutline_r (&in64, &out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+      else
+	*result = NULL;
+    }
+  else
+    r = __libc_getutline32_r (line, buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutline32_r, getutline_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutline32 (const struct utmp32 *line)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutline32_r (line, out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutline32, getutline, GLIBC_2_0);
+
+struct utmp32 *
+__pututline32 (const struct utmp32 *line)
+{
+  struct utmp32 *r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+   {
+      struct utmp in64;
+      __utmp_convert32to64 (line, &in64);
+      struct utmp *out64p = __libc_pututline (&in64);
+      r = out64p != NULL ? (struct utmp32 *) line : NULL;
+    }
+  else
+    r = __libc_pututline32 (line);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __pututline32, pututline, GLIBC_2_0);
+
+int
+__getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r;
+
+  __libc_lock_lock (__libc_utmp_lock);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp out64;
+      struct utmp *out64p;
+      r = __libc_getutent_r (&out64, &out64p);
+      if (r == 0)
+	{
+	  __utmp_convert64to32 (out64p, buffer);
+	  *result = buffer;
+	}
+    }
+  else
+    r = __libc_getutent32_r (buffer, result);
+
+  __libc_lock_unlock (__libc_utmp_lock);
+
+  return r;
+}
+compat_symbol (libc, __getutent32_r, getutent_r, GLIBC_2_0);
+
+struct utmp32 *
+__getutent32 (void)
+{
+  static struct utmp32 *out32 = NULL;
+  if (out32 == NULL)
+    {
+      out32 = malloc (sizeof (struct utmp32));
+      if (out32 == NULL)
+	return NULL;
+    }
+
+  struct utmp32 *result;
+  return __getutent32_r (out32, &result) < 0 ? NULL : result;
+}
+compat_symbol (libc, __getutent32, getutent, GLIBC_2_0);
+
+void
+__updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
+{
+  const char *file_name = utmp_file_name_time32 (wtmp_file);
+
+  if (__libc_utmpname_mode == UTMPNAME_TIME64)
+    {
+      struct utmp in32;
+      __utmp_convert32to64 (utmp, &in32);
+      __libc_updwtmp (file_name, &in32);
+    }
+  else
+    __libc_updwtmp32 (file_name, utmp);
+}
+compat_symbol (libc, __updwtmp32, updwtmp, GLIBC_2_0);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h b/login/utmp32.h
similarity index 78%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
rename to login/utmp32.h
index 002b5377d6..a3440a4c73 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.h
+++ b/login/utmp32.h
@@ -47,5 +47,14 @@ struct utmp32
   char __glibc_reserved[20];		/* Reserved for future use.  */
 };
 
+int __getutid32_r (const struct utmp32 *, struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutid32 (const struct utmp32 *);
+int __getutline32_r (const struct utmp32 *, struct utmp32 *,
+		     struct utmp32 **);
+struct utmp32 *__getutline32 (const struct utmp32 *line);
+struct utmp32 *__pututline32 (const struct utmp32 *line);
+int __getutent32_r (struct utmp32 *, struct utmp32 **);
+struct utmp32 *__getutent32 (void);
+void __updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp);
 
 #endif  /* utmp32.h  */
diff --git a/login/utmp_file.c b/login/utmp_file.c
index 377209b26d..ee1fe51b43 100644
--- a/login/utmp_file.c
+++ b/login/utmp_file.c
@@ -17,22 +17,16 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <signal.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
-#include <utmp.h>
-#include <not-cancel.h>
-#include <kernel-features.h>
-#include <sigsetops.h>
+#include <sys/param.h>
 #include <not-cancel.h>
 
-#include "utmp-private.h"
+#include <utmp-private.h>
 #include <utmp-path.h>
+#include <utmp-compat.h>
+#include <shlib-compat.h>
 
 
 /* Descriptor for the file and position.  */
@@ -40,41 +34,91 @@ static int file_fd = -1;
 static bool file_writable;
 static off64_t file_offset;
 
+
+/* The utmp{x} internal functions work on two operations modes
+
+   1. Read/write 64-bit time utmp{x} entries using the exported
+      'struct utmp{x}'
+
+   2. Read/write 32-bit time utmp{x} entries using the old 'struct utmp32'
+
+   The operation mode mainly change the register size and how to interpret
+   the 'last_entry' buffered record.  */
+enum operation_mode_t
+{
+  UTMP_TIME64,
+  UTMP_TIME32
+};
+static enum operation_mode_t cur_mode = UTMP_TIME64;
+
+enum
+{
+  utmp_buffer_size = MAX (sizeof (struct utmp), sizeof (struct utmp32))
+};
+
 /* Cache for the last read entry.  */
-static struct utmp last_entry;
+static char last_entry[utmp_buffer_size];
+
+static inline size_t last_entry_size (enum operation_mode_t mode)
+{
+  return mode == UTMP_TIME64 ? sizeof (struct utmp) : sizeof (struct utmp32);
+}
+
+static inline short int last_entry_type (enum operation_mode_t mode)
+{
+  short int r;
+  if (mode == UTMP_TIME32)
+    memcpy (&r, last_entry + offsetof (struct utmp32, ut_type), sizeof (r));
+  else
+    memcpy (&r, last_entry + offsetof (struct utmp, ut_type), sizeof (r));
+  return r;
+}
+
+static inline const char *last_entry_id (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_id;
+  return ((struct utmp32 *) (last_entry))->ut_id;
+}
+
+static inline const char *last_entry_line (enum operation_mode_t mode)
+{
+  if (mode == UTMP_TIME64)
+   return ((struct utmp *) (last_entry))->ut_line;
+  return ((struct utmp32 *) (last_entry))->ut_line;
+}
 
-/* Returns true if *ENTRY matches last_entry, based on
-   data->ut_type.  */
+/* Returns true if *ENTRY matches last_entry, based on data->ut_type.  */
 static bool
-matches_last_entry (const struct utmp *data)
+matches_last_entry (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line)
 {
   if (file_offset <= 0)
     /* Nothing has been read.  last_entry is stale and cannot match.  */
     return false;
 
-  if (data->ut_type == RUN_LVL
-      || data->ut_type == BOOT_TIME
-      || data->ut_type == OLD_TIME
-      || data->ut_type == NEW_TIME)
-    /* For some entry types, only a type match is required.  */
-    return data->ut_type == last_entry.ut_type;
-  else
-    /* For the process-related entries, a full match is needed.  */
-    return (data->ut_type == INIT_PROCESS
-	    || data->ut_type == LOGIN_PROCESS
-	    || data->ut_type == USER_PROCESS
-	    || data->ut_type == DEAD_PROCESS)
-      && (last_entry.ut_type == INIT_PROCESS
-	  || last_entry.ut_type == LOGIN_PROCESS
-	  || last_entry.ut_type == USER_PROCESS
-	  || last_entry.ut_type == DEAD_PROCESS)
-      && (data->ut_id[0] && last_entry.ut_id[0]
-	  ? strncmp (data->ut_id, last_entry.ut_id,
-		     sizeof last_entry.ut_id)
-	    == 0
-	  : (strncmp (data->ut_line, last_entry.ut_line,
-		      sizeof last_entry.ut_line)
-	     == 0));
+  switch (type)
+    {
+    case RUN_LVL:
+    case BOOT_TIME:
+    case OLD_TIME:
+    case NEW_TIME:
+      /* For some entry types, only a type match is required.  */
+      return type == last_entry_type (mode);
+    default:
+      /* For the process-related entries, a full match is needed.  */
+      return (type == INIT_PROCESS
+	      || type == LOGIN_PROCESS
+	      || type == USER_PROCESS
+	      || type == DEAD_PROCESS)
+	&& (last_entry_type (mode) == INIT_PROCESS
+	    || last_entry_type (mode) == LOGIN_PROCESS
+	    || last_entry_type (mode) == USER_PROCESS
+	    || last_entry_type (mode) == DEAD_PROCESS)
+	&& (id[0] != '\0' && last_entry_id (mode)[0] != '\0'
+	    ? strncmp (id, last_entry_id (mode), 4 * sizeof (char)) == 0
+	    : (strncmp (line, last_entry_id (mode), UT_LINESIZE) == 0));
+    }
 }
 
 /* Locking timeout.  */
@@ -143,33 +187,40 @@ file_unlock (int fd)
   __fcntl64_nocancel (fd, F_SETLKW, &fl);
 }
 
-int
-__libc_setutent (void)
+static bool
+internal_setutent (enum operation_mode_t mode)
 {
   if (file_fd < 0)
     {
-      const char *file_name;
-
-      file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	?__libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       file_writable = false;
       file_fd = __open_nocancel
 	(file_name, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
       if (file_fd == -1)
-	return 0;
+	return false;
+      cur_mode = mode;
     }
 
   __lseek64 (file_fd, 0, SEEK_SET);
   file_offset = 0;
 
-  return 1;
+  return true;
 }
 
 /* Preform initialization if necessary.  */
 static bool
-maybe_setutent (void)
+maybe_setutent (enum operation_mode_t mode)
 {
-  return file_fd >= 0 || __libc_setutent ();
+  if (file_fd >= 0 && cur_mode != mode)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+      file_offset = 0;
+    }
+  return file_fd >= 0 || internal_setutent (mode);
 }
 
 /* Reads the entry at file_offset, storing it in last_entry and
@@ -177,40 +228,34 @@ maybe_setutent (void)
    for EOF, and 1 for a successful read.  last_entry and file_offset
    are only updated on a successful and complete read.  */
 static ssize_t
-read_last_entry (void)
+read_last_entry (enum operation_mode_t mode)
 {
-  struct utmp buffer;
-  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
-				       file_offset);
+  char buffer[utmp_buffer_size];
+  const size_t size = last_entry_size (mode);
+  ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, size, file_offset);
   if (nbytes < 0)
     return -1;
-  else if (nbytes != sizeof (buffer))
+  else if (nbytes != size)
     /* Assume EOF.  */
     return 0;
   else
     {
-      last_entry = buffer;
-      file_offset += sizeof (buffer);
+      memcpy (last_entry, buffer, size);
+      file_offset += size;
       return 1;
     }
 }
 
-int
-__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+static int
+internal_getutent_r (enum operation_mode_t mode, void *buffer)
 {
   int saved_errno = errno;
 
-  if (!maybe_setutent ())
-    {
-      /* Not available.  */
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
     return -1;
 
-  ssize_t nbytes = read_last_entry ();
+  ssize_t nbytes = read_last_entry (mode);
   file_unlock (file_fd);
 
   if (nbytes <= 0)		/* Read error or EOF.  */
@@ -220,111 +265,86 @@ __libc_getutent_r (struct utmp *buffer, struct utmp **result)
 	   EOF is treated like an EOF (missing complete record at the
 	   end).  */
 	__set_errno (saved_errno);
-      *result = NULL;
       return -1;
     }
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
-
+  memcpy (buffer, &last_entry, last_entry_size (mode));
   return 0;
 }
 
-
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  Does not perform locking; for that see
    internal_getut_r below.  */
-static int
-internal_getut_nolock (const struct utmp *id)
+static bool
+internal_getut_nolock (enum operation_mode_t mode, short int type,
+		       const char *id, const char *line)
 {
-  while (1)
+  while (true)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
-	return -1;
+	return false;
       if (nbytes == 0)
 	{
 	  /* End of file reached.  */
 	  __set_errno (ESRCH);
-	  return -1;
+	  return false;
 	}
 
-      if (matches_last_entry (id))
+      if (matches_last_entry (mode, type, id, line))
 	break;
     }
-
-  return 0;
+  return true;
 }
 
 /* Search for *ID, updating last_entry and file_offset.  Return 0 on
    success and -1 on failure.  If the locking operation failed, write
    true to *LOCK_FAILED.  */
-static int
-internal_getut_r (const struct utmp *id, bool *lock_failed)
+static bool
+internal_getut_r (enum operation_mode_t mode, short int type, const char *id,
+		  const char *line)
 {
   if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *lock_failed = true;
-      return -1;
-    }
+    return false;
 
-  int result = internal_getut_nolock (id);
+  bool r = internal_getut_nolock (mode, type, id, line);
   file_unlock (file_fd);
-  return result;
+  return r;
 }
 
-/* For implementing this function we don't use the getutent_r function
-   because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
-		  struct utmp **result)
+static int
+internal_getutid_r (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode))
+    return -1;
 
   /* We don't have to distinguish whether we can lock the file or
      whether there is no entry.  */
-  bool lock_failed = false;
-  if (internal_getut_r (id, &lock_failed) < 0)
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (! internal_getut_r (mode, type, id, line))
+    return -1;
 
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
 /* For implementing this function we don't use the getutent_r function
    because we can avoid the reposition on every new entry this way.  */
-int
-__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
-		    struct utmp **result)
+static int
+internal_getutline_r (enum operation_mode_t mode, const char *line,
+		      void *buffer)
 {
-  if (!maybe_setutent ())
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  if (try_file_lock (file_fd, F_RDLCK))
-    {
-      *result = NULL;
-      return -1;
-    }
+  if (!maybe_setutent (mode)
+      || try_file_lock (file_fd, F_RDLCK))
+    return -1;
 
   while (1)
     {
-      ssize_t nbytes = read_last_entry ();
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  *result = NULL;
 	  return -1;
 	}
       if (nbytes == 0)
@@ -332,48 +352,45 @@ __libc_getutline_r (const struct utmp *line, struct utmp *buffer,
 	  /* End of file reached.  */
 	  file_unlock (file_fd);
 	  __set_errno (ESRCH);
-	  *result = NULL;
 	  return -1;
 	}
 
       /* Stop if we found a user or login entry.  */
-      if ((last_entry.ut_type == USER_PROCESS
-	   || last_entry.ut_type == LOGIN_PROCESS)
-	  && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
-	      == 0))
+      if ((last_entry_type (mode) == USER_PROCESS
+	   || last_entry_type (mode) == LOGIN_PROCESS)
+	  && (strncmp (line, last_entry_line (mode), UT_LINESIZE) == 0))
 	break;
     }
 
   file_unlock (file_fd);
-  memcpy (buffer, &last_entry, sizeof (struct utmp));
-  *result = buffer;
+  memcpy (buffer, &last_entry, last_entry_size (mode));
 
   return 0;
 }
 
-
-struct utmp *
-__libc_pututline (const struct utmp *data)
+static bool
+internal_pututline (enum operation_mode_t mode, short int type,
+		    const char *id, const char *line, const void *data)
 {
-  if (!maybe_setutent ())
-    return NULL;
-
-  struct utmp *pbuf;
+  if (!maybe_setutent (mode))
+    return false;
 
   if (! file_writable)
     {
       /* We must make the file descriptor writable before going on.  */
-      const char *file_name = utmp_file_name_time32 (__libc_utmp_file_name);
+      const char *file_name = mode == UTMP_TIME64
+	? __libc_utmp_file_name
+	: utmp_file_name_time32 (__libc_utmp_file_name);
 
       int new_fd = __open_nocancel
 	(file_name, O_RDWR | O_LARGEFILE | O_CLOEXEC);
       if (new_fd == -1)
-	return NULL;
+	return false;
 
       if (__dup2 (new_fd, file_fd) < 0)
 	{
 	  __close_nocancel_nostatus (new_fd);
-	  return NULL;
+	  return false;
 	}
       __close_nocancel_nostatus (new_fd);
       file_writable = true;
@@ -381,31 +398,32 @@ __libc_pututline (const struct utmp *data)
 
   /* Exclude other writers before validating the cache.  */
   if (try_file_lock (file_fd, F_WRLCK))
-    return NULL;
+    return false;
 
   /* Find the correct place to insert the data.  */
+  const size_t utmp_size = last_entry_size (mode);
   bool found = false;
-  if (matches_last_entry (data))
+  if (matches_last_entry (mode, type, id, line))
     {
       /* Read back the entry under the write lock.  */
-      file_offset -= sizeof (last_entry);
-      ssize_t nbytes = read_last_entry ();
+      file_offset -= utmp_size;
+      ssize_t nbytes = read_last_entry (mode);
       if (nbytes < 0)
 	{
 	  file_unlock (file_fd);
-	  return NULL;
+	  return false;
 	}
 
       if (nbytes == 0)
 	/* End of file reached.  */
 	found = false;
       else
-	found = matches_last_entry (data);
+	found = matches_last_entry (mode, type, id, line);
     }
 
   if (!found)
     /* Search forward for the entry.  */
-    found = internal_getut_nolock (data) >= 0;
+    found = internal_getut_nolock (mode, type, id, line);
 
   off64_t write_offset;
   if (!found)
@@ -416,26 +434,25 @@ __libc_pututline (const struct utmp *data)
       /* Round down to the next multiple of the entry size.  This
 	 ensures any partially-written record is overwritten by the
 	 new record.  */
-      write_offset = (write_offset / sizeof (struct utmp)
-		      * sizeof (struct utmp));
+      write_offset = write_offset / utmp_size * utmp_size;
     }
   else
     /* Overwrite last_entry.  */
-    write_offset = file_offset - sizeof (struct utmp);
+    write_offset = file_offset - utmp_size;
 
   /* Write the new data.  */
   ssize_t nbytes;
   if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
-      || (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
+      || (nbytes = __write_nocancel (file_fd, data, utmp_size)) < 0)
     {
       /* There is no need to recover the file position because all
 	 reads use pread64, and any future write is preceded by
 	 another seek.  */
       file_unlock (file_fd);
-      return NULL;
+      return false;
     }
 
-  if (nbytes != sizeof (struct utmp))
+  if (nbytes != utmp_size)
     {
       /* If we appended a new record this is only partially written.
 	 Remove it.  */
@@ -445,30 +462,18 @@ __libc_pututline (const struct utmp *data)
       /* Assume that the write failure was due to missing disk
 	 space.  */
       __set_errno (ENOSPC);
-      return NULL;
+      return false;
     }
 
   file_unlock (file_fd);
-  file_offset = write_offset + sizeof (struct utmp);
-  pbuf = (struct utmp *) data;
-
-  return pbuf;
-}
-
+  file_offset = write_offset + utmp_size;
 
-void
-__libc_endutent (void)
-{
-  if (file_fd >= 0)
-    {
-      __close_nocancel_nostatus (file_fd);
-      file_fd = -1;
-    }
+  return true;
 }
 
-
-int
-__libc_updwtmp (const char *file, const struct utmp *utmp)
+static int
+internal_updwtmp (enum operation_mode_t mode, const char *file,
+		  const void *utmp)
 {
   int result = -1;
   off64_t offset;
@@ -487,9 +492,10 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
 
   /* Remember original size of log file.  */
   offset = __lseek64 (fd, 0, SEEK_END);
-  if (offset % sizeof (struct utmp) != 0)
+  const size_t utmp_size = last_entry_size (mode);
+  if (offset % utmp_size != 0)
     {
-      offset -= offset % sizeof (struct utmp);
+      offset -= offset % utmp_size;
       __ftruncate64 (fd, offset);
 
       if (__lseek64 (fd, 0, SEEK_END) < 0)
@@ -499,8 +505,7 @@ __libc_updwtmp (const char *file, const struct utmp *utmp)
   /* Write the entry.  If we can't write all the bytes, reset the file
      size back to the original size.  That way, no partial entries
      will remain.  */
-  if (__write_nocancel (fd, utmp, sizeof (struct utmp))
-      != sizeof (struct utmp))
+  if (__write_nocancel (fd, utmp, utmp_size) != utmp_size)
     {
       __ftruncate64 (fd, offset);
       goto unlock_return;
@@ -516,3 +521,113 @@ unlock_return:
 
   return result;
 }
+
+void
+__libc_setutent (void)
+{
+  internal_setutent (UTMP_TIME64);
+}
+
+void
+__libc_setutent32 (void)
+{
+  internal_setutent (UTMP_TIME32);
+}
+
+int
+__libc_getutent_r (struct utmp *buffer, struct utmp **result)
+{
+  int r = internal_getutent_r (UTMP_TIME64, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
+		  struct utmp **result)
+{
+  int r = internal_getutid_r (UTMP_TIME64, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0? buffer : NULL;
+  return r;
+}
+
+/* For implementing this function we don't use the getutent_r function
+   because we can avoid the reposition on every new entry this way.  */
+int
+__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
+		    struct utmp **result)
+{
+  int r = internal_getutline_r (UTMP_TIME64, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp *
+__libc_pututline (const struct utmp *line)
+{
+  return internal_pututline (UTMP_TIME64, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp *) line : NULL;
+}
+
+void
+__libc_endutent (void)
+{
+  if (file_fd >= 0)
+    {
+      __close_nocancel_nostatus (file_fd);
+      file_fd = -1;
+    }
+}
+
+int
+__libc_updwtmp (const char *file, const struct utmp *utmp)
+{
+  return internal_updwtmp (UTMP_TIME64, file, utmp);
+}
+
+#if SHLIB_COMPAT(libc, GLIBC_2_0, UTMP_COMPAT_BASE)
+int
+__libc_getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
+{
+  int r = internal_getutent_r (UTMP_TIME32, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
+		    struct utmp32 **result)
+{
+  int r = internal_getutid_r (UTMP_TIME32, id->ut_type, id->ut_id,
+			      id->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+int
+__libc_getutline32_r (const struct utmp32 *line, struct utmp32 *buffer,
+		      struct utmp32 **result)
+{
+  int r = internal_getutline_r (UTMP_TIME32, line->ut_line, buffer);
+  *result = r == 0 ? buffer : NULL;
+  return r;
+}
+
+struct utmp32 *
+__libc_pututline32 (const struct utmp32 *line)
+{
+  return internal_pututline (UTMP_TIME32, line->ut_type, line->ut_id,
+			     line->ut_line, line)
+	 ? (struct utmp32 *) line : NULL;
+}
+
+int
+__libc_updwtmp32 (const char *file, const struct utmp32 *utmp)
+{
+  return internal_updwtmp (UTMP_TIME32, file, utmp);
+}
+#endif
diff --git a/login/utmpname.c b/login/utmpname.c
index c85c27fe68..c5c5bc458a 100644
--- a/login/utmpname.c
+++ b/login/utmpname.c
@@ -29,6 +29,7 @@ static const char default_file_name[] = _PATH_UTMP;
 
 /* Current file name.  */
 const char *__libc_utmp_file_name = (const char *) default_file_name;
+enum __libc_utmpname_mode_t __libc_utmpname_mode = UTMPNAME_TIME64;
 
 /* We have to use the lock in getutent_r.c.  */
 __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
@@ -66,6 +67,13 @@ __utmpname (const char *file)
 	}
     }
 
+  if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME64;
+  else if (strcmp (__libc_utmp_file_name, _PATH_UTMP_BASE) == 0)
+    __libc_utmpname_mode = UTMPNAME_TIME32;
+  else
+    __libc_utmpname_mode = UTMPNAME_UNDEF;
+
   result = 0;
 
 done:
diff --git a/login/utmpx32.c b/login/utmpx32.c
new file mode 100644
index 0000000000..5f7b327d4d
--- /dev/null
+++ b/login/utmpx32.c
@@ -0,0 +1,112 @@
+/* Compability symbols for utmpx with 32-bit entry times.
+   Copyright (C) 2008-2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <string.h>
+#include <utmp.h>
+#include <errno.h>
+#include <libc-symbols.h>
+
+#include <utmp32.h>
+#include <utmpx32.h>
+
+#include <utmp-compat.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)
+
+# define CHECK_SIZE_AND_OFFSET(field) \
+  _Static_assert (sizeof ((struct utmp32){0}.field)		\
+		  == sizeof ((struct utmpx32){0}.field),		\
+		  "sizeof ((struct utmp32){0}." #field " != "	\
+		  "sizeof ((struct utmpx32){0}" #field);	\
+  _Static_assert (offsetof (struct utmp32, field)			\
+		  == offsetof (struct utmpx32, field),		\
+		  "offsetof (struct utmp32, " #field ") != "	\
+		  "offsetof (struct utmpx32, " #field ")");
+
+/* Sanity check to call the utmp symbols.  */
+_Static_assert (sizeof (struct utmpx32) == sizeof (struct utmp32),
+		"sizeof (struct utmpx32) != sizeof (struct utmp32)");
+CHECK_SIZE_AND_OFFSET (ut_type)
+CHECK_SIZE_AND_OFFSET (ut_pid)
+CHECK_SIZE_AND_OFFSET (ut_line)
+CHECK_SIZE_AND_OFFSET (ut_user)
+CHECK_SIZE_AND_OFFSET (ut_id)
+CHECK_SIZE_AND_OFFSET (ut_host)
+CHECK_SIZE_AND_OFFSET (ut_tv)
+
+struct utmpx32 *
+getutxent32 (void)
+{
+  return (struct utmpx32 *) __getutent32 ();
+}
+compat_symbol (libc, getutxent32, getutxent, GLIBC_2_1);
+
+struct utmpx32 *
+getutxid32 (const struct utmpx32 *id)
+{
+  return (struct utmpx32 *) __getutid32 ((const struct utmp32 *) id);
+}
+compat_symbol (libc, getutxid32, getutxid, GLIBC_2_1);
+
+struct utmpx32 *
+getutxline32 (const struct utmpx32 *line)
+{
+  return (struct utmpx32 *) __getutline32 ((const struct utmp32 *) line);
+}
+compat_symbol (libc, getutxline32, getutxline, GLIBC_2_1);
+
+struct utmpx32 *
+pututxline32 (const struct utmpx32 *utmpx)
+{
+  return (struct utmpx32 *) __pututline32 ((const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, pututxline32, pututxline, GLIBC_2_1);
+
+void
+updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
+{
+  __updwtmp32 (wtmpx_file, (const struct utmp32 *) utmpx);
+}
+compat_symbol (libc, updwtmpx32, updwtmpx, GLIBC_2_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)   */
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1_1, UTMP_COMPAT_BASE)
+
+void
+__getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
+{
+  memset (utmp, 0, sizeof (struct utmpx32));
+  utmp->ut_type = utmpx->ut_type;
+  utmp->ut_pid = utmpx->ut_pid;
+  memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
+  memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
+  memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
+  memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
+  utmp->ut_tv.tv_sec = utmpx->ut_tv.tv_sec;
+  utmp->ut_tv.tv_usec = utmpx->ut_tv.tv_usec;
+}
+compat_symbol (libc, __getutmp32, getutmp, GLIBC_2_1_1);
+
+strong_alias (__getutmp32, __getutmpx32)
+compat_symbol (libc, __getutmpx32, getutmpx, GLIBC_2_1_1);
+
+#endif /* SHLIB_COMPAT(libc, GLIBC_2_1, UTMP_COMPAT_BASE)   */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h b/login/utmpx32.h
similarity index 93%
rename from sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
rename to login/utmpx32.h
index b9befad24e..ce1aa680a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.h
+++ b/login/utmpx32.h
@@ -36,11 +36,11 @@ struct utmpx32
   char ut_host[__UT_HOSTSIZE];	/* Hostname for remote login.  */
   struct __exit_status ut_exit;	/* Exit status of a process marked
 				   as DEAD_PROCESS.  */
-  __int64_t ut_session;		/* Session ID, used for windowing.  */
+  __int32_t ut_session;		/* Session ID, used for windowing.  */
   struct
   {
-    __int64_t tv_sec;		/* Seconds.  */
-    __int64_t tv_usec;		/* Microseconds.  */
+    __int32_t tv_sec;		/* Seconds.  */
+    __int32_t tv_usec;		/* Microseconds.  */
   } ut_tv;			/* Time entry was made.  */
 
   __int32_t ut_addr_v6[4];	/* Internet address of remote host.  */
diff --git a/sysdeps/generic/paths.h b/sysdeps/generic/paths.h
index 99a791ce31..ab2980e14a 100644
--- a/sysdeps/generic/paths.h
+++ b/sysdeps/generic/paths.h
@@ -61,11 +61,12 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/vmunix"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
-#define	_PATH_UTMP_DB	_PATH_UTMP_BASE ".db"
+#define _PATH_WUTMP_VER ".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_WUTMP_VER
+#define	_PATH_UTMP_DB	_PATH_UTMP_BASE _PATH_WUTMP_VER ".db"
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_WUTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/generic/utmp-compat.h b/sysdeps/generic/utmp-compat.h
new file mode 100644
index 0000000000..68cc4e0f46
--- /dev/null
+++ b/sysdeps/generic/utmp-compat.h
@@ -0,0 +1,3 @@
+/* This macro defines the glibc version tag at which the 64 bit struct
+   utmp functions have been added to the 32 bit glibc.  */
+#define UTMP_COMPAT_BASE GLIBC_2_34
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 509e9b7cb0..77589e9aab 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2203,6 +2203,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/i386/libutil.abilist b/sysdeps/mach/hurd/i386/libutil.abilist
index 1dd59e0afb..6d97d3cd5e 100644
--- a/sysdeps/mach/hurd/i386/libutil.abilist
+++ b/sysdeps/mach/hurd/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.6 login_tty F
 GLIBC_2.2.6 logout F
 GLIBC_2.2.6 logwtmp F
 GLIBC_2.2.6 openpty F
+GLIBC_2.33 login F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 4cc1c6a591..5703811d47 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2171,3 +2171,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 26ad9845e4..556144b40a 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2253,6 +2253,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libutil.abilist b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/alpha/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bb9dfd4daf..3e01139bcc 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1931,3 +1931,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/arc/libutil.abilist b/sysdeps/unix/sysv/linux/arc/libutil.abilist
index 61f73bc34e..6950302484 100644
--- a/sysdeps/unix/sysv/linux/arc/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.32 login_tty F
 GLIBC_2.32 logout F
 GLIBC_2.32 logwtmp F
 GLIBC_2.32 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3b0a47e967..ffc3be5255 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -155,6 +155,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 9ab3924888..cca9d7b2d8 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -152,6 +152,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 14a84dac8f..b11eefe55e 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2115,3 +2115,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/csky/libutil.abilist b/sysdeps/unix/sysv/linux/csky/libutil.abilist
index cbd11999a4..25006044fe 100644
--- a/sysdeps/unix/sysv/linux/csky/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.29 login_tty F
 GLIBC_2.29 logout F
 GLIBC_2.29 logwtmp F
 GLIBC_2.29 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 5c8502f3d3..f53f9d3dcc 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2074,6 +2074,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/libutil.abilist b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/hppa/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index ddc5837059..8604b9ba12 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2241,6 +2241,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libutil.abilist b/sysdeps/unix/sysv/linux/i386/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/i386/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e3b345b803..75a8b98445 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2106,6 +2106,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libutil.abilist b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/ia64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 25f2d1c08f..e293d0e766 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -156,6 +156,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
index cc1420e68c..d2d7724fa0 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libutil.abilist
@@ -1,3 +1,4 @@
+GLIBC_2.34 login F
 GLIBC_2.4 forkpty F
 GLIBC_2.4 login F
 GLIBC_2.4 login_tty F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c4891479d3..ef071cd43f 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2186,6 +2186,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 143b0163b4..7861c80ac2 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2166,3 +2166,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 13d374a031..c0aa1dd398 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2163,3 +2163,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
index 0da0a40c22..eef306314b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.18 login_tty F
 GLIBC_2.18 logout F
 GLIBC_2.18 logwtmp F
 GLIBC_2.18 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b2295f1937..10b83a39e5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2157,6 +2157,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 4c786070d0..51cde431b8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2155,6 +2155,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index aa9c6a4dca..5adbd9019e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2163,6 +2163,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5939588ad5..9870c6d28a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2157,6 +2157,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 92556c4237..49f615353b 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2204,3 +2204,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/nios2/libutil.abilist b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
index 19608bd74d..7ef9a41873 100644
--- a/sysdeps/unix/sysv/linux/nios2/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.21 login_tty F
 GLIBC_2.21 logout F
 GLIBC_2.21 logwtmp F
 GLIBC_2.21 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/paths.h b/sysdeps/unix/sysv/linux/paths.h
index 3b8aeab788..89686bcf88 100644
--- a/sysdeps/unix/sysv/linux/paths.h
+++ b/sysdeps/unix/sysv/linux/paths.h
@@ -62,10 +62,11 @@
 #define	_PATH_TTY	"/dev/tty"
 #define	_PATH_UNIX	"/boot/vmlinux"
 #define	_PATH_UTMP_BASE	"/var/run/utmp"
-#define	_PATH_UTMP	_PATH_UTMP_BASE
+#define	_PATH_UWTMP_VER	".v2"
+#define	_PATH_UTMP	_PATH_UTMP_BASE _PATH_UWTMP_VER
 #define	_PATH_VI	"/usr/bin/vi"
 #define	_PATH_WTMP_BASE	"/var/log/wtmp"
-#define	_PATH_WTMP	_PATH_WTMP_BASE
+#define	_PATH_WTMP	_PATH_WTMP_BASE _PATH_UWTMP_VER
 
 /* Provide trailing slash, since mostly used for building pathnames. */
 #define	_PATH_DEV	"/dev/"
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 26c93dff05..b349bde439 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2213,6 +2213,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f04b167788..43b2aabe84 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2246,6 +2246,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index c2ca00709e..7f02c58ee7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2076,6 +2076,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
index 9cf1da7aa4..fc74cb2c77 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.3 login_tty F
 GLIBC_2.3 logout F
 GLIBC_2.3 logwtmp F
 GLIBC_2.3 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0ea50dc851..2da63c5a70 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2366,3 +2366,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
index 99889de22e..3294de79be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.17 login_tty F
 GLIBC_2.17 logout F
 GLIBC_2.17 logwtmp F
 GLIBC_2.17 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 0263e284d4..216e14cba2 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1933,3 +1933,18 @@ GLIBC_2.33 wprintf F
 GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
index 59ae944bda..eded210f0b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.33 login_tty F
 GLIBC_2.33 logout F
 GLIBC_2.33 logwtmp F
 GLIBC_2.33 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 1626c5351f..a34560861b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2133,3 +2133,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
index cbfec8d46e..ec3a638024 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.27 login_tty F
 GLIBC_2.27 logout F
 GLIBC_2.27 logwtmp F
 GLIBC_2.27 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
deleted file mode 100644
index eebccece1c..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutent_r.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-weak_alias (__setutent, setutent)
-weak_alias (__endutent, endutent)
-
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutent_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutent_r, getutent_r, UTMP_COMPAT_BASE);
-default_symbol_version (__pututline, pututline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
deleted file mode 100644
index f50d633e48..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid.c"
-
-#if defined SHARED
-default_symbol_version (__getutid, getutid, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
deleted file mode 100644
index 5039b99a94..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutid_r.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <libc-lock.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutid_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutid_r, getutid_r, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
deleted file mode 100644
index 32b39575b0..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline.c"
-
-#if defined SHARED
-default_symbol_version (__getutline, getutline, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
deleted file mode 100644
index c9238c5f60..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutline_r.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <errno.h>
-#include <libc-lock.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include "login/getutline_r.c"
-
-#if defined SHARED
-default_symbol_version (__getutline_r, getutline_r, UTMP_COMPAT_BASE);;
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
deleted file mode 100644
index 6ffea2a553..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutmp.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#undef weak_alias
-#define weak_alias(a, b)
-#undef strong_alias
-#define strong_alias(a, b)
-
-#include <login/getutmp.c>
-
-#include "utmp-compat.h"
-
-default_symbol_version (__getutmp, getutmp, UTMP_COMPAT_BASE);
-_strong_alias (__getutmp, __getutmpx)
-default_symbol_version (__getutmpx, getutmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
deleted file mode 100644
index d91795af78..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxent.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxent __getutxent
-#include "login/getutxent.c"
-#undef getutxent
-
-default_symbol_version (__getutxent, getutxent, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
deleted file mode 100644
index d5d457d98d..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxid.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxid __getutxid
-#include "login/getutxid.c"
-#undef getutxid
-
-default_symbol_version (__getutxid, getutxid, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
deleted file mode 100644
index ab0189f653..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/getutxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define getutxline __getutxline
-#include "login/getutxline.c"
-#undef getutxline
-
-default_symbol_version (__getutxline, getutxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/login.c b/sysdeps/unix/sysv/linux/s390/s390-32/login.c
deleted file mode 100644
index 5df028298a..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/login.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <utmp.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define login __login
-#include "login/login.c"
-#undef login
-
-default_symbol_version (__login, login, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c b/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
deleted file mode 100644
index 1dfabc8f37..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/pututxline.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define pututxline __pututxline
-#include "login/pututxline.c"
-#undef pututxline
-
-default_symbol_version (__pututxline, pututxline, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
deleted file mode 100644
index 7ef8e85c00..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmp.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-
-#include "utmp-compat.h"
-#include "utmp-private.h"
-
-#if defined SHARED
-# undef weak_alias
-# define weak_alias(n,a)
-#endif
-#include <login/updwtmp.c>
-
-#if defined SHARED
-default_symbol_version (__updwtmp, updwtmp, UTMP_COMPAT_BASE);
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c b/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
deleted file mode 100644
index 51cf1f5ae3..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/updwtmpx.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <utmp.h>
-#include <utmpx.h>
-
-#include "utmp-compat.h"
-
-#undef weak_alias
-#define weak_alias(n,a)
-#define updwtmpx __updwtmpx
-#include "login/updwtmpx.c"
-#undef updwtmpx
-
-default_symbol_version (__updwtmpx, updwtmpx, UTMP_COMPAT_BASE);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
index 28632f72bd..dc4c926cca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/utmp-compat.h
@@ -18,4 +18,4 @@
 
 /* This macro defines the glibc version tag at which the 64 bit struct
    utmp functions have been added to the 32 bit glibc.  */
-#define UTMP_COMPAT_BASE GLIBC_2.9
+#define UTMP_COMPAT_BASE GLIBC_2_9
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
deleted file mode 100644
index 32496e5421..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmp32.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMP32_OUT(OUT)			\
-  static struct utmp32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmp32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmp entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmp and the result is
-   converted back to 32 bit utmp.  */
-#define ACCESS_UTMP_ENTRY(FUNC, FIELD)			\
-  struct utmp in64;					\
-  struct utmp *out64;					\
-  ALLOCATE_UTMP32_OUT (out32);				\
-							\
-  utmp_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmp_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_type matching ID->ut_type.  */
-struct utmp32 *
-getutid32 (const struct utmp32 *id)
-{
-  ACCESS_UTMP_ENTRY (__getutid, id)
-}
-symbol_version (getutid32, getutid, GLIBC_2.0);
-
-/* Search forward from the current point in the utmp file until the
-   next entry with a ut_line matching LINE->ut_line.  */
-struct utmp32 *
-getutline32 (const struct utmp32 *line)
-{
-  ACCESS_UTMP_ENTRY (__getutline, line)
-}
-symbol_version (getutline32, getutline, GLIBC_2.0);
-
-/* Write out entry pointed to by UTMP_PTR into the utmp file.  */
-struct utmp32 *
-pututline32 (const struct utmp32 *utmp_ptr)
-{
-  ACCESS_UTMP_ENTRY (__pututline, utmp_ptr)
-}
-symbol_version (pututline32, pututline, GLIBC_2.0);
-
-/* Read next entry from a utmp-like file.  */
-struct utmp32 *
-getutent32 (void)
-{
-  struct utmp *out64;
-  ALLOCATE_UTMP32_OUT (out32);
-
-  out64 = __getutent ();
-  if (!out64)
-    return NULL;
-
-  utmp_convert64to32 (out64, out32);
-  return out32;
-}
-symbol_version (getutent32, getutent, GLIBC_2.0);
-
-/* Reentrant versions of the file for handling utmp files.  */
-
-int
-getutent32_r (struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  ret = __getutent_r (&out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutent32_r, getutent_r, GLIBC_2.0);
-
-int
-getutid32_r (const struct utmp32 *id, struct utmp32 *buffer,
-	       struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (id, &in64);
-
-  ret = __getutid_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-}
-symbol_version (getutid32_r, getutid_r, GLIBC_2.0);
-
-int
-getutline32_r (const struct utmp32 *line,
-		 struct utmp32 *buffer, struct utmp32 **result)
-{
-  struct utmp in64;
-  struct utmp out64;
-  struct utmp *out64p;
-  int ret;
-
-  utmp_convert32to64 (line, &in64);
-
-  ret = __getutline_r (&in64, &out64, &out64p);
-  if (ret == -1)
-    {
-      *result = NULL;
-      return -1;
-    }
-
-  utmp_convert64to32 (out64p, buffer);
-  *result = buffer;
-
-  return 0;
-
-}
-symbol_version (getutline32_r, getutline_r, GLIBC_2.0);
-
-/* Append entry UTMP to the wtmp-like file WTMP_FILE.  */
-void
-updwtmp32 (const char *wtmp_file, const struct utmp32 *utmp)
-{
-  struct utmp in32;
-
-  utmp_convert32to64 (utmp, &in32);
-  __updwtmp (wtmp_file, &in32);
-}
-symbol_version (updwtmp32, updwtmp, GLIBC_2.0);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
deleted file mode 100644
index ad7de5c455..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx-convert.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-/* This file provides functions converting between the 32 and 64 bit
-   struct utmp variants.  */
-
-#ifndef _UTMPX_CONVERT_H
-#define _UTMPX_CONVERT_H 1
-
-#include <string.h>
-#include "utmpx32.h"
-
-/* Convert the 64 bit struct utmpx value in FROM to the 32 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert64to32 (const struct utmpx *from, struct utmpx32 *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int32_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int32_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int32_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-/* Convert the 32 bit struct utmpx value in FROM to the 64 bit version
-   returned in TO.  */
-static inline void
-utmpx_convert32to64 (const struct utmpx32 *from, struct utmpx *to)
-{
-#if _HAVE_UT_TYPE - 0
-  to->ut_type = from->ut_type;
-#endif
-#if _HAVE_UT_PID - 0
-  to->ut_pid = from->ut_pid;
-#endif
-  memcpy (to->ut_line, from->ut_line, __UT_LINESIZE);
-  memcpy (to->ut_user, from->ut_user, __UT_NAMESIZE);
-#if _HAVE_UT_ID - 0
-  memcpy (to->ut_id, from->ut_id, 4);
-#endif
-#if _HAVE_UT_HOST - 0
-  memcpy (to->ut_host, from->ut_host, __UT_HOSTSIZE);
-#endif
-  to->ut_exit = from->ut_exit;
-  to->ut_session = (int64_t) from->ut_session;
-#if _HAVE_UT_TV - 0
-  to->ut_tv.tv_sec = (int64_t) from->ut_tv.tv_sec;
-  to->ut_tv.tv_usec = (int64_t) from->ut_tv.tv_usec;
-#endif
-  memcpy (to->ut_addr_v6, from->ut_addr_v6, 4 * 4);
-}
-
-#endif /* utmpx-convert.h */
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c b/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
deleted file mode 100644
index ed970961bf..0000000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/utmpx32.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2008-2021 Free Software Foundation, Inc.
-   Contributed by Andreas Krebbel <Andreas.Krebbel@de.ibm.com>.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <utmp.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "utmp32.h"
-#include "utmp-convert.h"
-
-#include "utmpx32.h"
-#include "utmpx-convert.h"
-
-/* Allocate a static buffer to be returned to the caller.  As well as
-   with the existing version of these functions the caller has to be
-   aware that the contents of this buffer will change with subsequent
-   calls.  */
-#define ALLOCATE_UTMPX32_OUT(OUT)			\
-  static struct utmpx32 *OUT = NULL;			\
-							\
-  if (OUT == NULL)					\
-    {							\
-      OUT = malloc (sizeof (struct utmpx32));		\
-      if (OUT == NULL)					\
-	return NULL;					\
-    }
-
-/* Perform a lookup for a utmpx entry matching FIELD using function
-   FUNC.  FIELD is converted to a 64 bit utmpx and the result is
-   converted back to 32 bit utmpx.  */
-#define ACCESS_UTMPX_ENTRY(FUNC, FIELD)			\
-  struct utmpx in64;					\
-  struct utmpx *out64;					\
-  ALLOCATE_UTMPX32_OUT (out32);				\
-							\
-  utmpx_convert32to64 (FIELD, &in64);			\
-  out64 = FUNC (&in64);					\
-							\
-  if (out64 == NULL)					\
-    return NULL;					\
-							\
-  utmpx_convert64to32 (out64, out32);			\
-							\
-  return out32;
-
-
-/* Get the next entry from the user accounting database.  */
-struct utmpx32 *
-getutxent32 (void)
-{
-  struct utmpx *out64;
-  ALLOCATE_UTMPX32_OUT (out32);
-
-  out64 = __getutxent ();
-  if (!out64)
-    return NULL;
-
-  utmpx_convert64to32 (out64, out32);
-  return out32;
-
-}
-symbol_version (getutxent32, getutxent, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to ID.  */
-struct utmpx32 *
-getutxid32 (const struct utmpx32 *id)
-{
-  ACCESS_UTMPX_ENTRY (__getutxid, id);
-}
-symbol_version (getutxid32, getutxid, GLIBC_2.1);
-
-/* Get the user accounting database entry corresponding to LINE.  */
-struct utmpx32 *
-getutxline32 (const struct utmpx32 *line)
-{
-  ACCESS_UTMPX_ENTRY (__getutxline, line);
-}
-symbol_version (getutxline32, getutxline, GLIBC_2.1);
-
-/* Write the entry UTMPX into the user accounting database.  */
-struct utmpx32 *
-pututxline32 (const struct utmpx32 *utmpx)
-{
-  ACCESS_UTMPX_ENTRY (__pututxline, utmpx);
-}
-symbol_version (pututxline32, pututxline, GLIBC_2.1);
-
-/* Append entry UTMP to the wtmpx-like file WTMPX_FILE.  */
-void
-updwtmpx32 (const char *wtmpx_file, const struct utmpx32 *utmpx)
-{
-  struct utmpx in64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __updwtmpx (wtmpx_file, &in64);
-}
-symbol_version (updwtmpx32, updwtmpx, GLIBC_2.1);
-
-/* Copy the information in UTMPX to UTMP.  */
-void
-getutmp32 (const struct utmpx32 *utmpx, struct utmp32 *utmp)
-{
-  struct utmpx in64;
-  struct utmp out64;
-
-  utmpx_convert32to64 (utmpx, &in64);
-  __getutmp (&in64, &out64);
-  utmp_convert64to32 (&out64, utmp);
-}
-symbol_version (getutmp32, getutmp, GLIBC_2.1.1);
-
-/* Copy the information in UTMP to UTMPX.  */
-void
-getutmpx32 (const struct utmp32 *utmp, struct utmpx32 *utmpx)
-{
-  struct utmp in64;
-  struct utmpx out64;
-
-  utmp_convert32to64 (utmp, &in64);
-  __getutmpx (&in64, &out64);
-  utmpx_convert64to32 (&out64, utmpx);
-}
-symbol_version (getutmpx32, getutmpx, GLIBC_2.1.1);
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
new file mode 100644
index 0000000000..fee4b80cc0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/utmp-compat.h
@@ -0,0 +1,3 @@
+/* s390x already has 64-bit time for struct utmp{x} and lastlog.  This define
+   disable the compat symbols and support to 32-bit entries.  */
+#define UTMP_COMPAT_BASE GLIBC_2_0
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 22ceaa3d87..b5b3b6c247 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2081,6 +2081,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d36f228192..a0f1547fbf 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2078,6 +2078,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 59b4313280..c76547d839 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2202,6 +2202,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 266dcdfa08..75a0132c20 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2129,6 +2129,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
index aa2d35b323..fbff40d968 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.0 login_tty F
 GLIBC_2.0 logout F
 GLIBC_2.0 logwtmp F
 GLIBC_2.0 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/utmp-path.h b/sysdeps/unix/sysv/linux/utmp-path.h
index a377bc9dba..f42638e2c5 100644
--- a/sysdeps/unix/sysv/linux/utmp-path.h
+++ b/sysdeps/unix/sysv/linux/utmp-path.h
@@ -19,9 +19,8 @@
 #ifndef _UTMP_PATH_H
 #define _UTMP_PATH_H 1
 
-#include <string.h>
 #include <unistd.h>
-
+#include <string.h>
 
 /* The function returns the utmp database for 32-bit utmp{x} entries based
    on FILE_NAME:
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 2744bba4af..14bbd3450a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2088,6 +2088,21 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
index 1356ed4115..f68fa6e9ba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.2.5 login_tty F
 GLIBC_2.2.5 logout F
 GLIBC_2.2.5 logwtmp F
 GLIBC_2.2.5 openpty F
+GLIBC_2.34 login F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index ce2f4fb72b..95b58039e0 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2185,3 +2185,18 @@ GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
+GLIBC_2.34 getutent F
+GLIBC_2.34 getutent_r F
+GLIBC_2.34 getutid F
+GLIBC_2.34 getutid_r F
+GLIBC_2.34 getutline F
+GLIBC_2.34 getutline_r F
+GLIBC_2.34 getutmp F
+GLIBC_2.34 getutmpx F
+GLIBC_2.34 getutxent F
+GLIBC_2.34 getutxid F
+GLIBC_2.34 getutxline F
+GLIBC_2.34 pututline F
+GLIBC_2.34 pututxline F
+GLIBC_2.34 updwtmp F
+GLIBC_2.34 updwtmpx F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
index cff23106f5..5a66c2b333 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libutil.abilist
@@ -4,3 +4,4 @@ GLIBC_2.16 login_tty F
 GLIBC_2.16 logout F
 GLIBC_2.16 logwtmp F
 GLIBC_2.16 openpty F
+GLIBC_2.34 login F


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

end of thread, other threads:[~2021-03-05 19:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-23 12:37 [glibc/azanella/y2038] login: Add 64-bit time support to utmp/utmpx Adhemerval Zanella
2021-02-23 20:39 Adhemerval Zanella
2021-02-26 20:41 Adhemerval Zanella
2021-03-01 17:35 Adhemerval Zanella
2021-03-02 12:31 Adhemerval Zanella
2021-03-04 11:29 Adhemerval Zanella
2021-03-04 17:36 Adhemerval Zanella
2021-03-05 19:19 Adhemerval Zanella

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).