> Here are the changes I committed in gnulib. And here are the proposed changes for coreutils. Tested on a Fedora Rawhide system, prepared from https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-Rawhide-20230729.n.0.iso
The user-visible changes introduced by this change (when linking with libsystemd) are, as far as I can see: * "uptime", "users", "who -q" reports fewer users (because ptys without login are not counted). * "who -d" does not report anything any more. * "who -r" does not report anything any more. * "who -t" does not report anything any more. * "who -u" does not report ptys without login any more. The order is arbitrary. Example: Without systemd: bruno seat0 2023-07-30 11:25 ? 1663 (login screen) bruno tty2 2023-07-30 11:25 old 1663 (tty2) bruno pts/3 2023-08-01 01:36 22:33 30619 (:0) other pts/4 2023-08-01 17:19 06:50 40513 (::1) With systemd: other sshd pts/4 2023-08-01 17:19 06:50 40513 (::1) bruno seat0 2023-07-30 11:25 ? 1593 bruno tty2 2023-07-30 11:25 old 1593 * pinky $USER does not report a host any more (and thus does not spend time trying to do a DNS lookup of "login screen" and "tty2"). Example: Without systemd: Login Name TTY Idle When Where bruno Bruno Haible ?seat0 ????? 2023-07-30 11:25 login screen bruno Bruno Haible tty2 2d 2023-07-30 11:25 tty2 bruno Bruno Haible pts/3 22:39 2023-08-01 01:36 :0 With systemd: Login Name TTY Idle When Where bruno Bruno Haible ?seat0 ????? 2023-07-30 11:25 bruno Bruno Haible tty2 2d 2023-07-30 11:25 The proposed patch is attached. Note: Instead of the idiom #ifdef UT_HOST_SIZE (code for bounded ut_host) #else (code for unbounded ut_host) #endif one could also write if (UT_HOST_SIZE >= 0) { (code for bounded ut_host) } else { (code for unbounded ut_host) } It's just a matter of style whether one prefers #ifs or implicit dead code.
>From d80eea8fb087e9504a6dad27e1a880227f67915a Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Wed, 2 Aug 2023 01:32:55 +0200 Subject: [PATCH] maint: Update after gnulib module 'readutmp' changed For year-2038 safety on Linux/{x86,arm}, use systemd APIs. * 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/system.h (STREQ_LEN): Allow passing a third argument with value -1. * src/pinky.c: Test HAVE_STRUCT_XTMP_UT_HOST instead of HAVE_UT_HOST. (print_entry): Support the situation where ut_line is a 'char *' rather than a 'char[]' of fixed size. Likewise for ut_user and ut_host. * src/who.c: Test HAVE_STRUCT_XTMP_UT_HOST instead of HAVE_UT_HOST. (print_user): Support the situation where ut_line is a 'char *' rather than a 'char[]' of fixed size. Likewise for ut_user and ut_host. (print_deadprocs, print_login, print_initspawn, scan_entries): Likewise. (who): Free resources before returning. * src/users.c (users): Free resources before returning. * src/local.mk: Link the programs 'pinky', 'uptime', 'users', 'who' with $(READUTMP_LIB). --- configure.ac | 30 ------------------------------ src/local.mk | 6 ++++++ src/pinky.c | 41 ++++++++++++++++++++++++++++++----------- src/system.h | 6 +++++- src/users.c | 1 + src/who.c | 44 ++++++++++++++++++++++++++++++-------------- 6 files changed, 72 insertions(+), 56 deletions(-) diff --git a/configure.ac b/configure.ac index 33441a82f..afc1098f7 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 <sys/types.h> - #include <utmp.h> - 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 <sys/types.h> - #include <utmpx.h> - 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/src/local.mk b/src/local.mk index cb9b39274..4d7df2789 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 381e753b6..47abd7758 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 @@ -206,7 +206,8 @@ print_entry (const STRUCT_UTMP *utmp_ent) #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]; +#ifdef UT_LINE_SIZE + char line[DEV_DIR_LEN + UT_LINE_SIZE + 1]; char *p = line; /* Copy ut_line into LINE, prepending '/dev/' if ut_line is not @@ -214,7 +215,18 @@ print_entry (const STRUCT_UTMP *utmp_ent) 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)); + stzncpy (p, utmp_ent->ut_line, UT_LINE_SIZE); +#else + /* If ut_line contains a space, the device name starts after the space, + else at the beginning. */ + char *line = xmalloc (DEV_DIR_LEN + strlen (utmp_ent->ut_line) + 1); + char *space = strchr (utmp_ent->ut_line, ' '); + char *device = (space != NULL ? space + 1 : utmp_ent->ut_line); + if ( ! IS_ABSOLUTE_FILE_NAME (device)) + stpcpy (stpcpy (line, DEV_DIR_WITH_TRAILING_SLASH), device); + else + stpcpy (line, device); +#endif if (stat (line, &stats) == 0) { @@ -232,9 +244,13 @@ print_entry (const STRUCT_UTMP *utmp_ent) 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); +#else + const char *name = UT_USER (utmp_ent); +#endif pw = getpwnam (name); if (pw == nullptr) /* TRANSLATORS: Real name is unknown; at most 19 characters. */ @@ -253,8 +269,7 @@ print_entry (const STRUCT_UTMP *utmp_ent) } } - printf (" %c%-8.*s", - mesg, (int) sizeof (utmp_ent->ut_line), utmp_ent->ut_line); + printf (" %c%-8.*s", mesg, UT_LINE_SIZE, utmp_ent->ut_line); if (include_idle) { @@ -267,15 +282,19 @@ print_entry (const STRUCT_UTMP *utmp_ent) printf (" %s", time_string (utmp_ent)); -#ifdef HAVE_UT_HOST +#if 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; +# ifdef UT_HOST_SIZE + char ut_host[UT_HOST_SIZE + 1]; /* 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)); + 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, ':'); @@ -408,7 +427,7 @@ print_heading (void) if (include_idle) printf (" %-6s", _("Idle")); printf (" %-*s", time_format_width, _("When")); -#ifdef HAVE_UT_HOST +#if HAVE_STRUCT_XTMP_UT_HOST if (include_where) printf (" %s", _("Where")); #endif @@ -550,14 +569,14 @@ main (int argc, char **argv) case 'i': include_fullname = false; -#ifdef HAVE_UT_HOST +#if HAVE_STRUCT_XTMP_UT_HOST include_where = false; #endif break; case 'q': include_fullname = false; -#ifdef HAVE_UT_HOST +#if HAVE_STRUCT_XTMP_UT_HOST include_where = false; #endif include_idle = false; diff --git a/src/system.h b/src/system.h index b5ec074e7..60b67ba1a 100644 --- a/src/system.h +++ b/src/system.h @@ -192,7 +192,11 @@ select_plural (uintmax_t n) } #define STREQ(a, b) (strcmp (a, b) == 0) -#define STREQ_LEN(a, b, n) (strncmp (a, b, n) == 0) + +/* n < 0 means that a and b are unbounded. */ +#define STREQ_LEN(a, b, n) \ + ((n) >= 0 ? strncmp (a, b, n) == 0 : strcmp (a, b) == 0) + #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/users.c b/src/users.c index e14f3fc3e..d7c02cf98 100644 --- a/src/users.c +++ b/src/users.c @@ -90,6 +90,7 @@ users (char const *filename, int options) list_entries_users (n_users, utmp_buf); + free_utmp (n_users, utmp_buf); free (utmp_buf); } diff --git a/src/who.c b/src/who.c index ec0dff792..ae526ae57 100644 --- a/src/who.c +++ b/src/who.c @@ -333,24 +333,36 @@ 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 +#if HAVE_STRUCT_XTMP_UT_HOST static size_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]; +#ifdef UT_LINE_SIZE + char line[DEV_DIR_LEN + UT_LINE_SIZE + 1]; char *p = line; - PIDSTR_DECL_AND_INIT (pidstr, utmp_ent); /* 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)); + stzncpy (p, utmp_ent->ut_line, UT_LINE_SIZE); +#else + /* If ut_line contains a space, the device name starts after the space, + else at the beginning. */ + char *line = xmalloc (DEV_DIR_LEN + strlen (utmp_ent->ut_line) + 1); + char *space = strchr (utmp_ent->ut_line, ' '); + char *device = (space != NULL ? space + 1 : utmp_ent->ut_line); + if ( ! IS_ABSOLUTE_FILE_NAME (device)) + stpcpy (stpcpy (line, DEV_DIR_WITH_TRAILING_SLASH), device); + else + stpcpy (line, device); +#endif if (stat (line, &stats) == 0) { @@ -368,15 +380,19 @@ 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; +# ifdef UT_HOST_SIZE + char ut_host[UT_HOST_SIZE + 1]; /* 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)); + 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, ':'); @@ -428,8 +444,8 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) } #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 : "", ""); } @@ -470,7 +486,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 +499,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 +510,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); } @@ -583,8 +599,7 @@ scan_entries (size_t n, const STRUCT_UTMP *utmp_buf) 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); @@ -628,6 +643,7 @@ who (char const *filename, int options) else scan_entries (n_users, utmp_buf); + free_utmp (n_users, utmp_buf); free (utmp_buf); } -- 2.34.1