I wrote: > > (1) The API of the readutmp module should provide unlimited-length > > ut_user, > > ut_host etc. fields always. No more #ifdef UT_USER_SIZE. > > (2) The readutmp module should use a runtime 'if' rather than a > > compile-time > > #if, in order to dispatch between the systemd backend and the > > file-based > > backend. > > > > I'll work on (1) today.
(1) done through the following patch. It does not break coreutils. But coreutils can now be simplified through the attached 0001-maint-Simplify-after-gnulib-changed.patch . 2023-08-08 Bruno Haible <br...@clisp.org> readutmp: Return entries with unbounded strings on all platforms. Suggested by Paul Eggert in <https://lists.gnu.org/archive/html/bug-gnulib/2023-07/msg00165.html>. * m4/readutmp.m4 (gl_READUTMP): Test also whether struct utmp has an ut_tv member, and whether struct utmp and struct utmpx have an ut_session member. * lib/readutmp.h (struct gl_utmp): Define always. Add ut_exit field. (HAVE_GL_UTMP): Remove macro. (UT_USER, UT_TIME_MEMBER, UT_PID, UT_TYPE_EQ, UT_TYPE_NOT_DEFINED, UT_EXIT_E_TERMINATION, UT_EXIT_E_EXIT, STRUCT_UTMP): Define w.r.t. struct gl_utmp. (UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE): Define to -1 always. (getutent): Remove declaration. (HAVE_STRUCT_XTMP_UT_EXIT): Remove unused macro. (HAVE_STRUCT_XTMP_UT_ID, HAVE_STRUCT_XTMP_UT_PID, HAVE_STRUCT_XTMP_UT_HOST): Change to match the way coreutils uses these macros. * lib/readutmp.c (UT_USER, UT_TIME_MEMBER, UT_PID, UT_TYPE_EQ, UT_TYPE_NOT_DEFINED, IS_USER_PROCESS, UT_EXIT_E_TERMINATION, UT_EXIT_E_EXIT, UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE): Define w.r.t. struct utmpx or struct utmp. (extract_trimmed_name): Don't use UT_USER or UT_USER_SIZE here. (desirable_utmp_entry): Don't use UT_TIME_MEMBER or UT_USER here. (struct utmp_alloc): Define always. (add_utmp): Likewise. Add user_len, id_len, line_len, host_len, termination, exit arguments. Don't require that user, id, line, host are NUL-terminated. Assume user and host are non-NULL. (finish_utmp): New function, extracted from read_utmp. (read_utmp) [READUTMP_USE_SYSTEMD]: Update add_utmp invocations. Pass a non-NULL user and a non-NULL host. Call finish_utmp. (getutent): Move declaration from readutmp.h to here. (copy_utmp_entry): Remove function. (read_utmp) [UTMP_NAME_FUNCTION]: Replace variables n_read, n_alloc, utmp with a 'struct utmp_alloc'. Use 'struct utmpx32' from copy_utmp_entry here. Invoke add_utmp and finish_utmp. (read_utmp) [!UTMP_NAME_FUNCTION]: Replace variables n_read, n_alloc, utmp with a 'struct utmp_alloc'. Invoke add_utmp and finish_utmp. * NEWS: Mention the API change.
From 622d2c0763777eb909a4fda5048238f524cc36f9 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Tue, 8 Aug 2023 17:36:10 +0200 Subject: [PATCH] readutmp: Return entries with unbounded strings on all platforms. Suggested by Paul Eggert in <https://lists.gnu.org/archive/html/bug-gnulib/2023-07/msg00165.html>. * m4/readutmp.m4 (gl_READUTMP): Test also whether struct utmp has an ut_tv member, and whether struct utmp and struct utmpx have an ut_session member. * lib/readutmp.h (struct gl_utmp): Define always. Add ut_exit field. (HAVE_GL_UTMP): Remove macro. (UT_USER, UT_TIME_MEMBER, UT_PID, UT_TYPE_EQ, UT_TYPE_NOT_DEFINED, UT_EXIT_E_TERMINATION, UT_EXIT_E_EXIT, STRUCT_UTMP): Define w.r.t. struct gl_utmp. (UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE): Define to -1 always. (getutent): Remove declaration. (HAVE_STRUCT_XTMP_UT_EXIT): Remove unused macro. (HAVE_STRUCT_XTMP_UT_ID, HAVE_STRUCT_XTMP_UT_PID, HAVE_STRUCT_XTMP_UT_HOST): Change to match the way coreutils uses these macros. * lib/readutmp.c (UT_USER, UT_TIME_MEMBER, UT_PID, UT_TYPE_EQ, UT_TYPE_NOT_DEFINED, IS_USER_PROCESS, UT_EXIT_E_TERMINATION, UT_EXIT_E_EXIT, UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE): Define w.r.t. struct utmpx or struct utmp. (extract_trimmed_name): Don't use UT_USER or UT_USER_SIZE here. (desirable_utmp_entry): Don't use UT_TIME_MEMBER or UT_USER here. (struct utmp_alloc): Define always. (add_utmp): Likewise. Add user_len, id_len, line_len, host_len, termination, exit arguments. Don't require that user, id, line, host are NUL-terminated. Assume user and host are non-NULL. (finish_utmp): New function, extracted from read_utmp. (read_utmp) [READUTMP_USE_SYSTEMD]: Update add_utmp invocations. Pass a non-NULL user and a non-NULL host. Call finish_utmp. (getutent): Move declaration from readutmp.h to here. (copy_utmp_entry): Remove function. (read_utmp) [UTMP_NAME_FUNCTION]: Replace variables n_read, n_alloc, utmp with a 'struct utmp_alloc'. Use 'struct utmpx32' from copy_utmp_entry here. Invoke add_utmp and finish_utmp. (read_utmp) [!UTMP_NAME_FUNCTION]: Replace variables n_read, n_alloc, utmp with a 'struct utmp_alloc'. Invoke add_utmp and finish_utmp. * NEWS: Mention the API change. --- ChangeLog | 42 ++++ NEWS | 4 + lib/readutmp.c | 540 ++++++++++++++++++++++++++++++++----------------- lib/readutmp.h | 195 ++++++------------ m4/readutmp.m4 | 5 +- 5 files changed, 467 insertions(+), 319 deletions(-) diff --git a/ChangeLog b/ChangeLog index b655ce185d..dd730a435f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +2023-08-08 Bruno Haible <br...@clisp.org> + + readutmp: Return entries with unbounded strings on all platforms. + Suggested by Paul Eggert in + <https://lists.gnu.org/archive/html/bug-gnulib/2023-07/msg00165.html>. + * m4/readutmp.m4 (gl_READUTMP): Test also whether struct utmp has an + ut_tv member, and whether struct utmp and struct utmpx have an + ut_session member. + * lib/readutmp.h (struct gl_utmp): Define always. Add ut_exit field. + (HAVE_GL_UTMP): Remove macro. + (UT_USER, UT_TIME_MEMBER, UT_PID, UT_TYPE_EQ, UT_TYPE_NOT_DEFINED, + UT_EXIT_E_TERMINATION, UT_EXIT_E_EXIT, STRUCT_UTMP): Define w.r.t. + struct gl_utmp. + (UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE): Define to -1 + always. + (getutent): Remove declaration. + (HAVE_STRUCT_XTMP_UT_EXIT): Remove unused macro. + (HAVE_STRUCT_XTMP_UT_ID, HAVE_STRUCT_XTMP_UT_PID, + HAVE_STRUCT_XTMP_UT_HOST): Change to match the way coreutils uses these + macros. + * lib/readutmp.c (UT_USER, UT_TIME_MEMBER, UT_PID, UT_TYPE_EQ, + UT_TYPE_NOT_DEFINED, IS_USER_PROCESS, UT_EXIT_E_TERMINATION, + UT_EXIT_E_EXIT, UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE): + Define w.r.t. struct utmpx or struct utmp. + (extract_trimmed_name): Don't use UT_USER or UT_USER_SIZE here. + (desirable_utmp_entry): Don't use UT_TIME_MEMBER or UT_USER here. + (struct utmp_alloc): Define always. + (add_utmp): Likewise. Add user_len, id_len, line_len, host_len, + termination, exit arguments. Don't require that user, id, line, host are + NUL-terminated. Assume user and host are non-NULL. + (finish_utmp): New function, extracted from read_utmp. + (read_utmp) [READUTMP_USE_SYSTEMD]: Update add_utmp invocations. Pass a + non-NULL user and a non-NULL host. Call finish_utmp. + (getutent): Move declaration from readutmp.h to here. + (copy_utmp_entry): Remove function. + (read_utmp) [UTMP_NAME_FUNCTION]: Replace variables n_read, n_alloc, + utmp with a 'struct utmp_alloc'. Use 'struct utmpx32' from + copy_utmp_entry here. Invoke add_utmp and finish_utmp. + (read_utmp) [!UTMP_NAME_FUNCTION]: Replace variables n_read, n_alloc, + utmp with a 'struct utmp_alloc'. Invoke add_utmp and finish_utmp. + * NEWS: Mention the API change. + 2023-08-08 Bruno Haible <br...@clisp.org> readutmp: Fix compilation error on OpenBSD and AIX (regr. 2023-08-03). diff --git a/NEWS b/NEWS index 265f9788bc..081a5f6035 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,10 @@ User visible incompatible changes Date Modules Changes +2023-08-08 readutmp The result element type of the function read_utmp, + STRUCT_UTMP, is no longer the same as the result + value type of the function getutxent, struct utmpx. + 2023-08-03 readutmp Some STRUCT_UTMP members can be char *, 2023-08-01 rather than fixed-length char arrays. On some platforms, the timestamp is ut_ts of type diff --git a/lib/readutmp.c b/lib/readutmp.c index 4e1d7ec26b..7ef5bfe84c 100644 --- a/lib/readutmp.c +++ b/lib/readutmp.c @@ -43,6 +43,95 @@ /* Each of the FILE streams in this file is only used in a single thread. */ #include "unlocked-io.h" +/* The following macros describe the 'struct UTMP_STRUCT_NAME', + *not* 'struct gl_utmp'. */ +#undef UT_USER +#undef UT_TIME_MEMBER +#undef UT_PID +#undef UT_TYPE_EQ +#undef UT_TYPE_NOT_DEFINED +#undef IS_USER_PROCESS +#undef UT_EXIT_E_TERMINATION +#undef UT_EXIT_E_EXIT + +/* Accessor macro for the member named ut_user or ut_name. */ +#if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_NAME \ + : HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_NAME) +# define UT_USER(UT) ((UT)->ut_name) +#else +# define UT_USER(UT) ((UT)->ut_user) +#endif + +/* Accessor macro for the member of type time_t (or 'unsigned int'). */ +#if HAVE_UTMPX_H || (HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_TV) +# define UT_TIME_MEMBER(UT) ((UT)->ut_tv.tv_sec) +#else +# define UT_TIME_MEMBER(UT) ((UT)->ut_time) +#endif + +/* Accessor macro for the member named ut_pid. */ +#if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID) +# define UT_PID(UT) ((UT)->ut_pid) +#else +# define UT_PID(UT) 0 +#endif + +/* Accessor macros for the member named ut_type. */ +#if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMP_UT_TYPE : HAVE_STRUCT_UTMPX_UT_TYPE) +# define UT_TYPE_EQ(UT, V) ((UT)->ut_type == (V)) +# define UT_TYPE_NOT_DEFINED 0 +#else +# define UT_TYPE_EQ(UT, V) 0 +# define UT_TYPE_NOT_DEFINED 1 +#endif + +/* Determines whether an entry *UT corresponds to a user process. */ +#define IS_USER_PROCESS(UT) \ + ((UT)->ut_user[0] \ + && (UT_TYPE_USER_PROCESS (UT) \ + || (UT_TYPE_NOT_DEFINED && (UT)->ut_ts.tv_sec != 0))) + +#if HAVE_UTMPX_H +# if HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION +# define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.e_termination) +# elif HAVE_STRUCT_UTMPX_UT_EXIT_UT_TERMINATION /* OSF/1 */ +# define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.ut_termination) +# else +# define UT_EXIT_E_TERMINATION(UT) 0 +# endif +#elif HAVE_UTMP_H +# if HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION +# define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.e_termination) +# else +# define UT_EXIT_E_TERMINATION(UT) 0 +# endif +#endif + +#if HAVE_UTMPX_H +# if HAVE_STRUCT_UTMPX_UT_EXIT_E_EXIT +# define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.e_exit) +# elif HAVE_STRUCT_UTMPX_UT_EXIT_UT_EXIT /* OSF/1 */ +# define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.ut_exit) +# else +# define UT_EXIT_E_EXIT(UT) 0 +# endif +#elif HAVE_UTMP_H +# if HAVE_STRUCT_UTMP_UT_EXIT_E_EXIT +# define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.e_exit) +# else +# define UT_EXIT_E_EXIT(UT) 0 +# endif +#endif + +/* Size of the UT_USER (ut) member. */ +#define UT_USER_SIZE sizeof UT_USER ((struct UTMP_STRUCT_NAME *) 0) +/* Size of the ut->ut_id member. */ +#define UT_ID_SIZE sizeof (((struct UTMP_STRUCT_NAME *) 0)->ut_id) +/* Size of the ut->ut_line member. */ +#define UT_LINE_SIZE sizeof (((struct UTMP_STRUCT_NAME *) 0)->ut_line) +/* Size of the ut->ut_host member. */ +#define UT_HOST_SIZE sizeof (((struct UTMP_STRUCT_NAME *) 0)->ut_host) + #if 8 <= __GNUC__ # pragma GCC diagnostic ignored "-Wsizeof-pointer-memaccess" #endif @@ -52,14 +141,14 @@ # pragma GCC diagnostic ignored "-Wstringop-overread" #endif -/* Copy UT_USER (UT) into storage obtained from malloc. Then remove any +/* Copy UT->ut_user into storage obtained from malloc. Then remove any trailing spaces from the copy, NUL terminate it, and return the copy. */ char * extract_trimmed_name (const STRUCT_UTMP *ut) { - char const *name = UT_USER (ut); - idx_t len = strnlen (name, UT_USER_SIZE); + char const *name = ut->ut_user; + idx_t len = strlen (name); char const *p; for (p = name + len; name < p && p[-1] == ' '; p--) continue; @@ -73,6 +162,12 @@ extract_trimmed_name (const STRUCT_UTMP *ut) static bool desirable_utmp_entry (STRUCT_UTMP const *ut, int options) { +# if defined __OpenBSD__ && !HAVE_UTMPX_H + /* Eliminate entirely empty entries. */ + if (ut->ut_ts.tv_sec == 0 && ut->ut_user[0] == '\0' + && ut->ut_line[0] == '\0' && ut->ut_host[0] == '\0') + return false; +# endif bool user_proc = IS_USER_PROCESS (ut); if ((options & READ_UTMP_USER_PROCESS) && !user_proc) return false; @@ -81,15 +176,108 @@ desirable_utmp_entry (STRUCT_UTMP const *ut, int options) && 0 < UT_PID (ut) && (kill (UT_PID (ut), 0) < 0 && errno == ESRCH)) return false; -# if defined __OpenBSD__ && !HAVE_UTMPX_H - /* Eliminate entirely empty entries. */ - if (UT_TIME_MEMBER (ut) == 0 && UT_USER (ut)[0] == '\0' - && ut->ut_line[0] == '\0' && ut->ut_host[0] == '\0') - return false; -# endif return true; } +/* A memory allocation for an in-progress read_utmp. */ + +struct utmp_alloc +{ + /* A pointer to a possibly-empty array of utmp entries, + followed by a possibly-empty sequence of unused bytes, + followed by a possibly-empty sequence of string bytes. + UTMP is either null or allocated by malloc. */ + struct gl_utmp *utmp; + + /* The number of utmp entries. */ + idx_t filled; + + /* The string byte sequence length. Strings are null-terminated. */ + idx_t string_bytes; + + /* The total number of bytes allocated. This equals + FILLED * sizeof *UTMP + [size of free area] + STRING_BYTES. */ + idx_t alloc_bytes; +}; + +/* Use the memory allocation A, and if the read_utmp options OPTIONS + permit it, add a new entry with the given USER, etc. Grow A as + needed, reporting an error and exit on memory allocation failure. + Return the resulting memory allocation. */ + +static struct utmp_alloc +add_utmp (struct utmp_alloc a, int options, + char const *user, idx_t user_len, + char const *id, idx_t id_len, + char const *line, idx_t line_len, + char const *host, idx_t host_len, + pid_t pid, short type, struct timespec ts, long session, + int termination, int exit) +{ + int entry_bytes = sizeof (struct gl_utmp); + idx_t avail = a.alloc_bytes - (entry_bytes * a.filled + a.string_bytes); + idx_t needed_string_bytes = + (user_len + 1) + (id_len + 1) + (line_len + 1) + (host_len + 1); + idx_t needed = entry_bytes + needed_string_bytes; + if (avail < needed) + { + idx_t old_string_offset = a.alloc_bytes - a.string_bytes; + void *new = xpalloc (a.utmp, &a.alloc_bytes, needed - avail, -1, 1); + idx_t new_string_offset = a.alloc_bytes - a.string_bytes; + a.utmp = new; + char *q = new; + memmove (q + new_string_offset, q + old_string_offset, a.string_bytes); + } + struct gl_utmp *ut = &a.utmp[a.filled]; + char *stringlim = (char *) a.utmp + a.alloc_bytes; + char *p = stringlim - a.string_bytes; + *--p = '\0'; /* NUL-terminate ut->ut_user */ + ut->ut_user = p = memcpy (p - user_len, user, user_len); + *--p = '\0'; /* NUL-terminate ut->ut_id */ + ut->ut_id = p = memcpy (p - id_len, id, id_len); + *--p = '\0'; /* NUL-terminate ut->ut_line */ + ut->ut_line = p = memcpy (p - line_len, line, line_len); + *--p = '\0'; /* NUL-terminate ut->ut_host */ + ut->ut_host = memcpy (p - host_len, host, host_len); + ut->ut_ts = ts; + ut->ut_pid = pid; + ut->ut_session = session; + ut->ut_type = type; + ut->ut_exit.e_termination = termination; + ut->ut_exit.e_exit = exit; + if (desirable_utmp_entry (ut, options)) + { + /* Now that UT has been checked, relocate its string slots to be + relative to the end of the allocated storage, so that these + slots survive realloc. The slots will be relocated back just + before read_utmp returns. */ + ut->ut_user = (char *) (intptr_t) (ut->ut_user - stringlim); + ut->ut_id = (char *) (intptr_t) (ut->ut_id - stringlim); + ut->ut_line = (char *) (intptr_t) (ut->ut_line - stringlim); + ut->ut_host = (char *) (intptr_t) (ut->ut_host - stringlim); + a.filled++; + a.string_bytes += needed_string_bytes; + } + return a; +} + +/* Relocate the string pointers in A back to their natural position. */ +static struct utmp_alloc +finish_utmp (struct utmp_alloc a) +{ + char *stringlim = (char *) a.utmp + a.alloc_bytes; + + for (idx_t i = 0; i < a.filled; i++) + { + a.utmp[i].ut_user = (intptr_t) a.utmp[i].ut_user + stringlim; + a.utmp[i].ut_id = (intptr_t) a.utmp[i].ut_id + stringlim; + a.utmp[i].ut_line = (intptr_t) a.utmp[i].ut_line + stringlim; + a.utmp[i].ut_host = (intptr_t) a.utmp[i].ut_host + stringlim; + } + + return a; +} + # if READUTMP_USE_SYSTEMD /* Use systemd and Linux /proc and kernel APIs. */ @@ -226,81 +414,6 @@ guess_pty_name (uid_t uid, const struct timespec at) return NULL; } -/* A memory allocation for an in-progress read_utmp. */ - -struct utmp_alloc -{ - /* A pointer to a possibly-empty array of utmp entries, - followed by a possibly-empty sequence of unused bytes, - followed by a possibly-empty sequence of string bytes. - UTMP is either null or allocated by malloc. */ - STRUCT_UTMP *utmp; - - /* The number of utmp entries. */ - idx_t filled; - - /* The string byte sequence length. Strings are null-terminated. */ - idx_t string_bytes; - - /* The total number of bytes allocated. This equals - FILLED * sizeof *UTMP + [size of free area] + STRING_BYTES. */ - idx_t alloc_bytes; -}; - -/* Use the memory allocation A, and if the read_utmp options OPTIONS - permit it, add a new entry with the given USER, etc. Grow A as - needed, reporting an error and exit on memory allocation failure. - Return the resulting memory allocation. */ - -static struct utmp_alloc -add_utmp (struct utmp_alloc a, int options, - char const *user, char const *id, char const *line, pid_t pid, - short type, struct timespec ts, char const *host, long session) -{ - if (!user) user = ""; - if (!host) host = ""; - int entry_bytes = sizeof (STRUCT_UTMP); - idx_t usersize = strlen (user) + 1, idsize = strlen (id) + 1, - linesize = strlen (line) + 1, hostsize = strlen (host) + 1; - idx_t avail = a.alloc_bytes - (entry_bytes * a.filled + a.string_bytes); - idx_t needed_string_bytes = usersize + idsize + linesize + hostsize; - idx_t needed = entry_bytes + needed_string_bytes; - if (avail < needed) - { - idx_t old_string_offset = a.alloc_bytes - a.string_bytes; - void *new = xpalloc (a.utmp, &a.alloc_bytes, needed - avail, -1, 1); - idx_t new_string_offset = a.alloc_bytes - a.string_bytes; - a.utmp = new; - char *q = new; - memmove (q + new_string_offset, q + old_string_offset, a.string_bytes); - } - STRUCT_UTMP *ut = &a.utmp[a.filled]; - char *stringlim = (char *) a.utmp + a.alloc_bytes; - char *p = stringlim - a.string_bytes; - ut->ut_user = p = memcpy (p - usersize, user, usersize); - ut->ut_id = p = memcpy (p - idsize, id, idsize); - ut->ut_line = p = memcpy (p - linesize, line, linesize); - ut->ut_host = memcpy (p - hostsize, host, hostsize); - ut->ut_ts = ts; - ut->ut_pid = pid; - ut->ut_session = session; - ut->ut_type = type; - if (desirable_utmp_entry (ut, options)) - { - /* Now that UT has been checked, relocate its string slots to be - relative to the end of the allocated storage, so that these - slots survive realloc. The slots will be relocated back just - before read_utmp returns. */ - ut->ut_user = (char *) (intptr_t) (ut->ut_user - stringlim); - ut->ut_id = (char *) (intptr_t) (ut->ut_id - stringlim); - ut->ut_line = (char *) (intptr_t) (ut->ut_line - stringlim); - ut->ut_host = (char *) (intptr_t) (ut->ut_host - stringlim); - a.filled++; - a.string_bytes += needed_string_bytes; - } - return a; -} - int read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, int options) @@ -317,8 +430,12 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, /* Synthesize a BOOT_TIME entry. */ if (!(options & READ_UTMP_USER_PROCESS)) - a = add_utmp (a, options, "reboot", "", "~", 0, - BOOT_TIME, get_boot_time (), "", 0); + a = add_utmp (a, options, + "reboot", strlen ("reboot"), + "", 0, + "~", strlen ("~"), + "", 0, + 0, BOOT_TIME, get_boot_time (), 0, 0, 0); /* Synthesize USER_PROCESS entries. */ char **sessions; @@ -341,7 +458,8 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, if (sd_session_get_seat (session, &seat) < 0) seat = NULL; - char missing_type[] = ""; + char missing[] = ""; + char *type = NULL; char *tty; if (sd_session_get_tty (session, &tty) < 0) @@ -349,7 +467,7 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, tty = NULL; /* Try harder to get a sensible value for the tty. */ if (sd_session_get_type (session, &type) < 0) - type = missing_type; + type = missing; if (strcmp (type, "tty") == 0) { char *service; @@ -380,7 +498,7 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, { char *user; if (sd_session_get_username (session, &user) < 0) - user = NULL; + user = missing; pid_t leader_pid; if (sd_session_get_leader (session, &leader_pid) < 0) @@ -390,11 +508,11 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, char *remote_host; if (sd_session_get_remote_host (session, &remote_host) < 0) { - host = NULL; + host = missing; /* For backward compatibility, put the X11 display into the host field. */ if (!type && sd_session_get_type (session, &type) < 0) - type = missing_type; + type = missing; if (strcmp (type, "x11") == 0) { char *display; @@ -420,19 +538,29 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, } if (seat != NULL) - a = add_utmp (a, options, user, session, seat, + a = add_utmp (a, options, + user, strlen (user), + session, strlen (session), + seat, strlen (seat), + host, strlen (host), leader_pid /* the best we have */, - USER_PROCESS, start_ts, host, leader_pid); + USER_PROCESS, start_ts, leader_pid, 0, 0); if (tty != NULL) - a = add_utmp (a, options, user, session, tty, + a = add_utmp (a, options, + user, strlen (user), + session, strlen (session), + tty, strlen (tty), + host, strlen (host), leader_pid /* the best we have */, - USER_PROCESS, start_ts, host, leader_pid); + USER_PROCESS, start_ts, leader_pid, 0, 0); - free (host); - free (user); + if (host != missing) + free (host); + if (user != missing) + free (user); } - if (type != missing_type) + if (type != missing) free (type); free (tty); free (seat); @@ -441,18 +569,7 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, free (sessions); } - /* Relocate the string pointers back to their natural position. */ - { - char *stringlim = (char *) a.utmp + a.alloc_bytes; - - for (idx_t i = 0; i < a.filled; i++) - { - a.utmp[i].ut_user = (intptr_t) a.utmp[i].ut_user + stringlim; - a.utmp[i].ut_id = (intptr_t) a.utmp[i].ut_id + stringlim; - a.utmp[i].ut_line = (intptr_t) a.utmp[i].ut_line + stringlim; - a.utmp[i].ut_host = (intptr_t) a.utmp[i].ut_host + stringlim; - } - } + a = finish_utmp (a); *n_entries = a.filled; *utmp_buf = a.utmp; @@ -460,67 +577,16 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, return 0; } -# elif defined UTMP_NAME_FUNCTION +# elif defined UTMP_NAME_FUNCTION /* glibc, musl, macOS, FreeBSD, NetBSD, Minix, AIX, IRIX, Solaris, Cygwin, Android */ -static void -copy_utmp_entry (STRUCT_UTMP *dst, STRUCT_UTMP *src) -{ -# if __GLIBC__ && _TIME_BITS == 64 - /* Convert from external form in SRC to internal form in DST. - It is OK to convert now, rather than earlier, before - desirable_utmp_entry was invoked, because desirable_utmp_entry - inspects only the leading prefix of the entry, which is the - same in both external and internal forms. */ - - /* This is a near-copy of glibc's struct utmpx, which stops working - after the year 2038. Unlike the glibc version, struct utmpx32 - describes the file format even if time_t is 64 bits. */ - struct utmpx32 - { - short int ut_type; /* Type of login. */ - pid_t ut_pid; /* Process ID of login process. */ - char ut_line[sizeof src->ut_line]; /* Devicename. */ - char ut_id[sizeof src->ut_id]; /* Inittab ID. */ - char ut_user[sizeof src->ut_user]; /* Username. */ - char ut_host[sizeof src->ut_host]; /* Hostname for remote login. */ - struct __exit_status ut_exit; /* Exit status of a process marked - as DEAD_PROCESS. */ - /* The fields ut_session and ut_tv must be the same size when compiled - 32- and 64-bit. This allows files and shared memory to be shared - between 32- and 64-bit applications. */ - int ut_session; /* Session ID, used for windowing. */ - struct - { - /* Seconds. Unsigned not signed, as glibc did not exist before 1970, - and if the format is still in use after 2038 its timestamps - will surely have the sign bit on. This hack stops working - at 2106-02-07 06:28:16 UTC. */ - unsigned int tv_sec; - - int tv_usec; /* Microseconds. */ - } ut_tv; /* Time entry was made. */ - int ut_addr_v6[4]; /* Internet address of remote host. */ - char ut_reserved[20]; /* Reserved for future use. */ - } *s = (struct utmpx32 *) src; - memcpy (dst, s, offsetof (struct utmpx32, ut_session)); - dst->ut_session = s->ut_session; - dst->ut_tv.tv_sec = s->ut_tv.tv_sec; - dst->ut_tv.tv_usec = s->ut_tv.tv_usec; - memcpy (&dst->ut_addr_v6, s->ut_addr_v6, sizeof dst->ut_addr_v6); -# else - *dst = *src; +# if !HAVE_UTMPX_H && HAVE_UTMP_H && !HAVE_DECL_GETUTENT +struct utmp *getutent (void); # endif -} int read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, int options) { - idx_t n_read = 0; - idx_t n_alloc = 0; - STRUCT_UTMP *utmp = NULL; - STRUCT_UTMP *ut; - /* Ignore the return value for now. Solaris' utmpname returns 1 upon success -- which is contrary to what the GNU libc version does. In addition, older GNU libc @@ -529,59 +595,163 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, SET_UTMP_ENT (); - while ((ut = GET_UTMP_ENT ()) != NULL) - if (desirable_utmp_entry (ut, options)) + struct utmp_alloc a = {0}; + void const *entry; + + while ((entry = GET_UTMP_ENT ()) != NULL) + { +# if __GLIBC__ && _TIME_BITS == 64 + /* This is a near-copy of glibc's struct utmpx, which stops working + after the year 2038. Unlike the glibc version, struct utmpx32 + describes the file format even if time_t is 64 bits. */ + struct utmpx32 { - if (n_read == n_alloc) - utmp = xpalloc (utmp, &n_alloc, 1, -1, sizeof *utmp); + short int ut_type; /* Type of login. */ + pid_t ut_pid; /* Process ID of login process. */ + char ut_line[UT_LINE_SIZE]; /* Devicename. */ + char ut_id[UT_ID_SIZE]; /* Inittab ID. */ + char ut_user[UT_USER_SIZE]; /* Username. */ + char ut_host[UT_HOST_SIZE]; /* Hostname for remote login. */ + struct __exit_status ut_exit; /* Exit status of a process marked + as DEAD_PROCESS. */ + /* The fields ut_session and ut_tv must be the same size when compiled + 32- and 64-bit. This allows files and shared memory to be shared + between 32- and 64-bit applications. */ + int ut_session; /* Session ID, used for windowing. */ + struct + { + /* Seconds. Unsigned not signed, as glibc did not exist before 1970, + and if the format is still in use after 2038 its timestamps + will surely have the sign bit on. This hack stops working + at 2106-02-07 06:28:16 UTC. */ + unsigned int tv_sec; + int tv_usec; /* Microseconds. */ + } ut_tv; /* Time entry was made. */ + int ut_addr_v6[4]; /* Internet address of remote host. */ + char ut_reserved[20]; /* Reserved for future use. */ + }; + struct utmpx32 const *ut = (struct utmpx32 const *) entry; +# else + struct UTMP_STRUCT_NAME const *ut = (struct UTMP_STRUCT_NAME const *) entry; +# endif - copy_utmp_entry (&utmp[n_read++], ut); - } + a = add_utmp (a, options, + UT_USER (ut), strnlen (UT_USER (ut), UT_USER_SIZE), + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID) + ut->ut_id, strnlen (ut->ut_id, UT_ID_SIZE), + #else + "", 0, + #endif + ut->ut_line, strnlen (ut->ut_line, UT_LINE_SIZE), + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_HOST : HAVE_STRUCT_UTMP_UT_HOST) + ut->ut_host, strnlen (ut->ut_host, UT_HOST_SIZE), + #else + "", 0, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID) + ut->ut_pid, + #else + 0, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE) + ut->ut_type, + #else + 0, + #endif + #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV) + (struct timespec) { .tv_sec = ut->ut_tv.tv_sec, .tv_nsec = ut->ut_tv.tv_usec * 1000 }, + #else + (struct timespec) { .tv_sec = ut->ut_time, .tv_nsec = 0 }, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_SESSION : HAVE_STRUCT_UTMP_UT_SESSION) + ut->ut_session, + #else + 0, + #endif + UT_EXIT_E_TERMINATION (ut), UT_EXIT_E_EXIT (ut) + ); + } END_UTMP_ENT (); - *n_entries = n_read; - *utmp_buf = utmp; + a = finish_utmp (a); + + *n_entries = a.filled; + *utmp_buf = a.utmp; return 0; } -# else +# else /* old FreeBSD, OpenBSD, HP-UX */ int read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, int options) { - idx_t n_read = 0; - idx_t n_alloc = 0; - STRUCT_UTMP *utmp = NULL; - int saved_errno; FILE *f = fopen (file, "re"); if (! f) return -1; + struct utmp_alloc a = {0}; + for (;;) { - if (n_read == n_alloc) - utmp = xpalloc (utmp, &n_alloc, 1, -1, sizeof *utmp); - if (fread (&utmp[n_read], sizeof utmp[n_read], 1, f) == 0) + struct UTMP_STRUCT_NAME ut; + + if (fread (&ut, sizeof ut, 1, f) == 0) break; - n_read += desirable_utmp_entry (&utmp[n_read], options); + a = add_utmp (a, options, + UT_USER (&ut), strnlen (UT_USER (&ut), UT_USER_SIZE), + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID) + ut.ut_id, strnlen (ut.ut_id, UT_ID_SIZE), + #else + "", 0, + #endif + ut.ut_line, strnlen (ut.ut_line, UT_LINE_SIZE), + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_HOST : HAVE_STRUCT_UTMP_UT_HOST) + ut.ut_host, strnlen (ut.ut_host, UT_HOST_SIZE), + #else + "", 0, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID) + ut.ut_pid, + #else + 0, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE) + ut.ut_type, + #else + 0, + #endif + #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV) + (struct timespec) { .tv_sec = ut.ut_tv.tv_sec, .tv_nsec = ut.ut_tv.tv_usec * 1000 }, + #else + (struct timespec) { .tv_sec = ut.ut_time, .tv_nsec = 0 }, + #endif + #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_SESSION : HAVE_STRUCT_UTMP_UT_SESSION) + ut.ut_session, + #else + 0, + #endif + UT_EXIT_E_TERMINATION (&ut), UT_EXIT_E_EXIT (&ut) + ); } - saved_errno = ferror (f) ? errno : 0; + int saved_errno = ferror (f) ? errno : 0; if (fclose (f) != 0) saved_errno = errno; if (saved_errno != 0) { - free (utmp); + free (a.utmp); errno = saved_errno; return -1; } - *n_entries = n_read; - *utmp_buf = utmp; + a = finish_utmp (a); + + *n_entries = a.filled; + *utmp_buf = a.utmp; return 0; } diff --git a/lib/readutmp.h b/lib/readutmp.h index 043ae6df16..1ddb617b28 100644 --- a/lib/readutmp.h +++ b/lib/readutmp.h @@ -22,7 +22,7 @@ /* This file uses _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_RETURNS_NONNULL, HAVE_UTMP_H, HAVE_UTMPX_H, HAVE_STRUCT_UTMP_*, HAVE_STRUCT_UTMPX_*, - HAVE_UTMPNAME, HAVE_UTMPXNAME, HAVE_DECL_GETUTENT. */ + HAVE_UTMPNAME, HAVE_UTMPXNAME. */ #if !_GL_CONFIG_H_INCLUDED # error "Please include config.h first." #endif @@ -55,8 +55,8 @@ # include <utmpx.h> #endif -#if READUTMP_USE_SYSTEMD || ! (HAVE_UTMPX_H || HAVE_UTMP_H) +/* Type of entries returned by read_utmp on all platforms. */ struct gl_utmp { /* All 'char *' here are of arbitrary length and point to storage @@ -64,20 +64,46 @@ struct gl_utmp char *ut_user; /* User name */ char *ut_id; /* Session ID */ char *ut_line; /* seat / device */ - char *ut_host; /* for remote sessions: user@host or host */ + char *ut_host; /* for remote sessions: user@host or host, + for local sessions: the X11 display :N */ struct timespec ut_ts; /* time */ pid_t ut_pid; /* process ID of ? */ pid_t ut_session; /* process ID of session leader */ short ut_type; /* BOOT_TIME or USER_PROCESS */ + struct { int e_termination; int e_exit; } ut_exit; }; -# define HAVE_GL_UTMP 1 -# define UTMP_STRUCT_NAME gl_utmp -# define UT_TIME_MEMBER(UT) ((UT)->ut_ts.tv_sec) -# define UT_EXIT_E_TERMINATION(UT) 0 -# define UT_EXIT_E_EXIT(UT) 0 +/* The following types, macros, and constants describe the 'struct gl_utmp'. */ +#define UT_USER(UT) ((UT)->ut_user) +#define UT_TIME_MEMBER(UT) ((UT)->ut_ts.tv_sec) +#define UT_PID(UT) ((UT)->ut_pid) +#define UT_TYPE_EQ(UT, V) ((UT)->ut_type == (V)) +#define UT_TYPE_NOT_DEFINED 0 +#define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.e_termination) +#define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.e_exit) -#elif HAVE_UTMPX_H +/* Type of entry returned by read_utmp(). */ +typedef struct gl_utmp STRUCT_UTMP; + +/* Size of the UT_USER (ut) member, or -1 if unbounded. */ +enum { UT_USER_SIZE = -1 }; + +/* Size of the ut->ut_id member, or -1 if unbounded. */ +enum { UT_ID_SIZE = -1 }; + +/* Size of the ut->ut_line member, or -1 if unbounded. */ +enum { UT_LINE_SIZE = -1 }; + +/* Size of the ut->ut_host member, or -1 if unbounded. */ +enum { UT_HOST_SIZE = -1 }; + + +/* When read_utmp accesses a file (as opposed to fetching the information + from systemd), it uses the following low-level types and macros. + Keep them here, rather than moving them into readutmp.c, for backward + compatibility. */ + +#if HAVE_UTMPX_H /* <utmpx.h> defines 'struct utmpx' with the following fields: @@ -102,32 +128,15 @@ struct gl_utmp */ # define UTMP_STRUCT_NAME utmpx -# define UT_TIME_MEMBER(UT) ((UT)->ut_tv.tv_sec) # define SET_UTMP_ENT setutxent # define GET_UTMP_ENT getutxent # define END_UTMP_ENT endutxent -# ifdef HAVE_UTMPXNAME +# ifdef HAVE_UTMPXNAME /* glibc, musl, macOS, NetBSD, Minix, IRIX, Solaris, Cygwin */ # define UTMP_NAME_FUNCTION utmpxname -# elif defined UTXDB_ACTIVE +# elif defined UTXDB_ACTIVE /* FreeBSD */ # define UTMP_NAME_FUNCTION(x) setutxdb (UTXDB_ACTIVE, x) # endif -# if HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION -# define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.e_termination) -# elif HAVE_STRUCT_UTMPX_UT_EXIT_UT_TERMINATION /* OSF/1 */ -# define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.ut_termination) -# else -# define UT_EXIT_E_TERMINATION(UT) 0 -# endif - -# if HAVE_STRUCT_UTMPX_UT_EXIT_E_EXIT -# define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.e_exit) -# elif HAVE_STRUCT_UTMPX_UT_EXIT_UT_EXIT /* OSF/1 */ -# define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.ut_exit) -# else -# define UT_EXIT_E_EXIT(UT) 0 -# endif - #elif HAVE_UTMP_H /* <utmp.h> defines 'struct utmp' with the following fields: @@ -151,143 +160,63 @@ struct gl_utmp ⎣ ut_addr_v6 [u]int[4] glibc, musl, Android */ -# if !HAVE_DECL_GETUTENT - struct utmp *getutent (void); -# endif # define UTMP_STRUCT_NAME utmp -# define UT_TIME_MEMBER(UT) ((UT)->ut_time) # define SET_UTMP_ENT setutent # define GET_UTMP_ENT getutent # define END_UTMP_ENT endutent -# ifdef HAVE_UTMPNAME +# ifdef HAVE_UTMPNAME /* glibc, musl, NetBSD, Minix, AIX, HP-UX, IRIX, Solaris, Cygwin, Android */ # define UTMP_NAME_FUNCTION utmpname # endif -# if HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION -# define UT_EXIT_E_TERMINATION(UT) ((UT)->ut_exit.e_termination) -# else -# define UT_EXIT_E_TERMINATION(UT) 0 -# endif - -# if HAVE_STRUCT_UTMP_UT_EXIT_E_EXIT -# define UT_EXIT_E_EXIT(UT) ((UT)->ut_exit.e_exit) -# else -# define UT_EXIT_E_EXIT(UT) 0 -# endif - #endif -/* Accessor macro for the member named ut_user or ut_name. */ -#if (!HAVE_GL_UTMP \ - && (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_NAME \ - : HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_NAME)) -# define UT_USER(UT) ((UT)->ut_name) -#else -# define UT_USER(UT) ((UT)->ut_user) -#endif - -#define HAVE_STRUCT_XTMP_UT_EXIT \ - (!HAVE_GL_UTMP && (HAVE_STRUCT_UTMP_UT_EXIT || HAVE_STRUCT_UTMPX_UT_EXIT) - +/* Evaluates to 1 if gl_utmp's ut_id field may ever have a non-zero value. */ #define HAVE_STRUCT_XTMP_UT_ID \ - (HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_ID || HAVE_STRUCT_UTMPX_UT_ID) + (READUTMP_USE_SYSTEMD \ + || (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID)) +/* Evaluates to 1 if gl_utmp's ut_pid field may ever have a non-zero value. */ #define HAVE_STRUCT_XTMP_UT_PID \ - (HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_PID || HAVE_STRUCT_UTMPX_UT_PID) + (READUTMP_USE_SYSTEMD \ + || (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_PID : HAVE_STRUCT_UTMP_UT_PID)) +/* Evaluates to 1 if gl_utmp's ut_host field may ever be non-empty. */ #define HAVE_STRUCT_XTMP_UT_HOST \ - (HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_HOST || HAVE_STRUCT_UTMPX_UT_HOST) - -/* Type of entry returned by read_utmp(). */ -typedef struct UTMP_STRUCT_NAME STRUCT_UTMP; - -/* Size of the UT_USER (ut) member, or -1 if unbounded. */ -#if HAVE_GL_UTMP -enum { UT_USER_SIZE = -1 }; -#else -enum { UT_USER_SIZE = sizeof UT_USER ((STRUCT_UTMP *) 0) }; -# define UT_USER_SIZE UT_USER_SIZE -#endif - -/* Size of the ut->ut_id member, or -1 if unbounded. */ -#if HAVE_GL_UTMP -enum { UT_ID_SIZE = -1 }; -#else -# if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_ID : HAVE_STRUCT_UTMP_UT_ID) -enum { UT_ID_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_id) }; -# else -enum { UT_ID_SIZE = 1 }; -# endif -# define UT_ID_SIZE UT_ID_SIZE -#endif - -/* Size of the ut->ut_line member, or -1 if unbounded. */ -#if HAVE_GL_UTMP -enum { UT_LINE_SIZE = -1 }; -#else -enum { UT_LINE_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_line) }; -# define UT_LINE_SIZE UT_LINE_SIZE -#endif - -/* Size of the ut->ut_host member, or -1 if unbounded. */ -#if HAVE_GL_UTMP -enum { UT_HOST_SIZE = -1 }; -#else -enum { UT_HOST_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_host) }; -# define UT_HOST_SIZE UT_HOST_SIZE -#endif - -/* Definition of UTMP_FILE and WTMP_FILE. */ + (READUTMP_USE_SYSTEMD \ + || (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_HOST : HAVE_STRUCT_UTMP_UT_HOST)) +/* Definition of UTMP_FILE. + On glibc systems, UTMP_FILE is "/var/run/utmp". */ #if !defined UTMP_FILE && defined _PATH_UTMP # define UTMP_FILE _PATH_UTMP #endif - -#if !defined WTMP_FILE && defined _PATH_WTMP -# define WTMP_FILE _PATH_WTMP -#endif - #ifdef UTMPX_FILE /* Solaris, SysVr4 */ # undef UTMP_FILE # define UTMP_FILE UTMPX_FILE #endif +#ifndef UTMP_FILE +# define UTMP_FILE "/etc/utmp" +#endif +/* Definition of WTMP_FILE. + On glibc systems, UTMP_FILE is "/var/log/wtmp". */ +#if !defined WTMP_FILE && defined _PATH_WTMP +# define WTMP_FILE _PATH_WTMP +#endif #ifdef WTMPX_FILE /* Solaris, SysVr4 */ # undef WTMP_FILE # define WTMP_FILE WTMPX_FILE #endif - -#ifndef UTMP_FILE -# define UTMP_FILE "/etc/utmp" -#endif - #ifndef WTMP_FILE # define WTMP_FILE "/etc/wtmp" #endif -/* Accessor macro for the member named ut_pid. */ -#if HAVE_STRUCT_XTMP_UT_PID -# define UT_PID(UT) ((UT)->ut_pid) -#else -# define UT_PID(UT) 0 -#endif - -/* Accessor macros for the member named ut_type. */ - -#if HAVE_GL_UTMP || HAVE_STRUCT_UTMP_UT_TYPE || HAVE_STRUCT_UTMPX_UT_TYPE -# define UT_TYPE_EQ(UT, V) ((UT)->ut_type == (V)) -# define UT_TYPE_NOT_DEFINED 0 -#else -# define UT_TYPE_EQ(UT, V) 0 -# define UT_TYPE_NOT_DEFINED 1 -#endif - +/* Macros that test (UT)->ut_type. */ #ifdef BOOT_TIME # define UT_TYPE_BOOT_TIME(UT) UT_TYPE_EQ (UT, BOOT_TIME) #else # define UT_TYPE_BOOT_TIME(UT) 0 #endif - #ifdef USER_PROCESS # define UT_TYPE_USER_PROCESS(UT) UT_TYPE_EQ (UT, USER_PROCESS) #else @@ -296,9 +225,9 @@ enum { UT_HOST_SIZE = sizeof (((STRUCT_UTMP *) 0)->ut_host) }; /* Determines whether an entry *UT corresponds to a user process. */ #define IS_USER_PROCESS(UT) \ - (UT_USER (UT)[0] \ - && (UT_TYPE_USER_PROCESS (UT) \ - || (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (UT) != 0))) + (UT_USER (UT)[0] \ + && (UT_TYPE_USER_PROCESS (UT) \ + || (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (UT) != 0))) /* Define if read_utmp is not just a dummy. */ #if READUTMP_USE_SYSTEMD || HAVE_UTMPX_H || HAVE_UTMP_H @@ -312,7 +241,7 @@ enum READ_UTMP_USER_PROCESS = 2 }; -/* Return a copy of UT_USER (UT), without trailing spaces, +/* Return a copy of (UT)->ut_user, without trailing spaces, as a freshly allocated string. */ char *extract_trimmed_name (const STRUCT_UTMP *ut) _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE diff --git a/m4/readutmp.m4 b/m4/readutmp.m4 index a4b1cb4642..6ba5b2e225 100644 --- a/m4/readutmp.m4 +++ b/m4/readutmp.m4 @@ -1,4 +1,4 @@ -# readutmp.m4 serial 22 +# readutmp.m4 serial 23 dnl Copyright (C) 2002-2023 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -78,10 +78,13 @@ AC_DEFUN([gl_READUTMP] AC_CHECK_MEMBERS([struct utmp.ut_type],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmpx.ut_pid],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmp.ut_pid],,,[$utmp_includes]) + AC_CHECK_MEMBERS([struct utmp.ut_tv],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmpx.ut_host],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmp.ut_host],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmpx.ut_id],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmp.ut_id],,,[$utmp_includes]) + AC_CHECK_MEMBERS([struct utmpx.ut_session],,,[$utmp_includes]) + AC_CHECK_MEMBERS([struct utmp.ut_session],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmpx.ut_exit],,,[$utmp_includes]) AC_CHECK_MEMBERS([struct utmp.ut_exit],,,[$utmp_includes]) -- 2.34.1
>From 9949868ca1fdc6acd45dde3dae946084775f0f5f Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Tue, 8 Aug 2023 18:56:39 +0200 Subject: [PATCH] maint: Simplify after gnulib changed All of UT_USER_SIZE, UT_ID_SIZE, UT_LINE_SIZE, UT_HOST_SIZE are now -1. * src/pinky.c (print_entry): Remove code for bounded-length ut_line, ut_user, ut_host. (scan_entries): Remove code for bounded-length ut_user. * src/who.c (print_line): Remove userlen, linelen arguments. (print_user): Remove code for bounded-length ut_line, ut_user, ut_host. (make_id_equals_comment): Remove code for bounded-length ut_id. (print_boottime, print_deadprocs, print_login, print_initspawn, print_clockchange, print_runlevel, print_heading): Update print_line invocations. (scan_entries): Remove code for bounded-length ut_line. --- src/pinky.c | 26 +++++--------------------- src/who.c | 45 +++++++++++++++++---------------------------- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/src/pinky.c b/src/pinky.c index 38ceccbea..1429dd073 100644 --- a/src/pinky.c +++ b/src/pinky.c @@ -203,15 +203,10 @@ print_entry (const STRUCT_UTMP *utmp_ent) time_t last_change; char mesg; -#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 int dirfd; if (IS_ABSOLUTE_FILE_NAME (line)) @@ -239,19 +234,14 @@ print_entry (const STRUCT_UTMP *utmp_ent) last_change = 0; } - if (0 <= UT_USER_SIZE || strnlen (UT_USER (utmp_ent), 8) < 8) - printf ("%-8.*s", UT_USER_SIZE, UT_USER (utmp_ent)); + if (strnlen (UT_USER (utmp_ent), 8) < 8) + printf ("%-8s", UT_USER (utmp_ent)); else fputs (UT_USER (utmp_ent), stdout); if (include_fullname) { -#ifdef UT_USER_SIZE - char name[UT_USER_SIZE + 1]; - stzncpy (name, UT_USER (utmp_ent), UT_USER_SIZE); -#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. */ @@ -272,8 +262,8 @@ print_entry (const STRUCT_UTMP *utmp_ent) 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); + if (strnlen (utmp_ent->ut_line, 8) < 8) + printf ("%-8s", utmp_ent->ut_line); else fputs (utmp_ent->ut_line, stdout); @@ -293,13 +283,7 @@ print_entry (const STRUCT_UTMP *utmp_ent) { char *host = nullptr; char *display = nullptr; - -# 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, ':'); @@ -475,7 +459,7 @@ scan_entries (idx_t n, const STRUCT_UTMP *utmp_buf, if (argc_names) { for (int i = 0; i < argc_names; i++) - if (STREQ_LEN (UT_USER (utmp_buf), argv_names[i], UT_USER_SIZE)) + if (STREQ (UT_USER (utmp_buf), argv_names[i])) { print_entry (utmp_buf); break; diff --git a/src/who.c b/src/who.c index 0e94d3c83..27a7904e1 100644 --- a/src/who.c +++ b/src/who.c @@ -238,8 +238,8 @@ time_string (const STRUCT_UTMP *utmp_ent) will need tweaking if any of the localization stuff is done, or for 64 bit pids, etc. */ static void -print_line (int userlen, char const *user, const char state, - int linelen, char const *line, +print_line (char const *user, const char state, + char const *line, char const *time_str, char const *idle, char const *pid, char const *comment, char const *exitstr) { @@ -269,18 +269,18 @@ print_line (int userlen, char const *user, const char state, *x_exitstr = '\0'; err = asprintf (&buf, - "%-8.*s" + "%-8s" "%s" - " %-12.*s" + " %-12s" " %-*s" "%s" "%s" " %-8s" "%s" , - userlen, user ? user : " .", + user ? user : " .", include_mesg ? mesg : "", - linelen, line, + line, time_format_width, time_str, x_idle, @@ -339,15 +339,10 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) static idx_t hostlen; #endif -#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 int dirfd; if (IS_ABSOLUTE_FILE_NAME (line)) @@ -385,13 +380,7 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) { char *host = nullptr; char *display = nullptr; - -# 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, ':'); @@ -445,8 +434,8 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) } #endif - print_line (UT_USER_SIZE, UT_USER (utmp_ent), mesg, - UT_LINE_SIZE, utmp_ent->ut_line, + print_line (UT_USER (utmp_ent), mesg, + utmp_ent->ut_line, time_string (utmp_ent), idlestr, pidstr, hoststr ? hoststr : "", ""); } @@ -454,7 +443,7 @@ print_user (const STRUCT_UTMP *utmp_ent, time_t boottime) static void print_boottime (const STRUCT_UTMP *utmp_ent) { - print_line (-1, "", ' ', -1, _("system boot"), + print_line ("", ' ', _("system boot"), time_string (utmp_ent), "", "", "", ""); } @@ -462,7 +451,7 @@ static char * make_id_equals_comment (STRUCT_UTMP const *utmp_ent) { char const *id = UT_ID (utmp_ent); - idx_t idlen = strnlen (id, UT_ID_SIZE); + idx_t idlen = strlen (id); char const *prefix = _("id="); idx_t prefixlen = strlen (prefix); char *comment = xmalloc (prefixlen + idlen + 1); @@ -490,7 +479,7 @@ print_deadprocs (const STRUCT_UTMP *utmp_ent) /* FIXME: add idle time? */ - print_line (-1, "", ' ', UT_LINE_SIZE, utmp_ent->ut_line, + print_line ("", ' ', utmp_ent->ut_line, time_string (utmp_ent), "", pidstr, comment, exitstr); free (comment); } @@ -503,7 +492,7 @@ print_login (const STRUCT_UTMP *utmp_ent) /* FIXME: add idle time? */ - print_line (-1, _("LOGIN"), ' ', UT_LINE_SIZE, utmp_ent->ut_line, + print_line (_("LOGIN"), ' ', utmp_ent->ut_line, time_string (utmp_ent), "", pidstr, comment, ""); free (comment); } @@ -514,7 +503,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, "", ' ', UT_LINE_SIZE, utmp_ent->ut_line, + print_line ("", ' ', utmp_ent->ut_line, time_string (utmp_ent), "", pidstr, comment, ""); free (comment); } @@ -523,7 +512,7 @@ static void print_clockchange (const STRUCT_UTMP *utmp_ent) { /* FIXME: handle NEW_TIME & OLD_TIME both */ - print_line (-1, "", ' ', -1, _("clock change"), + print_line ("", ' ', _("clock change"), time_string (utmp_ent), "", "", "", ""); } @@ -542,7 +531,7 @@ print_runlevel (const STRUCT_UTMP *utmp_ent) comment = xmalloc (strlen (_("last=")) + 2); sprintf (comment, "%s%c", _("last="), (last == 'N') ? 'S' : last); - print_line (-1, "", ' ', -1, runlevline, time_string (utmp_ent), + print_line ("", ' ', runlevline, time_string (utmp_ent), "", "", c_isprint (last) ? comment : "", ""); return; @@ -577,7 +566,7 @@ list_entries_who (idx_t n, const STRUCT_UTMP *utmp_buf) static void print_heading (void) { - print_line (-1, _("NAME"), ' ', -1, _("LINE"), _("TIME"), _("IDLE"), + print_line (_("NAME"), ' ', _("LINE"), _("TIME"), _("IDLE"), _("PID"), _("COMMENT"), _("EXIT")); } @@ -609,7 +598,7 @@ scan_entries (idx_t n, const STRUCT_UTMP *utmp_buf) while (n--) { if (!my_line_only - || STREQ_LEN (ttyname_b, utmp_buf->ut_line, UT_LINE_SIZE)) + || STREQ (ttyname_b, utmp_buf->ut_line)) { if (need_users && IS_USER_PROCESS (utmp_buf)) print_user (utmp_buf, boottime); -- 2.34.1