diff options
author | Aurelien Jarno <aurelien@aurel32.net> | 2020-02-04 22:10:53 +0100 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2020-02-04 22:10:53 +0100 |
commit | b3e514beec20b2d66e22aa3c8460b9589ac58a21 (patch) | |
tree | 0092b55fa9ba6e055dcdfe54f94aff0111200ada | |
parent | 49e8e3916f0666d31904ffc9a4e9acc7053aac10 (diff) |
debian/patches/git-updates.diff: update from upstream stable branch.
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | debian/patches/git-updates.diff | 2438 |
2 files changed, 2440 insertions, 5 deletions
diff --git a/debian/changelog b/debian/changelog index 24063a28..b00e784d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +glibc (2.30-0experimental2) UNRELEASED; urgency=medium + + [ Aurelien Jarno ] + * debian/patches/git-updates.diff: update from upstream stable branch. + + -- Aurelien Jarno <aurel32@debian.org> Tue, 04 Feb 2020 22:10:26 +0100 + glibc (2.30-0experimental1) experimental; urgency=medium [ Samuel Thibault ] diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff index 5b80c956..d15cbfc2 100644 --- a/debian/patches/git-updates.diff +++ b/debian/patches/git-updates.diff @@ -1,10 +1,136 @@ GIT update of https://sourceware.org/git/glibc.git/release/2.30/master from glibc-2.30 diff --git a/ChangeLog b/ChangeLog -index cdb9e14881..c4687dfd4c 100644 +index cdb9e14881..bc2f4aae69 100644 --- a/ChangeLog +++ b/ChangeLog -@@ -1,3 +1,88 @@ +@@ -1,3 +1,214 @@ ++2019-08-15 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24899] ++ * sysdeps/gnu/bits/utmpx.h (struct utmpx): Add ++ __attribute_nonstring__ to ut_line, ut_id, ut_user, ut_host. ++ * sysdeps/unix/sysv/linux/s390/bits/utmpx.h (struct utmpx): ++ Likewise. ++ * sysdeps/gnu/bits/utmp.h (struct utmp): Add ++ __attribute_nonstring__ to ut_id. ++ * sysdeps/unix/sysv/linux/s390/bits/utmpx.h (struct utmp): ++ Likewise. ++ ++2019-08-28 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24902] ++ * login/Makefile (tests): Add tst-pututxline-lockfail. ++ (tst-pututxline-lockfail): Link with -lpthread. ++ * login/utmp_file.c (internal_getut_r): Remove buffer argument. ++ (__libc_getutid_r): Adjust. ++ (__libc_pututline): Likewise. Check for file_offset == -1. ++ * login/tst-pututxline-lockfail.c: New file. ++ ++2019-08-15 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24880] ++ * login/utmp_file.c (file_locking_failed): Use struct flock64. ++ (file_locking_unlock): Likewise. ++ ++2019-08-15 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #24879] ++ login: Disarm timer after utmp lock acquisition. ++ * login/utmp_file.c (struct file_locking): Remove. ++ (try_file_lock): Adjust. ++ (file_lock_restore): Remove function. ++ (__libc_getutent_r): . ++ (internal_getut_r): Likewise. ++ (__libc_getutline_r): Likewise. ++ (__libc_pututline): Likewise. ++ (__libc_updwtmp): Likewise. ++ ++2019-08-15 Florian Weimer <fweimer@redhat.com> ++ ++ * login/utmp_file.c (__libc_updwtmp): Unlock the right file ++ descriptor. ++ * login/Makefile (tests): Add tst-updwtmpx. ++ * login/tst-updwtmpx.c: New file. ++ ++2019-08-13 Florian Weimer <fweimer@redhat.com> ++ ++ * login/utmp_file.c (LOCK_FILE, LOCKING_FAILED, UNLOCK_FILE): ++ Remove macros. ++ (struct file_locking): New. ++ (try_file_lock, file_unlock, file_lock_restore): New functions. ++ (__libc_getutent_r): Use the new functions. ++ (internal_getut_r): Likewise. ++ (__libc_getutline_r): Likewise. ++ (__libc_pututline): Likewise. ++ (__libc_updwtmp): Likewise. ++ ++2019-08-13 Florian Weimer <fweimer@redhat.com> ++ ++ * login/getutid_r.c (__getutid_r): _HAVE_UT_ID and _HAVE_UT_TYPE ++ are always true. ++ * login/getutmp.c (getutmp): _HAVE_UT_TYPE, _HAVE_UT_PID, ++ _HAVE_UT_ID, _HAVE_UT_HOST, _HAVE_UT_TV are always true. ++ * login/getutmpx.c (getutmpx): Likewise. ++ * login/login.c (login): _HAVE_UT_TYPE, _HAVE_UT_PID are always ++ true. ++ * login/logout.c (logout): _HAVE_UT_TYPE, _HAVE_UT_HOST, ++ _HAVE_UT_TV are always true. ++ * login/logwtmp.c (logwtmp): _HAVE_UT_PID, _HAVE_UT_TYPE, ++ _HAVE_UT_HOST, _HAVE_UT_TV are always true. ++ * login/tst-utmp.c: _HAVE_UT_TYPE, _HAVE_UT_TV are always true. ++ * login/utmp_file.c (__libc_setutent): _HAVE_UT_TYPE, _HAVE_UT_ID ++ are always true. ++ (internal_getut_r): _HAVE_UT_TYPE is always true. ++ (__libc_pututline): Likewise. ++ * login/programs/utmpdump.c (print_entry): Assume that ++ _HAVE_UT_TYPE, _HAVE_UT_PID, _HAVE_UT_ID, _HAVE_UT_HOST, ++ _HAVE_UT_TV are always true. ++ * sysdeps/generic/utmp-equal.h (__utmp_equal): _HAVE_UT_TYPE, ++ _HAVE_UT_ID are always true. ++ * sysdeps/gnu/bits/utmp.h: Move to ... ++ * bits/utmp.h: ... here, replacing the old file. ++ ++2019-08-05 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #23518] ++ * login/uptmp-private.h (struct ufuncs): Remove definition. ++ (__libc_utmp_file_functions, __libc_utmp_unknown_functions) ++ (__libc_utmp_jump_table): Remove declarations. ++ (__libc_setutent, __libc_getutent_r, __libc_getutid_r) ++ (__libc_getutline_r, __libc_pututline, __libc_endutent) ++ (__libc_updwtmp): Declare. ++ * login/getutent_r.c (__libc_utmp_unknown_functions) ++ (__libc_utmp_jump_table, setutent_unknown, getutent_r_unknown) ++ (getutid_r_unknown, getutline_r_unknown, pututline_unknown) ++ (endutent_unknown): Remove definitions. ++ (__setutent): Call __libc_setutent. ++ (__getutent_r): Call __libc_getutent_r. ++ (__pututline): Call __libc_pututline. ++ (__endutent): Call __libc_endutent. ++ * login/getutid_r.c (__getutid_r): Call __libc_getutid_r. ++ * login/getutline_r.c (__getutline_r): Call __libc_getutline_r. ++ * login/updwtmp.c (__updwtmp): Call __libc_updwtmp. ++ * login/utmp_file.c (__libc_utmp_file_functions): Remove definition ++ (__libc_setutent): Rename from stetutent_file. Drop static. ++ (maybe_setutent): New function. ++ (__libc_getutent_r): Rename from getutent_r_file. Drop static. ++ Check for initialization. ++ (__libc_getutid_r): Rename from getutid_r_file. Drop static. ++ Check for initialization. ++ (__libc_getutline_r): Rename from getutline_r_file. Drop static. ++ Check for initialization. ++ (__libc_pututline): Rename from pututline_file. Drop static. ++ Check for initialization. ++ (__libc_endutent): Rename from endutent_file. Drop static. Check ++ for initialization. ++ (__libc_updwtmp): Rename from updwtmp_file. Drop static. ++ * login/utmpname.c (__utmpname): Call __libc_endutent. ++ * sysdeps/unix/getlogin_r (__getlogin_r): Call __libc_setutent, ++ __libc_getutlien_r, __libc_endutent. ++ * manual/users.texi (Who Logged In, Manipulating the Database): ++ Adjust. ++ +2019-08-15 Florian Weimer <fweimer@redhat.com> + + * malloc/Makefile (tests): Only add tst-mxfast for @@ -94,10 +220,10 @@ index cdb9e14881..c4687dfd4c 100644 * version.h (RELEASE): Set to "stable". diff --git a/NEWS b/NEWS -index ee9ed4de5a..74826b9eb8 100644 +index ee9ed4de5a..2c707f35ff 100644 --- a/NEWS +++ b/NEWS -@@ -4,6 +4,30 @@ See the end for copying conditions. +@@ -4,6 +4,37 @@ See the end for copying conditions. Please send GNU C library bug reports via <https://sourceware.org/bugzilla/> using `glibc' in the "product" field. @@ -114,20 +240,157 @@ index ee9ed4de5a..74826b9eb8 100644 + +The following bugs are resolved with this release: + ++ [23518] login: Remove utmp backend jump tables + [24682] localedata: zh_CN first weekday should be Monday per GB/T + 7408-2005 + [24867] malloc: Remove unwanted leading whitespace in malloc_info ++ [24879] login: Disarm timer after utmp lock acquisition ++ [24880] login: Use struct flock64 in utmp ++ [24882] login: Acquire write lock early in pututline + [24986] alpha: new getegid, geteuid and getppid syscalls used + unconditionally ++ [24899] login: Add nonstring attributes to struct utmp, struct utmpx ++ [24902] login: pututxline could fail to overwrite existing entries + [25189] Don't use a custom wrapper macro around __has_include + [25203] libio: Disable vtable validation for pre-2.1 interposed handles + [25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs + [25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection + [25232] No const correctness for strchr et al. for Clang++ ++ [25401] Remove incorrect alloc_size attribute from pvalloc + Version 2.30 +diff --git a/bits/utmp.h b/bits/utmp.h +index 4c36ca19ce..854b342164 100644 +--- a/bits/utmp.h ++++ b/bits/utmp.h +@@ -1,4 +1,4 @@ +-/* The `struct utmp' type, describing entries in the utmp file. Generic/BSDish ++/* The `struct utmp' type, describing entries in the utmp file. + Copyright (C) 1993-2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -21,29 +21,107 @@ + #endif + + #include <paths.h> +-#include <time.h> ++#include <sys/time.h> ++#include <sys/types.h> ++#include <bits/wordsize.h> + + +-#define UT_NAMESIZE 8 +-#define UT_LINESIZE 8 +-#define UT_HOSTSIZE 16 ++#define UT_LINESIZE 32 ++#define UT_NAMESIZE 32 ++#define UT_HOSTSIZE 256 + + ++/* The structure describing an entry in the database of ++ previous logins. */ + struct lastlog + { +- time_t ll_time; ++#if __WORDSIZE_TIME64_COMPAT32 ++ int32_t ll_time; ++#else ++ __time_t ll_time; ++#endif + char ll_line[UT_LINESIZE]; + char ll_host[UT_HOSTSIZE]; + }; + +-struct utmp ++ ++/* The structure describing the status of a terminated process. This ++ type is used in `struct utmp' below. */ ++struct exit_status + { +- char ut_line[UT_LINESIZE]; +- char ut_user[UT_NAMESIZE]; +-#define ut_name ut_user +- char ut_host[UT_HOSTSIZE]; +- long int ut_time; ++ short int e_termination; /* Process termination status. */ ++ short int e_exit; /* Process exit status. */ + }; + + +-#define _HAVE_UT_HOST 1 /* We have the ut_host field. */ ++/* The structure describing an entry in the user accounting database. */ ++struct utmp ++{ ++ short int ut_type; /* Type of login. */ ++ pid_t ut_pid; /* Process ID of login process. */ ++ char ut_line[UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ ++ struct exit_status ut_exit; /* Exit status of a process marked ++ as DEAD_PROCESS. */ ++/* 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. */ ++ struct ++ { ++ int32_t tv_sec; /* Seconds. */ ++ int32_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. */ ++}; ++ ++/* Backwards compatibility hacks. */ ++#define ut_name ut_user ++#ifndef _NO_UT_TIME ++/* We have a problem here: `ut_time' is also used otherwise. Define ++ _NO_UT_TIME if the compiler complains. */ ++# define ut_time ut_tv.tv_sec ++#endif ++#define ut_xtime ut_tv.tv_sec ++#define ut_addr ut_addr_v6[0] ++ ++ ++/* Values for the `ut_type' field of a `struct utmp'. */ ++#define EMPTY 0 /* No valid user accounting information. */ ++ ++#define RUN_LVL 1 /* The system's runlevel. */ ++#define BOOT_TIME 2 /* Time of system boot. */ ++#define NEW_TIME 3 /* Time after system clock changed. */ ++#define OLD_TIME 4 /* Time when system clock changed. */ ++ ++#define INIT_PROCESS 5 /* Process spawned by the init process. */ ++#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ ++#define USER_PROCESS 7 /* Normal process. */ ++#define DEAD_PROCESS 8 /* Terminated process. */ ++ ++#define ACCOUNTING 9 ++ ++/* Old Linux name for the EMPTY type. */ ++#define UT_UNKNOWN EMPTY ++ ++ ++/* Tell the user that we have a modern system with UT_HOST, UT_PID, ++ UT_TYPE, UT_ID and UT_TV fields. */ ++#define _HAVE_UT_TYPE 1 ++#define _HAVE_UT_PID 1 ++#define _HAVE_UT_ID 1 ++#define _HAVE_UT_TV 1 ++#define _HAVE_UT_HOST 1 diff --git a/configure b/configure index c773c487b5..6d26b8246f 100755 --- a/configure @@ -258,10 +521,1747 @@ index 62a46415c1..cd4b33602a 100644 END LC_TIME LC_MESSAGES +diff --git a/login/Makefile b/login/Makefile +index 92535f0aec..4fd8195e73 100644 +--- a/login/Makefile ++++ b/login/Makefile +@@ -43,7 +43,8 @@ endif + subdir-dirs = programs + vpath %.c programs + +-tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin ++tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \ ++ tst-pututxline-lockfail tst-pututxline-cache + + # Build the -lutil library with these extra functions. + extra-libs := libutil +@@ -71,3 +72,6 @@ endif + $(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force) + $(make-target-directory) + -$(INSTALL_PROGRAM) -m 4755 -o root $< $@ ++ ++$(objpfx)tst-pututxline-lockfail: $(shared-thread-library) ++$(objpfx)tst-pututxline-cache: $(shared-thread-library) +diff --git a/login/getutent_r.c b/login/getutent_r.c +index 98ffc5d1c6..fd13be8a1e 100644 +--- a/login/getutent_r.c ++++ b/login/getutent_r.c +@@ -23,115 +23,16 @@ + + #include "utmp-private.h" + +- +-/* Functions defined here. */ +-static int setutent_unknown (void); +-static int getutent_r_unknown (struct utmp *buffer, struct utmp **result); +-static int getutid_r_unknown (const struct utmp *line, struct utmp *buffer, +- struct utmp **result); +-static int getutline_r_unknown (const struct utmp *id, struct utmp *buffer, +- struct utmp **result); +-static struct utmp *pututline_unknown (const struct utmp *data); +-static void endutent_unknown (void); +- +-/* Initial Jump table. */ +-const struct utfuncs __libc_utmp_unknown_functions = +-{ +- setutent_unknown, +- getutent_r_unknown, +- getutid_r_unknown, +- getutline_r_unknown, +- pututline_unknown, +- endutent_unknown, +- NULL +-}; +- +-/* Currently selected backend. */ +-const struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions; +- + /* We need to protect the opening of the file. */ + __libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden) + + +-static int +-setutent_unknown (void) +-{ +- int result; +- +- result = (*__libc_utmp_file_functions.setutent) (); +- if (result) +- __libc_utmp_jump_table = &__libc_utmp_file_functions; +- +- return result; +-} +- +- +-static int +-getutent_r_unknown (struct utmp *buffer, struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutent_r) (buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static int +-getutid_r_unknown (const struct utmp *id, struct utmp *buffer, +- struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutid_r) (id, buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static int +-getutline_r_unknown (const struct utmp *line, struct utmp *buffer, +- struct utmp **result) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->getutline_r) (line, buffer, result); +- +- /* Not available. */ +- *result = NULL; +- return -1; +-} +- +- +-static struct utmp * +-pututline_unknown (const struct utmp *data) +-{ +- /* The backend was not yet initialized. */ +- if (setutent_unknown ()) +- return (*__libc_utmp_jump_table->pututline) (data); +- +- /* Not available. */ +- return NULL; +-} +- +- +-static void +-endutent_unknown (void) +-{ +- /* Nothing to do. */ +-} +- +- + void + __setutent (void) + { + __libc_lock_lock (__libc_utmp_lock); + +- (*__libc_utmp_jump_table->setutent) (); ++ __libc_setutent (); + + __libc_lock_unlock (__libc_utmp_lock); + } +@@ -145,7 +46,7 @@ __getutent_r (struct utmp *buffer, struct utmp **result) + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result); ++ retval = __libc_getutent_r (buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +@@ -162,7 +63,7 @@ __pututline (const struct utmp *data) + + __libc_lock_lock (__libc_utmp_lock); + +- buffer = (*__libc_utmp_jump_table->pututline) (data); ++ buffer = __libc_pututline (data); + + __libc_lock_unlock (__libc_utmp_lock); + +@@ -177,8 +78,7 @@ __endutent (void) + { + __libc_lock_lock (__libc_utmp_lock); + +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + + __libc_lock_unlock (__libc_utmp_lock); + } +diff --git a/login/getutid_r.c b/login/getutid_r.c +index 34ea61d8f4..460d94be0c 100644 +--- a/login/getutid_r.c ++++ b/login/getutid_r.c +@@ -32,7 +32,6 @@ __libc_lock_define (extern, __libc_utmp_lock attribute_hidden) + int + __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + { +-#if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0) + int retval; + + /* Test whether ID has any of the legal types. */ +@@ -49,15 +48,11 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result) + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result); ++ retval = __libc_getutid_r (id, buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + + return retval; +-#else /* !_HAVE_UT_ID && !_HAVE_UT_TYPE */ +- __set_errno (ENOSYS); +- return -1; +-#endif + } + libc_hidden_def (__getutid_r) + weak_alias (__getutid_r, getutid_r) +diff --git a/login/getutline_r.c b/login/getutline_r.c +index 110b89e438..f03255dbbd 100644 +--- a/login/getutline_r.c ++++ b/login/getutline_r.c +@@ -36,7 +36,7 @@ __getutline_r (const struct utmp *line, struct utmp *buffer, + + __libc_lock_lock (__libc_utmp_lock); + +- retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result); ++ retval = __libc_getutline_r (line, buffer, result); + + __libc_lock_unlock (__libc_utmp_lock); + +diff --git a/login/getutmp.c b/login/getutmp.c +index 73bc15d781..4e3be11216 100644 +--- a/login/getutmp.c ++++ b/login/getutmp.c +@@ -23,23 +23,11 @@ + void + getutmp (const struct utmpx *utmpx, struct utmp *utmp) + { +-#if _HAVE_UT_TYPE - 0 + utmp->ut_type = utmpx->ut_type; +-#endif +-#if _HAVE_UT_PID - 0 + utmp->ut_pid = utmpx->ut_pid; +-#endif + memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line)); + memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user)); +-#if _HAVE_UT_ID - 0 + memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id)); +-#endif +-#if _HAVE_UT_HOST - 0 + memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host)); +-#endif +-#if _HAVE_UT_TV - 0 + utmp->ut_tv = utmpx->ut_tv; +-#else +- utmp->ut_time = utmpx->ut_time; +-#endif + } +diff --git a/login/getutmpx.c b/login/getutmpx.c +index b181d9bc30..da28d339ab 100644 +--- a/login/getutmpx.c ++++ b/login/getutmpx.c +@@ -24,24 +24,11 @@ void + getutmpx (const struct utmp *utmp, struct utmpx *utmpx) + { + memset (utmpx, 0, sizeof (struct utmpx)); +- +-#if _HAVE_UT_TYPE - 0 + utmpx->ut_type = utmp->ut_type; +-#endif +-#if _HAVE_UT_PID - 0 + utmpx->ut_pid = utmp->ut_pid; +-#endif + memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line)); + memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user)); +-#if _HAVE_UT_ID - 0 + memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id)); +-#endif +-#if _HAVE_UT_HOST - 0 + memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host)); +-#endif +-#if _HAVE_UT_TV - 0 + utmpx->ut_tv = utmp->ut_tv; +-#else +- utmpx->ut_time = utmp->ut_time; +-#endif + } +diff --git a/login/login.c b/login/login.c +index 09ef3f75a5..b7d638c692 100644 +--- a/login/login.c ++++ b/login/login.c +@@ -91,12 +91,8 @@ login (const struct utmp *ut) + struct utmp copy = *ut; + + /* Fill in those fields we supply. */ +-#if _HAVE_UT_TYPE - 0 + copy.ut_type = USER_PROCESS; +-#endif +-#if _HAVE_UT_PID - 0 + copy.ut_pid = getpid (); +-#endif + + /* Seek tty. */ + found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty)); +diff --git a/login/logout.c b/login/logout.c +index 85254d0324..5015c1af0b 100644 +--- a/login/logout.c ++++ b/login/logout.c +@@ -36,9 +36,7 @@ logout (const char *line) + setutent (); + + /* Fill in search information. */ +-#if _HAVE_UT_TYPE - 0 + tmp.ut_type = USER_PROCESS; +-#endif + strncpy (tmp.ut_line, line, sizeof tmp.ut_line); + + /* Read the record. */ +@@ -46,20 +44,12 @@ logout (const char *line) + { + /* Clear information about who & from where. */ + memset (ut->ut_name, '\0', sizeof ut->ut_name); +-#if _HAVE_UT_HOST - 0 + memset (ut->ut_host, '\0', sizeof ut->ut_host); +-#endif +-#if _HAVE_UT_TV - 0 + struct timeval tv; + __gettimeofday (&tv, NULL); + ut->ut_tv.tv_sec = tv.tv_sec; + ut->ut_tv.tv_usec = tv.tv_usec; +-#else +- ut->ut_time = time (NULL); +-#endif +-#if _HAVE_UT_TYPE - 0 + ut->ut_type = DEAD_PROCESS; +-#endif + + if (pututline (ut) != NULL) + result = 1; +diff --git a/login/logwtmp.c b/login/logwtmp.c +index f53187121c..50d14976c7 100644 +--- a/login/logwtmp.c ++++ b/login/logwtmp.c +@@ -30,26 +30,16 @@ logwtmp (const char *line, const char *name, const char *host) + + /* Set information in new entry. */ + memset (&ut, 0, sizeof (ut)); +-#if _HAVE_UT_PID - 0 + ut.ut_pid = getpid (); +-#endif +-#if _HAVE_UT_TYPE - 0 + ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS; +-#endif + strncpy (ut.ut_line, line, sizeof ut.ut_line); + strncpy (ut.ut_name, name, sizeof ut.ut_name); +-#if _HAVE_UT_HOST - 0 + strncpy (ut.ut_host, host, sizeof ut.ut_host); +-#endif + +-#if _HAVE_UT_TV - 0 + struct timeval tv; + __gettimeofday (&tv, NULL); + ut.ut_tv.tv_sec = tv.tv_sec; + ut.ut_tv.tv_usec = tv.tv_usec; +-#else +- ut.ut_time = time (NULL); +-#endif + + updwtmp (_PATH_WTMP, &ut); + } +diff --git a/login/programs/utmpdump.c b/login/programs/utmpdump.c +index 4c312f0939..85d8e31b43 100644 +--- a/login/programs/utmpdump.c ++++ b/login/programs/utmpdump.c +@@ -37,47 +37,11 @@ print_entry (struct utmp *up) + temp_tv.tv_sec = up->ut_tv.tv_sec; + temp_tv.tv_usec = up->ut_tv.tv_usec; + +- (printf) ( +- /* The format string. */ +-#if _HAVE_UT_TYPE +- "[%d] " +-#endif +-#if _HAVE_UT_PID +- "[%05d] " +-#endif +-#if _HAVE_UT_ID +- "[%-4.4s] " +-#endif +- "[%-8.8s] [%-12.12s]" +-#if _HAVE_UT_HOST +- " [%-16.16s]" +-#endif +- " [%-15.15s]" +-#if _HAVE_UT_TV +- " [%ld]" +-#endif +- "\n" +- /* The arguments. */ +-#if _HAVE_UT_TYPE +- , up->ut_type +-#endif +-#if _HAVE_UT_PID +- , up->ut_pid +-#endif +-#if _HAVE_UT_ID +- , up->ut_id +-#endif +- , up->ut_user, up->ut_line +-#if _HAVE_UT_HOST +- , up->ut_host +-#endif +-#if _HAVE_UT_TV +- , 4 + ctime (&temp_tv.tv_sec) +- , (long int) temp_tv.tv_usec +-#else +- , 4 + ctime (&up->ut_time) +-#endif +- ); ++ printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-16.16s] [%-15.15s]" ++ " [%ld]\n", ++ up->ut_type, up->ut_pid, up->ut_id, up->ut_user, up->ut_line, ++ up->ut_host, 4 + ctime (&temp_tv.tv_sec), ++ (long int) temp_tv.tv_usec); + } + + int +diff --git a/login/tst-pututxline-cache.c b/login/tst-pututxline-cache.c +new file mode 100644 +index 0000000000..3f30dd1776 +--- /dev/null ++++ b/login/tst-pututxline-cache.c +@@ -0,0 +1,193 @@ ++/* Test case for cache invalidation after concurrent write (bug 24882). ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see <http://www.gnu.org/licenses/>. */ ++ ++/* This test writes an entry to the utmpx file, reads it (so that it ++ is cached) in process1, and overwrites the same entry in process2 ++ with something that does not match the search criteria. At this ++ point, the cache of the first process is stale, and when process1 ++ attempts to write a new record which would have gone to the same ++ place (as indicated by the cache), it needs to realize that it has ++ to pick a different slot because the old slot is now used for ++ something else. */ ++ ++#include <errno.h> ++#include <stdlib.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/support.h> ++#include <support/temp_file.h> ++#include <support/xthread.h> ++#include <support/xunistd.h> ++#include <utmp.h> ++#include <utmpx.h> ++ ++/* Set to the path of the utmp file. */ ++static char *utmp_file; ++ ++/* Used to synchronize the subprocesses. The barrier itself is ++ allocated in shared memory. */ ++static pthread_barrier_t *barrier; ++ ++/* setutxent with error checking. */ ++static void ++xsetutxent (void) ++{ ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++} ++ ++/* getutxent with error checking. */ ++static struct utmpx * ++xgetutxent (void) ++{ ++ errno = 0; ++ struct utmpx *result = getutxent (); ++ if (result == NULL) ++ FAIL_EXIT1 ("getutxent: %m"); ++ return result; ++} ++ ++static void ++put_entry (const char *id, pid_t pid, const char *user, const char *line) ++{ ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_pid = pid, ++ .ut_host = "localhost", ++ }; ++ strcpy (ut.ut_id, id); ++ strncpy (ut.ut_user, user, sizeof (ut.ut_user)); ++ strncpy (ut.ut_line, line, sizeof (ut.ut_line)); ++ TEST_VERIFY (pututxline (&ut) != NULL); ++} ++ ++/* Use two cooperating subprocesses to avoid issues related to ++ unlock-on-close semantics of POSIX advisory locks. */ ++ ++static __attribute__ ((noreturn)) void ++process1 (void) ++{ ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ ++ /* Create an entry. */ ++ xsetutxent (); ++ put_entry ("1", 101, "root", "process1"); ++ ++ /* Retrieve the entry. This will fill the internal cache. */ ++ { ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_line = "process1", ++ }; ++ struct utmpx *result = getutxline (&ut); ++ if (result == NULL) ++ FAIL_EXIT1 ("getutxline (\"process1\"): %m"); ++ TEST_COMPARE (result->ut_pid, 101); ++ } ++ ++ /* Signal the other process to overwrite the entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for the other process to complete the write operation. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Add another entry. Note: This time, there is no setutxent call. */ ++ put_entry ("1", 103, "root", "process1"); ++ ++ _exit (0); ++} ++ ++static void ++process2 (void *closure) ++{ ++ /* Wait for the first process to write its entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Truncate the file. The glibc interface does not support ++ re-purposing records, but an external expiration mechanism may ++ trigger this. */ ++ TEST_COMPARE (truncate64 (utmp_file, 0), 0); ++ ++ /* Write the replacement entry. */ ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ xsetutxent (); ++ put_entry ("2", 102, "user", "process2"); ++ ++ /* Signal the other process that the entry has been replaced. */ ++ xpthread_barrier_wait (barrier); ++} ++ ++static int ++do_test (void) ++{ ++ xclose (create_temp_file ("tst-tumpx-cache-write-", &utmp_file)); ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS); ++ barrier = support_shared_allocate (sizeof (*barrier)); ++ xpthread_barrier_init (barrier, &attr, 2); ++ } ++ ++ /* Run both subprocesses in parallel. */ ++ { ++ pid_t pid1 = xfork (); ++ if (pid1 == 0) ++ process1 (); ++ support_isolate_in_subprocess (process2, NULL); ++ int status; ++ xwaitpid (pid1, &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ /* Check that the utmpx database contains the expected records. */ ++ { ++ TEST_COMPARE (utmpname (utmp_file), 0); ++ xsetutxent (); ++ ++ struct utmpx *ut = xgetutxent (); ++ TEST_COMPARE_STRING (ut->ut_id, "2"); ++ TEST_COMPARE (ut->ut_pid, 102); ++ TEST_COMPARE_STRING (ut->ut_user, "user"); ++ TEST_COMPARE_STRING (ut->ut_line, "process2"); ++ ++ ut = xgetutxent (); ++ TEST_COMPARE_STRING (ut->ut_id, "1"); ++ TEST_COMPARE (ut->ut_pid, 103); ++ TEST_COMPARE_STRING (ut->ut_user, "root"); ++ TEST_COMPARE_STRING (ut->ut_line, "process1"); ++ ++ if (getutxent () != NULL) ++ FAIL_EXIT1 ("additional utmpx entry"); ++ } ++ ++ xpthread_barrier_destroy (barrier); ++ support_shared_free (barrier); ++ free (utmp_file); ++ ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/login/tst-pututxline-lockfail.c b/login/tst-pututxline-lockfail.c +new file mode 100644 +index 0000000000..47c25dc065 +--- /dev/null ++++ b/login/tst-pututxline-lockfail.c +@@ -0,0 +1,176 @@ ++/* Test the lock upgrade path in tst-pututxline. ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see <http://www.gnu.org/licenses/>. */ ++ ++/* pututxline upgrades the read lock on the file to a write lock. ++ This test verifies that if the lock upgrade fails, the utmp ++ subsystem remains in a consistent state, so that pututxline can be ++ called again. */ ++ ++#include <errno.h> ++#include <fcntl.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/support.h> ++#include <support/temp_file.h> ++#include <support/xthread.h> ++#include <support/xunistd.h> ++#include <unistd.h> ++#include <utmp.h> ++#include <utmpx.h> ++ ++/* Path to the temporary utmp file. */ ++static char *path; ++ ++/* Used to synchronize the subprocesses. The barrier itself is ++ allocated in shared memory. */ ++static pthread_barrier_t *barrier; ++ ++/* Use pututxline to write an entry for PID. */ ++static struct utmpx * ++write_entry (pid_t pid) ++{ ++ struct utmpx ut = ++ { ++ .ut_type = LOGIN_PROCESS, ++ .ut_id = "1", ++ .ut_user = "root", ++ .ut_pid = pid, ++ .ut_line = "entry", ++ .ut_host = "localhost", ++ }; ++ return pututxline (&ut); ++} ++ ++/* Create the initial entry in a subprocess, so that the utmp ++ subsystem in the original process is not disturbed. */ ++static void ++subprocess_create_entry (void *closure) ++{ ++ TEST_COMPARE (utmpname (path), 0); ++ TEST_VERIFY (write_entry (101) != NULL); ++} ++ ++/* Acquire an advisory read lock on PATH. */ ++__attribute__ ((noreturn)) static void ++subprocess_lock_file (void) ++{ ++ int fd = xopen (path, O_RDONLY, 0); ++ ++ struct flock64 fl = ++ { ++ .l_type = F_RDLCK, ++ fl.l_whence = SEEK_SET, ++ }; ++ TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0); ++ ++ /* Signal to the main process that the lock has been acquired. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for the unlock request from the main process. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Implicitly unlock the file. */ ++ xclose (fd); ++ ++ /* Overwrite the existing entry. */ ++ TEST_COMPARE (utmpname (path), 0); ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (write_entry (102) != NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ _exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ xclose (create_temp_file ("tst-pututxline-lockfail-", &path)); ++ ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS); ++ barrier = support_shared_allocate (sizeof (*barrier)); ++ xpthread_barrier_init (barrier, &attr, 2); ++ xpthread_barrierattr_destroy (&attr); ++ } ++ ++ /* Write the initial entry. */ ++ support_isolate_in_subprocess (subprocess_create_entry, NULL); ++ ++ pid_t locker_pid = xfork (); ++ if (locker_pid == 0) ++ subprocess_lock_file (); ++ ++ /* Wait for the file locking to complete. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Try to add another entry. This attempt will fail, with EINTR or ++ EAGAIN. */ ++ TEST_COMPARE (utmpname (path), 0); ++ TEST_VERIFY (write_entry (102) == NULL); ++ if (errno != EINTR) ++ TEST_COMPARE (errno, EAGAIN); ++ ++ /* Signal the subprocess to overwrite the entry. */ ++ xpthread_barrier_wait (barrier); ++ ++ /* Wait for write and unlock to complete. */ ++ { ++ int status; ++ xwaitpid (locker_pid, &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ /* The file is no longer locked, so this operation will succeed. */ ++ TEST_VERIFY (write_entry (103) != NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ /* Check that there is just one entry with the expected contents. ++ If pututxline becomes desynchronized internally, the entry is not ++ overwritten (bug 24902). */ ++ errno = 0; ++ setutxent (); ++ TEST_COMPARE (errno, 0); ++ struct utmpx *ut = getutxent (); ++ TEST_VERIFY_EXIT (ut != NULL); ++ TEST_COMPARE (ut->ut_type, LOGIN_PROCESS); ++ TEST_COMPARE_STRING (ut->ut_id, "1"); ++ TEST_COMPARE_STRING (ut->ut_user, "root"); ++ TEST_COMPARE (ut->ut_pid, 103); ++ TEST_COMPARE_STRING (ut->ut_line, "entry"); ++ TEST_COMPARE_STRING (ut->ut_host, "localhost"); ++ TEST_VERIFY (getutxent () == NULL); ++ errno = 0; ++ endutxent (); ++ TEST_COMPARE (errno, 0); ++ ++ xpthread_barrier_destroy (barrier); ++ support_shared_free (barrier); ++ free (path); ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/login/tst-updwtmpx.c b/login/tst-updwtmpx.c +new file mode 100644 +index 0000000000..0a4a27daeb +--- /dev/null ++++ b/login/tst-updwtmpx.c +@@ -0,0 +1,112 @@ ++/* Basic test coverage for updwtmpx. ++ Copyright (C) 2019 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; see the file COPYING.LIB. If ++ not, see <http://www.gnu.org/licenses/>. */ ++ ++/* This program runs a series of tests. Each one calls updwtmpx ++ twice, to write two records, optionally with misalignment in the ++ file, and reads back the results. */ ++ ++#include <errno.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/descriptors.h> ++#include <support/support.h> ++#include <support/temp_file.h> ++#include <support/test-driver.h> ++#include <support/xunistd.h> ++#include <unistd.h> ++#include <utmpx.h> ++ ++static int ++do_test (void) ++{ ++ /* Two entries filled with an arbitrary bit pattern. */ ++ struct utmpx entries[2]; ++ unsigned char pad; ++ { ++ unsigned char *p = (unsigned char *) &entries[0]; ++ for (size_t i = 0; i < sizeof (entries); ++i) ++ { ++ p[i] = i; ++ } ++ /* Make sure that the first and second entry and the padding are ++ different. */ ++ p[sizeof (struct utmpx)] = p[0] + 1; ++ pad = p[0] + 2; ++ } ++ ++ char *path; ++ int fd = create_temp_file ("tst-updwtmpx-", &path); ++ ++ /* Used to check that updwtmpx does not leave an open file ++ descriptor around. */ ++ struct support_descriptors *descriptors = support_descriptors_list (); ++ ++ /* updwtmpx is expected to remove misalignment. Optionally insert ++ one byte of misalignment at the start and in the middle (after ++ the first entry). */ ++ for (int misaligned_start = 0; misaligned_start < 2; ++misaligned_start) ++ for (int misaligned_middle = 0; misaligned_middle < 2; ++misaligned_middle) ++ { ++ if (test_verbose > 0) ++ printf ("info: misaligned_start=%d misaligned_middle=%d\n", ++ misaligned_start, misaligned_middle); ++ ++ xftruncate (fd, 0); ++ TEST_COMPARE (pwrite64 (fd, &pad, misaligned_start, 0), ++ misaligned_start); ++ ++ /* Write first entry and check it. */ ++ errno = 0; ++ updwtmpx (path, &entries[0]); ++ TEST_COMPARE (errno, 0); ++ support_descriptors_check (descriptors); ++ TEST_COMPARE (xlseek (fd, 0, SEEK_END), sizeof (struct utmpx)); ++ struct utmpx buffer; ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]), ++ &buffer, sizeof (buffer)); ++ ++ /* Middle mis-alignmet. */ ++ TEST_COMPARE (pwrite64 (fd, &pad, misaligned_middle, ++ sizeof (struct utmpx)), misaligned_middle); ++ ++ /* Write second entry and check both entries. */ ++ errno = 0; ++ updwtmpx (path, &entries[1]); ++ TEST_COMPARE (errno, 0); ++ support_descriptors_check (descriptors); ++ TEST_COMPARE (xlseek (fd, 0, SEEK_END), 2 * sizeof (struct utmpx)); ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]), ++ &buffer, sizeof (buffer)); ++ TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), sizeof (buffer)), ++ sizeof (buffer)); ++ TEST_COMPARE_BLOB (&entries[1], sizeof (entries[1]), ++ &buffer, sizeof (buffer)); ++ } ++ ++ support_descriptors_free (descriptors); ++ free (path); ++ xclose (fd); ++ ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/login/tst-utmp.c b/login/tst-utmp.c +index ce48e8326e..02d0c1fe8c 100644 +--- a/login/tst-utmp.c ++++ b/login/tst-utmp.c +@@ -39,8 +39,6 @@ + #endif + + +-#if defined UTMPX || _HAVE_UT_TYPE +- + /* Prototype for our test function. */ + static int do_test (int argc, char *argv[]); + +@@ -75,11 +73,7 @@ do_prepare (int argc, char *argv[]) + + struct utmp entry[] = + { +-#if defined UTMPX || _HAVE_UT_TV + #define UT(a) .ut_tv = { .tv_sec = (a)} +-#else +-#define UT(a) .ut_time = (a) +-#endif + + { .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) }, + { .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) }, +@@ -167,11 +161,7 @@ simulate_login (const char *line, const char *user) + entry[n].ut_pid = (entry_pid += 27); + entry[n].ut_type = USER_PROCESS; + strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user)); +-#if defined UTMPX || _HAVE_UT_TV - 0 + entry[n].ut_tv.tv_sec = (entry_time += 1000); +-#else +- entry[n].ut_time = (entry_time += 1000); +-#endif + setutent (); + + if (pututline (&entry[n]) == NULL) +@@ -201,11 +191,7 @@ simulate_logout (const char *line) + { + entry[n].ut_type = DEAD_PROCESS; + strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user)); +-#if defined UTMPX || _HAVE_UT_TV - 0 + entry[n].ut_tv.tv_sec = (entry_time += 1000); +-#else +- entry[n].ut_time = (entry_time += 1000); +-#endif + setutent (); + + if (pututline (&entry[n]) == NULL) +@@ -390,14 +376,3 @@ do_test (int argc, char *argv[]) + + return result; + } +- +-#else +- +-/* No field 'ut_type' in struct utmp. */ +-int +-main (void) +-{ +- return 0; +-} +- +-#endif +diff --git a/login/updwtmp.c b/login/updwtmp.c +index b9bccd9b67..387e580828 100644 +--- a/login/updwtmp.c ++++ b/login/updwtmp.c +@@ -29,7 +29,7 @@ __updwtmp (const char *wtmp_file, const struct utmp *utmp) + { + const char *file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file); + +- (*__libc_utmp_file_functions.updwtmp) (file_name, utmp); ++ __libc_updwtmp (file_name, utmp); + } + libc_hidden_def (__updwtmp) + weak_alias (__updwtmp, updwtmp) +diff --git a/login/utmp-private.h b/login/utmp-private.h +index a82a923657..d60461d644 100644 +--- a/login/utmp-private.h ++++ b/login/utmp-private.h +@@ -24,24 +24,17 @@ + #include <utmp.h> + #include <libc-lock.h> + +-/* The structure describing the functions in a backend. */ +-struct utfuncs +-{ +- int (*setutent) (void); +- int (*getutent_r) (struct utmp *, struct utmp **); +- int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **); +- int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **); +- struct utmp *(*pututline) (const struct utmp *); +- void (*endutent) (void); +- int (*updwtmp) (const char *, const struct utmp *); +-}; +- +-/* The tables from the services. */ +-extern const struct utfuncs __libc_utmp_file_functions attribute_hidden; +-extern const struct utfuncs __libc_utmp_unknown_functions attribute_hidden; +- +-/* Currently selected backend. */ +-extern const struct utfuncs *__libc_utmp_jump_table attribute_hidden; ++/* These functions check for initialization, but not perform any ++ locking. */ ++int __libc_setutent (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; + + /* Current file name. */ + extern const char *__libc_utmp_file_name attribute_hidden; +diff --git a/login/utmp_file.c b/login/utmp_file.c +index b19d3caf0d..e98bc31899 100644 +--- a/login/utmp_file.c ++++ b/login/utmp_file.c +@@ -43,6 +43,25 @@ static off64_t file_offset; + /* Cache for the last read entry. */ + static struct utmp last_entry; + ++/* Returns true if *ENTRY matches last_entry, based on ++ data->ut_type. */ ++static bool ++matches_last_entry (const struct utmp *data) ++{ ++ 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 __utmp_equal (&last_entry, data); ++} + + /* Locking timeout. */ + #ifndef TIMEOUT +@@ -52,90 +71,70 @@ static struct utmp last_entry; + /* Do-nothing handler for locking timeout. */ + static void timeout_handler (int signum) {}; + +-/* LOCK_FILE(fd, type) failure_statement +- attempts to get a lock on the utmp file referenced by FD. If it fails, +- the failure_statement is executed, otherwise it is skipped. +- LOCKING_FAILED() +- jumps into the UNLOCK_FILE macro and ensures cleanup of LOCK_FILE. +- UNLOCK_FILE(fd) +- unlocks the utmp file referenced by FD and performs the cleanup of +- LOCK_FILE. +- */ +-#define LOCK_FILE(fd, type) \ +-{ \ +- struct flock fl; \ +- struct sigaction action, old_action; \ +- unsigned int old_timeout; \ +- \ +- /* Cancel any existing alarm. */ \ +- old_timeout = alarm (0); \ +- \ +- /* Establish signal handler. */ \ +- action.sa_handler = timeout_handler; \ +- __sigemptyset (&action.sa_mask); \ +- action.sa_flags = 0; \ +- __sigaction (SIGALRM, &action, &old_action); \ +- \ +- alarm (TIMEOUT); \ +- \ +- /* Try to get the lock. */ \ +- memset (&fl, '\0', sizeof (struct flock)); \ +- fl.l_type = (type); \ +- fl.l_whence = SEEK_SET; \ +- if (__fcntl64_nocancel ((fd), F_SETLKW, &fl) < 0) +- +-#define LOCKING_FAILED() \ +- goto unalarm_return +- +-#define UNLOCK_FILE(fd) \ +- /* Unlock the file. */ \ +- fl.l_type = F_UNLCK; \ +- __fcntl64_nocancel ((fd), F_SETLKW, &fl); \ +- \ +- unalarm_return: \ +- /* Reset the signal handler and alarm. We must reset the alarm \ +- before resetting the handler so our alarm does not generate a \ +- spurious SIGALRM seen by the user. However, we cannot just set \ +- the user's old alarm before restoring the handler, because then \ +- it's possible our handler could catch the user alarm's SIGARLM \ +- and then the user would never see the signal he expected. */ \ +- alarm (0); \ +- __sigaction (SIGALRM, &old_action, NULL); \ +- if (old_timeout != 0) \ +- alarm (old_timeout); \ +-} while (0) +- +- +-/* Functions defined here. */ +-static int setutent_file (void); +-static int getutent_r_file (struct utmp *buffer, struct utmp **result); +-static int getutid_r_file (const struct utmp *key, struct utmp *buffer, +- struct utmp **result); +-static int getutline_r_file (const struct utmp *key, struct utmp *buffer, +- struct utmp **result); +-static struct utmp *pututline_file (const struct utmp *data); +-static void endutent_file (void); +-static int updwtmp_file (const char *file, const struct utmp *utmp); +- +-/* Jump table for file functions. */ +-const struct utfuncs __libc_utmp_file_functions = ++ ++/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking ++ operation failed and recovery needs to be performed. ++ ++ file_unlock (FD) removes the lock (which must have been ++ successfully acquired). */ ++ ++static bool ++try_file_lock (int fd, int type) + { +- setutent_file, +- getutent_r_file, +- getutid_r_file, +- getutline_r_file, +- pututline_file, +- endutent_file, +- updwtmp_file +-}; ++ /* Cancel any existing alarm. */ ++ int old_timeout = alarm (0); ++ ++ /* Establish signal handler. */ ++ struct sigaction old_action; ++ struct sigaction action; ++ action.sa_handler = timeout_handler; ++ __sigemptyset (&action.sa_mask); ++ action.sa_flags = 0; ++ __sigaction (SIGALRM, &action, &old_action); ++ ++ alarm (TIMEOUT); ++ ++ /* Try to get the lock. */ ++ struct flock64 fl = ++ { ++ .l_type = type, ++ .l_whence = SEEK_SET, ++ }; ++ ++ bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0; ++ int saved_errno = errno; ++ ++ /* Reset the signal handler and alarm. We must reset the alarm ++ before resetting the handler so our alarm does not generate a ++ spurious SIGALRM seen by the user. However, we cannot just set ++ the user's old alarm before restoring the handler, because then ++ it's possible our handler could catch the user alarm's SIGARLM and ++ then the user would never see the signal he expected. */ ++ alarm (0); ++ __sigaction (SIGALRM, &old_action, NULL); ++ if (old_timeout != 0) ++ alarm (old_timeout); ++ ++ __set_errno (saved_errno); ++ return status; ++} + ++static void ++file_unlock (int fd) ++{ ++ struct flock64 fl = ++ { ++ .l_type = F_UNLCK, ++ }; ++ __fcntl64_nocancel (fd, F_SETLKW, &fl); ++} + + #ifndef TRANSFORM_UTMP_FILE_NAME + # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name) + #endif + +-static int +-setutent_file (void) ++int ++__libc_setutent (void) + { + if (file_fd < 0) + { +@@ -153,56 +152,68 @@ setutent_file (void) + __lseek64 (file_fd, 0, SEEK_SET); + file_offset = 0; + +- /* Make sure the entry won't match. */ +-#if _HAVE_UT_TYPE - 0 +- last_entry.ut_type = -1; +-#else +- last_entry.ut_line[0] = '\177'; +-# if _HAVE_UT_ID - 0 +- last_entry.ut_id[0] = '\0'; +-# endif +-#endif +- + return 1; + } + ++/* Preform initialization if necessary. */ ++static bool ++maybe_setutent (void) ++{ ++ return file_fd >= 0 || __libc_setutent (); ++} + +-static int +-getutent_r_file (struct utmp *buffer, struct utmp **result) ++/* Reads the entry at file_offset, storing it in last_entry and ++ updating file_offset on success. Returns -1 for a read error, 0 ++ 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) + { +- ssize_t nbytes; ++ struct utmp buffer; ++ ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer), ++ file_offset); ++ if (nbytes < 0) ++ return -1; ++ else if (nbytes != sizeof (buffer)) ++ /* Assume EOF. */ ++ return 0; ++ else ++ { ++ last_entry = buffer; ++ file_offset += sizeof (buffer); ++ return 1; ++ } ++} + +- assert (file_fd >= 0); ++int ++__libc_getutent_r (struct utmp *buffer, struct utmp **result) ++{ ++ int saved_errno = errno; + +- if (file_offset == -1l) ++ if (!maybe_setutent ()) + { + /* Not available. */ + *result = NULL; + return -1; + } + +- LOCK_FILE (file_fd, F_RDLCK) +- { +- nbytes = 0; +- LOCKING_FAILED (); +- } +- +- /* Read the next entry. */ +- nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp)); ++ if (try_file_lock (file_fd, F_RDLCK)) ++ return -1; + +- UNLOCK_FILE (file_fd); ++ ssize_t nbytes = read_last_entry (); ++ file_unlock (file_fd); + +- if (nbytes != sizeof (struct utmp)) ++ if (nbytes <= 0) /* Read error or EOF. */ + { +- if (nbytes != 0) +- file_offset = -1l; ++ if (nbytes == 0) ++ /* errno should be unchanged to indicate success. A premature ++ EOF is treated like an EOF (missing complete record at the ++ end). */ ++ __set_errno (saved_errno); + *result = NULL; + return -1; + } + +- /* Update position pointer. */ +- file_offset += sizeof (struct utmp); +- + memcpy (buffer, &last_entry, sizeof (struct utmp)); + *result = buffer; + +@@ -210,82 +221,55 @@ getutent_r_file (struct utmp *buffer, struct utmp **result) + } + + ++/* 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_r (const struct utmp *id, struct utmp *buffer, +- bool *lock_failed) ++internal_getut_nolock (const struct utmp *id) + { +- int result = -1; +- +- LOCK_FILE (file_fd, F_RDLCK) +- { +- *lock_failed = true; +- LOCKING_FAILED (); +- } +- +-#if _HAVE_UT_TYPE - 0 +- if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME +- || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME) ++ while (1) + { +- /* Search for next entry with type RUN_LVL, BOOT_TIME, +- OLD_TIME, or NEW_TIME. */ +- +- while (1) ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) ++ return -1; ++ if (nbytes == 0) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, buffer, sizeof (struct utmp)) +- != sizeof (struct utmp)) +- { +- __set_errno (ESRCH); +- file_offset = -1l; +- goto unlock_return; +- } +- file_offset += sizeof (struct utmp); +- +- if (id->ut_type == buffer->ut_type) +- break; ++ /* End of file reached. */ ++ __set_errno (ESRCH); ++ return -1; + } +- } +- else +-#endif /* _HAVE_UT_TYPE */ +- { +- /* Search for the next entry with the specified ID and with type +- INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */ + +- while (1) +- { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, buffer, sizeof (struct utmp)) +- != sizeof (struct utmp)) +- { +- __set_errno (ESRCH); +- file_offset = -1l; +- goto unlock_return; +- } +- file_offset += sizeof (struct utmp); +- +- if (__utmp_equal (buffer, id)) +- break; +- } ++ if (matches_last_entry (id)) ++ break; + } + +- result = 0; ++ return 0; ++} + +-unlock_return: +- UNLOCK_FILE (file_fd); ++/* 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) ++{ ++ if (try_file_lock (file_fd, F_RDLCK)) ++ { ++ *lock_failed = true; ++ return -1; ++ } + ++ int result = internal_getut_nolock (id); ++ file_unlock (file_fd); + return result; + } + +- + /* For implementing this function we don't use the getutent_r function + because we can avoid the reposition on every new entry this way. */ +-static int +-getutid_r_file (const struct utmp *id, struct utmp *buffer, +- struct utmp **result) ++int ++__libc_getutid_r (const struct utmp *id, struct utmp *buffer, ++ struct utmp **result) + { +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent ()) + { + *result = NULL; + return -1; +@@ -294,7 +278,7 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer, + /* 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, &last_entry, &lock_failed) < 0) ++ if (internal_getut_r (id, &lock_failed) < 0) + { + *result = NULL; + return -1; +@@ -306,69 +290,65 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer, + 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. */ +-static int +-getutline_r_file (const struct utmp *line, struct utmp *buffer, +- struct utmp **result) ++int ++__libc_getutline_r (const struct utmp *line, struct utmp *buffer, ++ struct utmp **result) + { +- assert (file_fd >= 0); +- +- if (file_offset == -1l) ++ if (!maybe_setutent ()) + { + *result = NULL; + return -1; + } + +- LOCK_FILE (file_fd, F_RDLCK) ++ if (try_file_lock (file_fd, F_RDLCK)) + { + *result = NULL; +- LOCKING_FAILED (); ++ return -1; + } + + while (1) + { +- /* Read the next entry. */ +- if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) ++ { ++ file_unlock (file_fd); ++ *result = NULL; ++ return -1; ++ } ++ if (nbytes == 0) + { ++ /* End of file reached. */ ++ file_unlock (file_fd); + __set_errno (ESRCH); +- file_offset = -1l; + *result = NULL; +- goto unlock_return; ++ return -1; + } +- file_offset += sizeof (struct utmp); + + /* Stop if we found a user or login entry. */ +- if ( +-#if _HAVE_UT_TYPE - 0 +- (last_entry.ut_type == USER_PROCESS ++ if ((last_entry.ut_type == USER_PROCESS + || last_entry.ut_type == LOGIN_PROCESS) +- && +-#endif +- !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)) ++ && (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line) ++ == 0)) + break; + } + ++ file_unlock (file_fd); + memcpy (buffer, &last_entry, sizeof (struct utmp)); + *result = buffer; + +-unlock_return: +- UNLOCK_FILE (file_fd); +- +- return ((*result == NULL) ? -1 : 0); ++ return 0; + } + + +-static struct utmp * +-pututline_file (const struct utmp *data) ++struct utmp * ++__libc_pututline (const struct utmp *data) + { +- struct utmp buffer; +- struct utmp *pbuf; +- int found; ++ if (!maybe_setutent ()) ++ return NULL; + +- assert (file_fd >= 0); ++ struct utmp *pbuf; + + if (! file_writable) + { +@@ -380,8 +360,7 @@ pututline_file (const struct utmp *data) + if (new_fd == -1) + return NULL; + +- if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1 +- || __dup2 (new_fd, file_fd) < 0) ++ if (__dup2 (new_fd, file_fd) < 0) + { + __close_nocancel_nostatus (new_fd); + return NULL; +@@ -390,95 +369,96 @@ pututline_file (const struct utmp *data) + file_writable = true; + } + ++ /* Exclude other writers before validating the cache. */ ++ if (try_file_lock (file_fd, F_WRLCK)) ++ return NULL; ++ + /* Find the correct place to insert the data. */ +- if (file_offset > 0 +- && ( +-#if _HAVE_UT_TYPE - 0 +- (last_entry.ut_type == data->ut_type +- && (last_entry.ut_type == RUN_LVL +- || last_entry.ut_type == BOOT_TIME +- || last_entry.ut_type == OLD_TIME +- || last_entry.ut_type == NEW_TIME)) +- || +-#endif +- __utmp_equal (&last_entry, data))) +- found = 1; +- else ++ bool found = false; ++ if (matches_last_entry (data)) + { +- bool lock_failed = false; +- found = internal_getut_r (data, &buffer, &lock_failed); +- +- if (__builtin_expect (lock_failed, false)) ++ /* Read back the entry under the write lock. */ ++ file_offset -= sizeof (last_entry); ++ ssize_t nbytes = read_last_entry (); ++ if (nbytes < 0) + { +- __set_errno (EAGAIN); ++ file_unlock (file_fd); + return NULL; + } +- } + +- LOCK_FILE (file_fd, F_WRLCK) +- { +- pbuf = NULL; +- LOCKING_FAILED (); ++ if (nbytes == 0) ++ /* End of file reached. */ ++ found = false; ++ else ++ found = matches_last_entry (data); + } + +- if (found < 0) ++ if (!found) ++ /* Search forward for the entry. */ ++ found = internal_getut_nolock (data) >= 0; ++ ++ off64_t write_offset; ++ if (!found) + { + /* We append the next entry. */ +- file_offset = __lseek64 (file_fd, 0, SEEK_END); +- if (file_offset % sizeof (struct utmp) != 0) +- { +- file_offset -= file_offset % sizeof (struct utmp); +- __ftruncate64 (file_fd, file_offset); +- +- if (__lseek64 (file_fd, 0, SEEK_END) < 0) +- { +- pbuf = NULL; +- goto unlock_return; +- } +- } ++ write_offset = __lseek64 (file_fd, 0, SEEK_END); ++ ++ /* 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)); + } + else ++ /* Overwrite last_entry. */ ++ write_offset = file_offset - sizeof (struct utmp); ++ ++ /* 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) + { +- /* We replace the just read entry. */ +- file_offset -= sizeof (struct utmp); +- __lseek64 (file_fd, file_offset, SEEK_SET); ++ /* 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; + } + +- /* Write the new data. */ +- if (__write_nocancel (file_fd, data, sizeof (struct utmp)) +- != sizeof (struct utmp)) ++ if (nbytes != sizeof (struct utmp)) + { + /* If we appended a new record this is only partially written. + Remove it. */ +- if (found < 0) +- (void) __ftruncate64 (file_fd, file_offset); +- pbuf = NULL; +- } +- else +- { +- file_offset += sizeof (struct utmp); +- pbuf = (struct utmp *) data; ++ if (!found) ++ (void) __ftruncate64 (file_fd, write_offset); ++ file_unlock (file_fd); ++ /* Assume that the write failure was due to missing disk ++ space. */ ++ __set_errno (ENOSPC); ++ return NULL; + } + +- unlock_return: +- UNLOCK_FILE (file_fd); ++ file_unlock (file_fd); ++ file_offset = write_offset + sizeof (struct utmp); ++ pbuf = (struct utmp *) data; + + return pbuf; + } + + +-static void +-endutent_file (void) ++void ++__libc_endutent (void) + { +- assert (file_fd >= 0); +- +- __close_nocancel_nostatus (file_fd); +- file_fd = -1; ++ if (file_fd >= 0) ++ { ++ __close_nocancel_nostatus (file_fd); ++ file_fd = -1; ++ } + } + + +-static int +-updwtmp_file (const char *file, const struct utmp *utmp) ++int ++__libc_updwtmp (const char *file, const struct utmp *utmp) + { + int result = -1; + off64_t offset; +@@ -489,8 +469,11 @@ updwtmp_file (const char *file, const struct utmp *utmp) + if (fd < 0) + return -1; + +- LOCK_FILE (fd, F_WRLCK) +- LOCKING_FAILED (); ++ if (try_file_lock (fd, F_WRLCK)) ++ { ++ __close_nocancel_nostatus (fd); ++ return -1; ++ } + + /* Remember original size of log file. */ + offset = __lseek64 (fd, 0, SEEK_END); +@@ -516,7 +499,7 @@ updwtmp_file (const char *file, const struct utmp *utmp) + result = 0; + + unlock_return: +- UNLOCK_FILE (fd); ++ file_unlock (fd); + + /* Close WTMP file. */ + __close_nocancel_nostatus (fd); +diff --git a/login/utmpname.c b/login/utmpname.c +index c3da183d5b..8f94b19caf 100644 +--- a/login/utmpname.c ++++ b/login/utmpname.c +@@ -42,8 +42,7 @@ __utmpname (const char *file) + __libc_lock_lock (__libc_utmp_lock); + + /* Close the old file. */ +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + + if (strcmp (file, __libc_utmp_file_name) != 0) + { diff --git a/malloc/Makefile b/malloc/Makefile -index d2fba29953..742c515eb2 100644 +index d2fba29953..9698574bba 100644 --- a/malloc/Makefile +++ b/malloc/Makefile +@@ -27,7 +27,7 @@ headers := $(dist-headers) obstack.h mcheck.h + tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-mcheck tst-mallocfork tst-trim1 \ + tst-malloc-usable tst-realloc tst-reallocarray tst-posix_memalign \ +- tst-pvalloc tst-memalign tst-mallopt \ ++ tst-pvalloc tst-pvalloc-fortify tst-memalign tst-mallopt \ + tst-malloc-backtrace tst-malloc-thread-exit \ + tst-malloc-thread-fail tst-malloc-fork-deadlock \ + tst-mallocfork2 \ @@ -54,7 +54,7 @@ tests-internal += \ tst-dynarray-at-fail \ @@ -370,6 +2370,20 @@ index 00ce48cf58..8c68b21b2b 100644 <size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n", sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count); +diff --git a/malloc/malloc.h b/malloc/malloc.h +index 70d8282bdc..f62c6c594c 100644 +--- a/malloc/malloc.h ++++ b/malloc/malloc.h +@@ -71,8 +71,7 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__ + + /* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up + __size to nearest pagesize. */ +-extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ +- __attribute_alloc_size__ ((1)) __wur; ++extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur; + + /* Underlying allocation function; successive calls should return + contiguous pieces of memory. */ diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c new file mode 100644 index 0000000000..7a7750bc71 @@ -426,6 +2440,60 @@ index 0000000000..7a7750bc71 +} + +#include <support/test-driver.c> +diff --git a/malloc/tst-pvalloc-fortify.c b/malloc/tst-pvalloc-fortify.c +new file mode 100644 +index 0000000000..391b7fa2f5 +--- /dev/null ++++ b/malloc/tst-pvalloc-fortify.c +@@ -0,0 +1,48 @@ ++/* Test fortify-source allocation size handling in pvalloc (bug 25401). ++ 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; see the file COPYING.LIB. If ++ not, see <https://www.gnu.org/licenses/>. */ ++ ++#undef _FORTIFY_SOURCE ++#define _FORTIFY_SOURCE 2 ++#include <malloc.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <unistd.h> ++ ++static int ++do_test (void) ++{ ++ /* The test below assumes that pvalloc rounds up the allocation size ++ to at least 8. */ ++ TEST_VERIFY (xsysconf (_SC_PAGESIZE) >= 8); ++ ++ void *p = pvalloc (5); ++ TEST_VERIFY_EXIT (p != NULL); ++ ++ /* This is valid assuming the page size is at least 8 because ++ pvalloc rounds up the allocation size to a multiple of the page ++ size. Due to bug 25041, this used to trigger a compiler ++ warning. */ ++ strcpy (p, "abcdefg"); ++ ++ asm ("" : : "g" (p) : "memory"); /* Optimization barrier. */ ++ TEST_VERIFY (malloc_usable_size (p) >= xsysconf (_SC_PAGESIZE)); ++ return 0; ++} ++ ++#include <support/test-driver.c> diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h index f1bd994a10..b1695376dc 100644 --- a/misc/sys/cdefs.h @@ -549,6 +2617,217 @@ index 0f77dd2ed0..89c4527a81 100644 ildouble: 6 ldouble: 6 +diff --git a/sysdeps/generic/not-cancel.h b/sysdeps/generic/not-cancel.h +index f3d862651e..724c3e5e71 100644 +--- a/sysdeps/generic/not-cancel.h ++++ b/sysdeps/generic/not-cancel.h +@@ -41,6 +41,8 @@ + (void) __close (fd) + #define __read_nocancel(fd, buf, n) \ + __read (fd, buf, n) ++#define __pread64_nocancel(fd, buf, count, offset) \ ++ __pread64 (fd, buf, count, offset) + #define __write_nocancel(fd, buf, n) \ + __write (fd, buf, n) + #define __writev_nocancel_nostatus(fd, iov, n) \ +diff --git a/sysdeps/generic/utmp-equal.h b/sysdeps/generic/utmp-equal.h +index d077147a7a..d61cbb3300 100644 +--- a/sysdeps/generic/utmp-equal.h ++++ b/sysdeps/generic/utmp-equal.h +@@ -27,26 +27,16 @@ + static int + __utmp_equal (const struct utmp *entry, const struct utmp *match) + { +- return +- ( +-#if _HAVE_UT_TYPE - 0 +- (entry->ut_type == INIT_PROCESS +- || entry->ut_type == LOGIN_PROCESS +- || entry->ut_type == USER_PROCESS +- || entry->ut_type == DEAD_PROCESS) +- && +- (match->ut_type == INIT_PROCESS +- || match->ut_type == LOGIN_PROCESS +- || match->ut_type == USER_PROCESS +- || match->ut_type == DEAD_PROCESS) +- && +-#endif +-#if _HAVE_UT_ID - 0 +- (entry->ut_id[0] && match->ut_id[0] +- ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 +- : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0) +-#else +- strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0 +-#endif +- ); ++ return (entry->ut_type == INIT_PROCESS ++ || entry->ut_type == LOGIN_PROCESS ++ || entry->ut_type == USER_PROCESS ++ || entry->ut_type == DEAD_PROCESS) ++ && (match->ut_type == INIT_PROCESS ++ || match->ut_type == LOGIN_PROCESS ++ || match->ut_type == USER_PROCESS ++ || match->ut_type == DEAD_PROCESS) ++ && (entry->ut_id[0] && match->ut_id[0] ++ ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0 ++ : (strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) ++ == 0)); + } +diff --git a/sysdeps/gnu/bits/utmp.h b/sysdeps/gnu/bits/utmp.h +deleted file mode 100644 +index 7357034cb6..0000000000 +--- a/sysdeps/gnu/bits/utmp.h ++++ /dev/null +@@ -1,126 +0,0 @@ +-/* The `struct utmp' type, describing entries in the utmp file. GNU version. +- Copyright (C) 1993-2019 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 +- <http://www.gnu.org/licenses/>. */ +- +-#ifndef _UTMP_H +-# error "Never include <bits/utmp.h> directly; use <utmp.h> instead." +-#endif +- +-#include <paths.h> +-#include <sys/time.h> +-#include <sys/types.h> +-#include <bits/wordsize.h> +- +- +-#define UT_LINESIZE 32 +-#define UT_NAMESIZE 32 +-#define UT_HOSTSIZE 256 +- +- +-/* The structure describing an entry in the database of +- previous logins. */ +-struct lastlog +- { +-#if __WORDSIZE_TIME64_COMPAT32 +- int32_t ll_time; +-#else +- __time_t ll_time; +-#endif +- char ll_line[UT_LINESIZE]; +- char ll_host[UT_HOSTSIZE]; +- }; +- +- +-/* The structure describing the status of a terminated process. This +- type is used in `struct utmp' below. */ +-struct exit_status +- { +- short int e_termination; /* Process termination status. */ +- short int e_exit; /* Process exit status. */ +- }; +- +- +-/* The structure describing an entry in the user accounting database. */ +-struct utmp +-{ +- short int ut_type; /* Type of login. */ +- pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[UT_LINESIZE] +- __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[UT_NAMESIZE] +- __attribute_nonstring__; /* Username. */ +- char ut_host[UT_HOSTSIZE] +- __attribute_nonstring__; /* Hostname for remote login. */ +- struct exit_status ut_exit; /* Exit status of a process marked +- as DEAD_PROCESS. */ +-/* 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. */ +- struct +- { +- int32_t tv_sec; /* Seconds. */ +- int32_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. */ +-}; +- +-/* Backwards compatibility hacks. */ +-#define ut_name ut_user +-#ifndef _NO_UT_TIME +-/* We have a problem here: `ut_time' is also used otherwise. Define +- _NO_UT_TIME if the compiler complains. */ +-# define ut_time ut_tv.tv_sec +-#endif +-#define ut_xtime ut_tv.tv_sec +-#define ut_addr ut_addr_v6[0] +- +- +-/* Values for the `ut_type' field of a `struct utmp'. */ +-#define EMPTY 0 /* No valid user accounting information. */ +- +-#define RUN_LVL 1 /* The system's runlevel. */ +-#define BOOT_TIME 2 /* Time of system boot. */ +-#define NEW_TIME 3 /* Time after system clock changed. */ +-#define OLD_TIME 4 /* Time when system clock changed. */ +- +-#define INIT_PROCESS 5 /* Process spawned by the init process. */ +-#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */ +-#define USER_PROCESS 7 /* Normal process. */ +-#define DEAD_PROCESS 8 /* Terminated process. */ +- +-#define ACCOUNTING 9 +- +-/* Old Linux name for the EMPTY type. */ +-#define UT_UNKNOWN EMPTY +- +- +-/* Tell the user that we have a modern system with UT_HOST, UT_PID, +- UT_TYPE, UT_ID and UT_TV fields. */ +-#define _HAVE_UT_TYPE 1 +-#define _HAVE_UT_PID 1 +-#define _HAVE_UT_ID 1 +-#define _HAVE_UT_TV 1 +-#define _HAVE_UT_HOST 1 +diff --git a/sysdeps/gnu/bits/utmpx.h b/sysdeps/gnu/bits/utmpx.h +index 472a7d57d3..2beadbf587 100644 +--- a/sysdeps/gnu/bits/utmpx.h ++++ b/sysdeps/gnu/bits/utmpx.h +@@ -56,10 +56,14 @@ struct utmpx + { + short int ut_type; /* Type of login. */ + __pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[__UT_LINESIZE]; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[__UT_NAMESIZE]; /* Username. */ +- char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */ ++ char ut_line[__UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[__UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[__UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + diff --git a/sysdeps/hppa/fpu/libm-test-ulps b/sysdeps/hppa/fpu/libm-test-ulps index d0c4dea001..2c61a7ae91 100644 --- a/sysdeps/hppa/fpu/libm-test-ulps @@ -921,6 +3200,58 @@ index 4d291181bd..0000000000 -PSEUDO_END (__getppid) - -weak_alias (__getppid, getppid) +diff --git a/sysdeps/unix/getlogin_r.c b/sysdeps/unix/getlogin_r.c +index 6c564d3b59..88971a9931 100644 +--- a/sysdeps/unix/getlogin_r.c ++++ b/sysdeps/unix/getlogin_r.c +@@ -64,8 +64,8 @@ __getlogin_r (char *name, size_t name_len) + held so that our search is thread-safe. */ + + __libc_lock_lock (__libc_utmp_lock); +- (*__libc_utmp_jump_table->setutent) (); +- result = (*__libc_utmp_jump_table->getutline_r) (&line, &buffer, &ut); ++ __libc_setutent (); ++ result = __libc_getutline_r (&line, &buffer, &ut); + if (result < 0) + { + if (errno == ESRCH) +@@ -74,8 +74,7 @@ __getlogin_r (char *name, size_t name_len) + else + result = errno; + } +- (*__libc_utmp_jump_table->endutent) (); +- __libc_utmp_jump_table = &__libc_utmp_unknown_functions; ++ __libc_endutent (); + __libc_lock_unlock (__libc_utmp_lock); + + if (result == 0) +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index 1ab6bcbfc8..a7980a60f6 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -212,8 +212,8 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \ + close_nocancel fcntl_nocancel nanosleep_nocancel \ + open_nocancel open64_nocancel \ + openat_nocancel openat64_nocancel \ +- pause_nocancel read_nocancel waitpid_nocancel \ +- write_nocancel statx_cp ++ pause_nocancel read_nocancel pread64_nocancel \ ++ waitpid_nocancel write_nocancel statx_cp + + sysdep_headers += bits/fcntl-linux.h + +diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions +index 1ca102a9e2..d385085c61 100644 +--- a/sysdeps/unix/sysv/linux/Versions ++++ b/sysdeps/unix/sysv/linux/Versions +@@ -182,6 +182,7 @@ libc { + __syscall_rt_sigqueueinfo; + __open_nocancel; + __read_nocancel; ++ __pread64_nocancel; + __close_nocancel; + __sigtimedwait; + # functions used by nscd diff --git a/sysdeps/unix/sysv/linux/alpha/getegid.S b/sysdeps/unix/sysv/linux/alpha/getegid.S new file mode 100644 index 0000000000..167009d17a @@ -1164,6 +3495,66 @@ index 9147aa4582..3db1b32b08 100644 + +LIBC_CONFIG_VAR([mips-force-execstack],[${libc_cv_mips_force_execstack}]) +LIBC_CONFIG_VAR([mips-has-gnustack],[${libc_mips_has_gnustack}]) +diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h +index 16cc31cba5..bf7d80125a 100644 +--- a/sysdeps/unix/sysv/linux/not-cancel.h ++++ b/sysdeps/unix/sysv/linux/not-cancel.h +@@ -43,6 +43,9 @@ __typeof (openat64) __openat64_nocancel; + /* Non cancellable read syscall. */ + __typeof (__read) __read_nocancel; + ++/* Non cancellable pread syscall (LFS version). */ ++__typeof (__pread64) __pread64_nocancel; ++ + /* Uncancelable write. */ + __typeof (__write) __write_nocancel; + +@@ -84,6 +87,7 @@ hidden_proto (__open64_nocancel) + hidden_proto (__openat_nocancel) + hidden_proto (__openat64_nocancel) + hidden_proto (__read_nocancel) ++hidden_proto (__pread64_nocancel) + hidden_proto (__write_nocancel) + hidden_proto (__close_nocancel) + hidden_proto (__waitpid_nocancel) +diff --git a/sysdeps/unix/sysv/linux/pread64_nocancel.c b/sysdeps/unix/sysv/linux/pread64_nocancel.c +new file mode 100644 +index 0000000000..dab61260e5 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/pread64_nocancel.c +@@ -0,0 +1,32 @@ ++/* Linux pread64() syscall implementation -- non-cancellable. ++ Copyright (C) 2019 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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <unistd.h> ++#include <sysdep-cancel.h> ++#include <not-cancel.h> ++ ++#ifndef __NR_pread64 ++# define __NR_pread64 __NR_pread ++#endif ++ ++ssize_t ++__pread64_nocancel (int fd, void *buf, size_t count, off64_t offset) ++{ ++ return INLINE_SYSCALL_CALL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset)); ++} ++hidden_def (__pread64_nocancel) diff --git a/sysdeps/unix/sysv/linux/riscv/vfork.S b/sysdeps/unix/sysv/linux/riscv/vfork.S index 67373f181b..dc173d6b47 100644 --- a/sysdeps/unix/sysv/linux/riscv/vfork.S @@ -1182,6 +3573,43 @@ index 67373f181b..dc173d6b47 100644 .text LEAF (__libc_vfork) +diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmp.h b/sysdeps/unix/sysv/linux/s390/bits/utmp.h +index 862115c6f8..0569c3b784 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/utmp.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/utmp.h +@@ -61,7 +61,8 @@ struct utmp + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINESIZE] + __attribute_nonstring__; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ + char ut_user[UT_NAMESIZE] + __attribute_nonstring__; /* Username. */ + char ut_host[UT_HOSTSIZE] +diff --git a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h +index ea3e860a2d..737d9dca05 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/utmpx.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/utmpx.h +@@ -56,10 +56,14 @@ struct utmpx + { + short int ut_type; /* Type of login. */ + __pid_t ut_pid; /* Process ID of login process. */ +- char ut_line[__UT_LINESIZE]; /* Devicename. */ +- char ut_id[4]; /* Inittab ID. */ +- char ut_user[__UT_NAMESIZE]; /* Username. */ +- char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */ ++ char ut_line[__UT_LINESIZE] ++ __attribute_nonstring__; /* Devicename. */ ++ char ut_id[4] ++ __attribute_nonstring__; /* Inittab ID. */ ++ char ut_user[__UT_NAMESIZE] ++ __attribute_nonstring__; /* Username. */ ++ char ut_host[__UT_HOSTSIZE] ++ __attribute_nonstring__; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + diff --git a/sysdeps/unix/sysv/linux/test-errno-linux.c b/sysdeps/unix/sysv/linux/test-errno-linux.c index cb979d44bd..aaa9eadc0a 100644 --- a/sysdeps/unix/sysv/linux/test-errno-linux.c |