From 0e58c95000114f246db1e44507f0b1dd17d22a1a Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 3 Aug 2023 18:35:29 -0700 Subject: [PATCH] maint: Update after gnulib module 'readutmp' changed MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit (This patch is coauthored with Bruno Haible, with original version at .) This updates the gnulib submodule to latest. For year-2038 safety on Linux/{x86,arm}, this adds an --enable-systemd option to ‘configure’. The idea is that this sort of thing will become the default after it has been tested more. * configure.ac: Don't test whether struct utmp and struct utmpx have the ut_host field; this is now done in gnulib's readutmp module. * src/local.mk: Link the programs 'pinky', 'uptime', 'users', 'who' with $(READUTMP_LIB). * src/pinky.c, src/who.c: Test HAVE_STRUCT_XTMP_UT_HOST instead of HAVE_UT_HOST. * src/pinky.c (print_entry): * src/who.c (print_user, print_deadprocs, print_login) (print_initspawn, scan_entries): Support the situation where ut_line is a 'char *' rather than a 'char[]' of fixed size. Likewise for ut_user and ut_host. (make_id_equals_comment): Likewise for ut_id. * src/pinky.c (print_entry): * src/who.c (print_user): Open /dev to simplify looking up its entries. Don’t use printf if the output might in theory be longer than INT_MAX. * src/pinky.c (scan_entries, short_pinky): * src/uptime.c (print_uptime, uptime): * src/users.c (list_entries_users, users): * src/who.c (who): Use idx_t where new read_utmp needs it. * src/system.h (STREQ_LEN): Add comment that last arg can be -1. --- NEWS | 4 ++ configure.ac | 30 ------------ gnulib | 2 +- src/local.mk | 6 +++ src/pinky.c | 95 +++++++++++++++++++++++++------------- src/system.h | 2 +- src/uptime.c | 4 +- src/users.c | 10 ++-- src/who.c | 127 ++++++++++++++++++++++++++++++--------------------- 9 files changed, 159 insertions(+), 121 deletions(-) diff --git a/NEWS b/NEWS index 2b8f984ba8..53a342a5ed 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,10 @@ GNU coreutils NEWS -*- outline -*- pinky, uptime, users, and who no longer misbehave on 32-bit GNU/Linux platforms like x86 and ARM where time_t was historically 32 bits. + A new configure-time option --enable-systemd enables experimental + support for using systemd, to let these programs continue to work on + these old platforms even after the year 2038, so long as systemd + is also installed. [bug introduced in coreutils-9.0] 'pr --length=1 --double-space' no longer enters an infinite loop. diff --git a/configure.ac b/configure.ac index 33441a82ff..afc1098f76 100644 --- a/configure.ac +++ b/configure.ac @@ -406,36 +406,6 @@ AC_DEFUN([coreutils_DUMMY_1], ]) coreutils_DUMMY_1 -AC_MSG_CHECKING([ut_host in struct utmp]) -AC_CACHE_VAL([su_cv_func_ut_host_in_utmp], -[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include - #include - struct utmp ut; - int s = sizeof ut.ut_host;]])], - [su_cv_func_ut_host_in_utmp=yes], - [su_cv_func_ut_host_in_utmp=no])]) -AC_MSG_RESULT([$su_cv_func_ut_host_in_utmp]) -if test $su_cv_func_ut_host_in_utmp = yes; then - have_ut_host=1 - AC_DEFINE([HAVE_UT_HOST], [1], [FIXME]) -fi - -if test -z "$have_ut_host"; then - AC_MSG_CHECKING([ut_host in struct utmpx]) - AC_CACHE_VAL([su_cv_func_ut_host_in_utmpx], - [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include - #include - struct utmpx ut; - int s = sizeof ut.ut_host;]])], - [su_cv_func_ut_host_in_utmpx=yes], - [su_cv_func_ut_host_in_utmpx=no])]) - AC_MSG_RESULT([$su_cv_func_ut_host_in_utmpx]) - if test $su_cv_func_ut_host_in_utmpx = yes; then - AC_DEFINE([HAVE_UTMPX_H], [1], [FIXME]) - AC_DEFINE([HAVE_UT_HOST], [1], [FIXME]) - fi -fi - GNULIB_BOOT_TIME([gl_ADD_PROG([optional_bin_progs], [uptime])]) AC_SYS_POSIX_TERMIOS() diff --git a/gnulib b/gnulib index 0e7af0cff0..f6aa86ea62 160000 --- a/gnulib +++ b/gnulib @@ -1 +1 @@ -Subproject commit 0e7af0cff0011f25f5f842af5216325923017b34 +Subproject commit f6aa86ea62cd60141e918142bf3ba9fda8ee2463 diff --git a/src/local.mk b/src/local.mk index cb9b392743..4d7df27894 100644 --- a/src/local.mk +++ b/src/local.mk @@ -317,6 +317,12 @@ src_who_LDADD += $(GETADDRINFO_LIB) src_hostname_LDADD += $(GETHOSTNAME_LIB) src_uname_LDADD += $(GETHOSTNAME_LIB) +# for read_utmp +src_pinky_LDADD += $(READUTMP_LIB) +src_uptime_LDADD += $(READUTMP_LIB) +src_users_LDADD += $(READUTMP_LIB) +src_who_LDADD += $(READUTMP_LIB) + # for strsignal src_kill_LDADD += $(LIBTHREAD) diff --git a/src/pinky.c b/src/pinky.c index b6d411c858..38ceccbea6 100644 --- a/src/pinky.c +++ b/src/pinky.c @@ -62,7 +62,7 @@ static bool include_home_and_shell = true; static bool do_short_format = true; /* if true, display the ut_host field. */ -#ifdef HAVE_UT_HOST +#if HAVE_STRUCT_XTMP_UT_HOST static bool include_where = true; #endif @@ -203,20 +203,32 @@ print_entry (const STRUCT_UTMP *utmp_ent) time_t last_change; char mesg; -#define DEV_DIR_WITH_TRAILING_SLASH "/dev/" -#define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1) - - char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1]; - char *p = line; +#ifdef UT_LINE_SIZE + char line[UT_LINE_SIZE + 1]; + stzncpy (line, utmp_ent->ut_line, UT_LINE_SIZE); +#else + /* If ut_line contains a space, the device name starts after the space. */ + char *line = utmp_ent->ut_line; + char *space = strchr (line, ' '); + line = space ? space + 1 : line; +#endif - /* Copy ut_line into LINE, prepending '/dev/' if ut_line is not - already an absolute file name. Some system may put the full, - absolute file name in ut_line. */ - if ( ! IS_ABSOLUTE_FILE_NAME (utmp_ent->ut_line)) - p = stpcpy (p, DEV_DIR_WITH_TRAILING_SLASH); - stzncpy (p, utmp_ent->ut_line, sizeof (utmp_ent->ut_line)); + int dirfd; + if (IS_ABSOLUTE_FILE_NAME (line)) + dirfd = AT_FDCWD; + else + { + static int dev_dirfd; + if (!dev_dirfd) + { + dev_dirfd = open ("/dev", O_PATHSEARCH | O_DIRECTORY); + if (dev_dirfd < 0) + dev_dirfd = AT_FDCWD - 1; + } + dirfd = dev_dirfd; + } - if (stat (line, &stats) == 0) + if (AT_FDCWD <= dirfd && fstatat (dirfd, line, &stats, 0) == 0) { mesg = (stats.st_mode & S_IWGRP) ? ' ' : '*'; last_change = stats.st_atime; @@ -227,15 +239,20 @@ print_entry (const STRUCT_UTMP *utmp_ent) last_change = 0; } - printf ("%-8.*s", UT_USER_SIZE, UT_USER (utmp_ent)); + if (0 <= UT_USER_SIZE || strnlen (UT_USER (utmp_ent), 8) < 8) + printf ("%-8.*s", UT_USER_SIZE, UT_USER (utmp_ent)); + else + fputs (UT_USER (utmp_ent), stdout); if (include_fullname) { - struct passwd *pw; +#ifdef UT_USER_SIZE char name[UT_USER_SIZE + 1]; - stzncpy (name, UT_USER (utmp_ent), UT_USER_SIZE); - pw = getpwnam (name); +#else + char *name = UT_USER (utmp_ent); +#endif + struct passwd *pw = getpwnam (name); if (pw == nullptr) /* TRANSLATORS: Real name is unknown; at most 19 characters. */ printf (" %19s", _(" ???")); @@ -253,8 +270,12 @@ print_entry (const STRUCT_UTMP *utmp_ent) } } - printf (" %c%-8.*s", - mesg, (int) sizeof (utmp_ent->ut_line), utmp_ent->ut_line); + fputc (' ', stdout); + fputc (mesg, stdout); + if (0 <= UT_LINE_SIZE || strnlen (utmp_ent->ut_line, 8) < 8) + printf ("%-8.*s", UT_LINE_SIZE, utmp_ent->ut_line); + else + fputs (utmp_ent->ut_line, stdout); if (include_idle) { @@ -267,15 +288,18 @@ print_entry (const STRUCT_UTMP *utmp_ent) printf (" %s", time_string (utmp_ent)); -#ifdef HAVE_UT_HOST +#ifdef HAVE_STRUCT_XTMP_UT_HOST if (include_where && utmp_ent->ut_host[0]) { - char ut_host[sizeof (utmp_ent->ut_host) + 1]; char *host = nullptr; char *display = nullptr; - /* Copy the host name into UT_HOST, and ensure it's nul terminated. */ - stzncpy (ut_host, utmp_ent->ut_host, sizeof (utmp_ent->ut_host)); +# ifdef UT_HOST_SIZE + char ut_host[UT_HOST_SIZE + 1]; + stzncpy (ut_host, utmp_ent->ut_host, UT_HOST_SIZE); +# else + char *ut_host = utmp_ent->ut_host; +# endif /* Look for an X display. */ display = strchr (ut_host, ':'); @@ -288,10 +312,13 @@ print_entry (const STRUCT_UTMP *utmp_ent) if ( ! host) host = ut_host; + fputc (' ', stdout); + fputs (host, stdout); if (display) - printf (" %s:%s", host, display); - else - printf (" %s", host); + { + fputc (':', stdout); + fputs (display, stdout); + } if (host != ut_host) free (host); @@ -408,17 +435,23 @@ print_heading (void) if (include_idle) printf (" %-6s", _("Idle")); printf (" %-*s", time_format_width, _("When")); -#ifdef HAVE_UT_HOST +#ifdef HAVE_STRUCT_XTMP_UT_HOST if (include_where) printf (" %s", _("Where")); #endif putchar ('\n'); } +/* Work around , + triggered by STREQ_LEN with a negative length. */ +#if 11 <= __GNUC__ +# pragma GCC diagnostic ignored "-Wstringop-overread" +#endif + /* Display UTMP_BUF, which should have N entries. */ static void -scan_entries (size_t n, const STRUCT_UTMP *utmp_buf, +scan_entries (idx_t n, const STRUCT_UTMP *utmp_buf, const int argc_names, char *const argv_names[]) { if (hard_locale (LC_TIME)) @@ -461,7 +494,7 @@ static void short_pinky (char const *filename, const int argc_names, char *const argv_names[]) { - size_t n_users; + idx_t n_users; STRUCT_UTMP *utmp_buf = nullptr; if (read_utmp (filename, &n_users, &utmp_buf, 0) != 0) @@ -550,14 +583,14 @@ main (int argc, char **argv) case 'i': include_fullname = false; -#ifdef HAVE_UT_HOST +#ifdef HAVE_STRUCT_XTMP_UT_HOST include_where = false; #endif break; case 'q': include_fullname = false; -#ifdef HAVE_UT_HOST +#ifdef HAVE_STRUCT_XTMP_UT_HOST include_where = false; #endif include_idle = false; diff --git a/src/system.h b/src/system.h index b5ec074e7c..7b736604b0 100644 --- a/src/system.h +++ b/src/system.h @@ -192,7 +192,7 @@ select_plural (uintmax_t n) } #define STREQ(a, b) (strcmp (a, b) == 0) -#define STREQ_LEN(a, b, n) (strncmp (a, b, n) == 0) +#define STREQ_LEN(a, b, n) (strncmp (a, b, n) == 0) /* n==-1 means unbounded */ #define STRPREFIX(a, b) (strncmp (a, b, strlen (b)) == 0) /* Just like strncmp, but the second argument must be a literal string diff --git a/src/uptime.c b/src/uptime.c index bdbf1451a1..ad1bbb9a19 100644 --- a/src/uptime.c +++ b/src/uptime.c @@ -45,7 +45,7 @@ proper_name ("Kaveh Ghazi") static void -print_uptime (size_t n, const STRUCT_UTMP *this) +print_uptime (idx_t n, const STRUCT_UTMP *this) { idx_t entries = 0; time_t boot_time = 0; @@ -169,7 +169,7 @@ print_uptime (size_t n, const STRUCT_UTMP *this) static _Noreturn void uptime (char const *filename, int options) { - size_t n_users; + idx_t n_users; STRUCT_UTMP *utmp_buf = nullptr; if (read_utmp (filename, &n_users, &utmp_buf, options) != 0) diff --git a/src/users.c b/src/users.c index e14f3fc3e7..353c1765de 100644 --- a/src/users.c +++ b/src/users.c @@ -42,11 +42,11 @@ userid_compare (const void *v_a, const void *v_b) } static void -list_entries_users (size_t n, const STRUCT_UTMP *this) +list_entries_users (idx_t n, const STRUCT_UTMP *this) { - char **u = xnmalloc (n, sizeof *u); - size_t i; - size_t n_entries = 0; + char **u = xinmalloc (n, sizeof *u); + idx_t i; + idx_t n_entries = 0; while (n--) { @@ -82,7 +82,7 @@ list_entries_users (size_t n, const STRUCT_UTMP *this) static void users (char const *filename, int options) { - size_t n_users; + idx_t n_users; STRUCT_UTMP *utmp_buf; if (read_utmp (filename, &n_users, &utmp_buf, options) != 0) diff --git a/src/who.c b/src/who.c index ec0dff7923..0e94d3c835 100644 --- a/src/who.c +++ b/src/who.c @@ -333,26 +333,38 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) time_t last_change; char mesg; char idlestr[IDLESTR_LEN + 1]; + PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); static char *hoststr; -#if HAVE_UT_HOST - static size_t hostlen; +#if HAVE_STRUCT_XTMP_UT_HOST + static idx_t hostlen; #endif -#define DEV_DIR_WITH_TRAILING_SLASH "/dev/" -#define DEV_DIR_LEN (sizeof (DEV_DIR_WITH_TRAILING_SLASH) - 1) - - char line[sizeof (utmp_ent->ut_line) + DEV_DIR_LEN + 1]; - char *p = line; - PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); +#ifdef UT_LINE_SIZE + char line[UT_LINE_SIZE + 1]; + stzncpy (line, utmp_ent->ut_line, UT_LINE_SIZE); +#else + /* If ut_line contains a space, the device name starts after the space. */ + char *line = utmp_ent->ut_line; + char *space = strchr (line, ' '); + line = space ? space + 1 : line; +#endif - /* Copy ut_line into LINE, prepending '/dev/' if ut_line is not - already an absolute file name. Some systems may put the full, - absolute file name in ut_line. */ - if ( ! IS_ABSOLUTE_FILE_NAME (utmp_ent->ut_line)) - p = stpcpy (p, DEV_DIR_WITH_TRAILING_SLASH); - stzncpy (p, utmp_ent->ut_line, sizeof (utmp_ent->ut_line)); + int dirfd; + if (IS_ABSOLUTE_FILE_NAME (line)) + dirfd = AT_FDCWD; + else + { + static int dev_dirfd; + if (!dev_dirfd) + { + dev_dirfd = open ("/dev", O_PATHSEARCH | O_DIRECTORY); + if (dev_dirfd < 0) + dev_dirfd = AT_FDCWD - 1; + } + dirfd = dev_dirfd; + } - if (stat (line, &stats) == 0) + if (AT_FDCWD <= dirfd && fstatat (dirfd, line, &stats, 0) == 0) { mesg = is_tty_writable (&stats) ? '+' : '-'; last_change = stats.st_atime; @@ -368,15 +380,18 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) else sprintf (idlestr, " ?"); -#if HAVE_UT_HOST +#if HAVE_STRUCT_XTMP_UT_HOST if (utmp_ent->ut_host[0]) { - char ut_host[sizeof (utmp_ent->ut_host) + 1]; char *host = nullptr; char *display = nullptr; - /* Copy the host name into UT_HOST, and ensure it's nul terminated. */ - stzncpy (ut_host, utmp_ent->ut_host, sizeof (utmp_ent->ut_host)); +# ifdef UT_HOST_SIZE + char ut_host[UT_HOST_SIZE + 1]; + stzncpy (ut_host, utmp_ent->ut_host, UT_HOST_SIZE); +# else + char *ut_host = utmp_ent->ut_host; +# endif /* Look for an X display. */ display = strchr (ut_host, ':'); @@ -394,23 +409,29 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) if (display) { - if (hostlen < strlen (host) + strlen (display) + 4) + idx_t needed = strlen (host) + strlen (display) + 4; + if (hostlen < needed) { - hostlen = strlen (host) + strlen (display) + 4; free (hoststr); - hoststr = xmalloc (hostlen); + hoststr = xpalloc (nullptr, &hostlen, needed - hostlen, -1, 1); } - sprintf (hoststr, "(%s:%s)", host, display); + char *p = hoststr; + *p++ = '('; + p = stpcpy (p, host); + *p++ = ':'; + strcpy (stpcpy (p, display), ")"); } else { - if (hostlen < strlen (host) + 3) + idx_t needed = strlen (host) + 3; + if (hostlen < needed) { - hostlen = strlen (host) + 3; free (hoststr); - hoststr = xmalloc (hostlen); + hoststr = xpalloc (nullptr, &hostlen, needed - hostlen, -1, 1); } - sprintf (hoststr, "(%s)", host); + char *p = hoststr; + *p++ = '('; + strcpy (stpcpy (p, host), ")"); } if (host != ut_host) @@ -419,17 +440,13 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) else { if (hostlen < 1) - { - hostlen = 1; - free (hoststr); - hoststr = xmalloc (hostlen); - } + hoststr = xpalloc (hoststr, &hostlen, 1, -1, 1); *hoststr = '\0'; } #endif - print_line (sizeof UT_USER (utmp_ent), UT_USER (utmp_ent), mesg, - sizeof utmp_ent->ut_line, utmp_ent->ut_line, + print_line (UT_USER_SIZE, UT_USER (utmp_ent), mesg, + UT_LINE_SIZE, utmp_ent->ut_line, time_string (utmp_ent), idlestr, pidstr, hoststr ? hoststr : "", ""); } @@ -444,11 +461,14 @@ print_boottime (const STRUCT_UTMP *utmp_ent) static char * make_id_equals_comment (STRUCT_UTMP const *utmp_ent) { - size_t utmpsize = sizeof UT_ID (utmp_ent); - char *comment = xmalloc (strlen (_("id=")) + utmpsize + 1); - - char *p = stpcpy (comment, _("id=")); - stzncpy (p, UT_ID (utmp_ent), utmpsize); + char const *id = UT_ID (utmp_ent); + idx_t idlen = strnlen (id, UT_ID_SIZE); + char const *prefix = _("id="); + idx_t prefixlen = strlen (prefix); + char *comment = xmalloc (prefixlen + idlen + 1); + char *p = mempcpy (comment, prefix, prefixlen); + p = mempcpy (p, id, idlen); + *p = '\0'; return comment; } @@ -470,7 +490,7 @@ print_deadprocs (const STRUCT_UTMP *utmp_ent) /* FIXME: add idle time? */ - print_line (-1, "", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line, + print_line (-1, "", ' ', UT_LINE_SIZE, utmp_ent->ut_line, time_string (utmp_ent), "", pidstr, comment, exitstr); free (comment); } @@ -483,7 +503,7 @@ print_login (const STRUCT_UTMP *utmp_ent) /* FIXME: add idle time? */ - print_line (-1, _("LOGIN"), ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line, + print_line (-1, _("LOGIN"), ' ', UT_LINE_SIZE, utmp_ent->ut_line, time_string (utmp_ent), "", pidstr, comment, ""); free (comment); } @@ -494,7 +514,7 @@ print_initspawn (const STRUCT_UTMP *utmp_ent) char *comment = make_id_equals_comment (utmp_ent); PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); - print_line (-1, "", ' ', sizeof utmp_ent->ut_line, utmp_ent->ut_line, + print_line (-1, "", ' ', UT_LINE_SIZE, utmp_ent->ut_line, time_string (utmp_ent), "", pidstr, comment, ""); free (comment); } @@ -531,9 +551,9 @@ print_runlevel (const STRUCT_UTMP *utmp_ent) /* Print the username of each valid entry and the number of valid entries in UTMP_BUF, which should have N elements. */ static void -list_entries_who (size_t n, const STRUCT_UTMP *utmp_buf) +list_entries_who (idx_t n, const STRUCT_UTMP *utmp_buf) { - unsigned long int entries = 0; + idx_t entries = 0; char const *separator = ""; while (n--) @@ -551,7 +571,7 @@ list_entries_who (size_t n, const STRUCT_UTMP *utmp_buf) } utmp_buf++; } - printf (_("\n# users=%lu\n"), entries); + printf (_("\n# users=%td\n"), entries); } static void @@ -561,9 +581,15 @@ print_heading (void) _("PID"), _("COMMENT"), _("EXIT")); } +/* Work around , + triggered by STREQ_LEN with a negative length. */ +#if 11 <= __GNUC__ +# pragma GCC diagnostic ignored "-Wstringop-overread" +#endif + /* Display UTMP_BUF, which should have N entries. */ static void -scan_entries (size_t n, const STRUCT_UTMP *utmp_buf) +scan_entries (idx_t n, const STRUCT_UTMP *utmp_buf) { char *ttyname_b IF_LINT ( = nullptr); time_t boottime = TYPE_MINIMUM (time_t); @@ -576,15 +602,14 @@ scan_entries (size_t n, const STRUCT_UTMP *utmp_buf) ttyname_b = ttyname (STDIN_FILENO); if (!ttyname_b) return; - if (STRNCMP_LIT (ttyname_b, DEV_DIR_WITH_TRAILING_SLASH) == 0) - ttyname_b += DEV_DIR_LEN; /* Discard /dev/ prefix. */ + if (STRNCMP_LIT (ttyname_b, "/dev/") == 0) + ttyname_b += sizeof "/dev/" - 1; /* Discard /dev/ prefix. */ } while (n--) { if (!my_line_only - || STREQ_LEN (ttyname_b, utmp_buf->ut_line, - sizeof (utmp_buf->ut_line))) + || STREQ_LEN (ttyname_b, utmp_buf->ut_line, UT_LINE_SIZE)) { if (need_users && IS_USER_PROCESS (utmp_buf)) print_user (utmp_buf, boottime); @@ -617,7 +642,7 @@ scan_entries (size_t n, const STRUCT_UTMP *utmp_buf) static void who (char const *filename, int options) { - size_t n_users; + idx_t n_users; STRUCT_UTMP *utmp_buf; if (read_utmp (filename, &n_users, &utmp_buf, options) != 0) -- 2.47.2