Thanks for the further comments. I installed your patch, along with the
attached additional patches. The first makes 'uptime' a bit more
resilient in the case of utmp and other failures, and the second adds
NEWS items as per your comments.From 1ea34cbf6a235f2436a3265ab9ded6f04748051e Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Tue, 15 Aug 2023 14:00:54 -0700
Subject: [PATCH 1/2] uptime: be more generous about read_utmp failure
* src/uptime.c (print_uptime): Check for overflow
when computing uptime. Use C99-style decl after statements.
Do not let an idx_t value go negative.
(print_uptime, uptime): Be more generous about read_utmp failures,
or when read_utmp does not report the boot time. Instead of
failing, warn but keep going, printing the information that we did
get, and then exit with nonzero status.
(print_uptime): Return the desired exit status. Caller changed.
---
src/uptime.c | 77 +++++++++++++++++++++++++++++++---------------------
1 file changed, 46 insertions(+), 31 deletions(-)
diff --git a/src/uptime.c b/src/uptime.c
index 813d29430..928829dfc 100644
--- a/src/uptime.c
+++ b/src/uptime.c
@@ -17,9 +17,11 @@
/* Created by hacking who.c by Kaveh Ghazi gh...@caip.rutgers.edu. */
#include <config.h>
-#include <stdio.h>
+#include <stdckdint.h>
+#include <stdio.h>
#include <sys/types.h>
+
#include "system.h"
#if HAVE_SYSCTL && HAVE_SYS_SYSCTL_H && ! defined __GLIBC__
@@ -43,19 +45,11 @@
proper_name ("David MacKenzie"), \
proper_name ("Kaveh Ghazi")
-static void
-print_uptime (idx_t n, struct gl_utmp const *this)
+static int
+print_uptime (idx_t n, struct gl_utmp const *utmp_buf)
{
- idx_t entries = 0;
+ int status = EXIT_SUCCESS;
time_t boot_time = 0;
- time_t time_now;
- time_t uptime;
- intmax_t updays;
- int uphours;
- int upmins;
- struct tm *tmn;
- double avg[3];
- int loads;
#if HAVE_SYSCTL && ! defined __GLIBC__ \
&& defined CTL_KERN && defined KERN_BOOTTIME
@@ -81,35 +75,47 @@ print_uptime (idx_t n, struct gl_utmp const *this)
/* Loop through all the utmp entries we just read and count up the valid
ones, also in the process possibly gleaning boottime. */
- while (n--)
+ idx_t entries = 0;
+ for (idx_t i = 0; i < n; i++)
{
+ struct gl_utmp const *this = &utmp_buf[i];
entries += IS_USER_PROCESS (this);
if (UT_TYPE_BOOT_TIME (this))
boot_time = this->ut_ts.tv_sec;
- ++this;
}
/* The gnulib module 'readutmp' is supposed to provide a BOOT_TIME entry
on all platforms. */
if (boot_time == 0)
- error (EXIT_FAILURE, errno, _("couldn't get boot time"));
-
- time_now = time (nullptr);
- uptime = time_now - boot_time;
- updays = uptime / 86400;
- uphours = uptime % 86400 / 3600;
- upmins = uptime % 86400 % 3600 / 60;
- tmn = localtime (&time_now);
+ {
+ error (0, errno, _("couldn't get boot time"));
+ status = EXIT_FAILURE;
+ }
+
+ time_t time_now = time (nullptr);
+ struct tm *tmn = time_now == (time_t) -1 ? nullptr : localtime (&time_now);
/* procps' version of uptime also prints the seconds field, but
previous versions of coreutils don't. */
if (tmn)
/* TRANSLATORS: This prints the current clock time. */
fprintftime (stdout, _(" %H:%M:%S "), tmn, 0, 0);
else
- printf (_(" ??:???? "));
- if (uptime == (time_t) -1)
- printf (_("up ???? days ??:??, "));
+ {
+ printf (_(" ??:???? "));
+ status = EXIT_FAILURE;
+ }
+
+ intmax_t uptime;
+ if (time_now == (time_t) -1 || boot_time == 0
+ || ckd_sub (&uptime, time_now, boot_time) || uptime < 0)
+ {
+ printf (_("up ???? days ??:??, "));
+ status = EXIT_FAILURE;
+ }
else
{
+ intmax_t updays = uptime / 86400;
+ int uphours = uptime % 86400 / 3600;
+ int upmins = uptime % 86400 % 3600 / 60;
if (0 < updays)
printf (ngettext ("up %"PRIdMAX" day %2d:%02d, ",
"up %"PRIdMAX" days %2d:%02d, ",
@@ -118,10 +124,12 @@ print_uptime (idx_t n, struct gl_utmp const *this)
else
printf (_("up %2d:%02d, "), uphours, upmins);
}
+
printf (ngettext ("%td user", "%td users", select_plural (entries)),
entries);
- loads = getloadavg (avg, 3);
+ double avg[3];
+ int loads = getloadavg (avg, 3);
if (loads == -1)
putchar ('\n');
@@ -136,6 +144,8 @@ print_uptime (idx_t n, struct gl_utmp const *this)
if (loads > 0)
putchar ('\n');
}
+
+ return status;
}
/* Display the system uptime and the number of users on the system,
@@ -147,12 +157,17 @@ uptime (char const *filename, int options)
{
idx_t n_users;
struct gl_utmp *utmp_buf;
- if (read_utmp (filename, &n_users, &utmp_buf, options) != 0)
- error (EXIT_FAILURE, errno, "%s", quotef (filename));
-
- print_uptime (n_users, utmp_buf);
+ int read_utmp_status = (read_utmp (filename, &n_users, &utmp_buf, options) < 0
+ ? EXIT_FAILURE : EXIT_SUCCESS);
+ if (read_utmp_status != EXIT_SUCCESS)
+ {
+ error (0, errno, "%s", quotef (filename));
+ n_users = 0;
+ utmp_buf = nullptr;
+ }
- exit (EXIT_SUCCESS);
+ int print_uptime_status = print_uptime (n_users, utmp_buf);
+ exit (MAX (read_utmp_status, print_uptime_status));
}
void
--
2.39.2
From b1b67827b2e288f1bd8e220adce4333faf6f0cd2 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Tue, 15 Aug 2023 14:11:38 -0700
Subject: [PATCH 2/2] maint: update uptime NEWS
* NEWS: Update as per Bruno Haible <https://bugs.gnu.org/65255#14>.
---
NEWS | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index 3a06f4b30..909dcacd4 100644
--- a/NEWS
+++ b/NEWS
@@ -51,7 +51,10 @@ GNU coreutils NEWS -*- outline -*-
erroneously, especially with large input files with no separators.
[This bug was present in "the beginning".]
- 'uptime' no longer incorrectly prints "0 users" on OpenBSD.
+ 'uptime' no longer incorrectly prints "0 users" on OpenBSD,
+ and is being built again on FreeBSD and Haiku.
+ [bugs introduced in coreutils-9.2]
+
[bug introduced in coreutils-9.2]
'wc -l' and 'cksum' no longer crash with an "Illegal instruction" error
@@ -91,6 +94,13 @@ GNU coreutils NEWS -*- outline -*-
tac now falls back to '/tmp' if a configured $TMPDIR is unavailable.
+ 'who -a' now displays the boot time on Alpine Linux, OpenBSD,
+ Cygwin, Haiku, and some Android distributions
+
+ 'uptime' now succeeds on some Android distributions, and now counts
+ VM saved/sleep time on GNU (Linux, Hurd, kFreeBSD), NetBSD, OpenBSD,
+ Minux, and Cygwin.
+
On GNU/Linux platforms where utmp-format files have 32-bit timestamps,
pinky, uptime, and who can now work for times after the year 2038,
so long as systemd is installed, you configure with a new, experimental
--
2.39.2