Bug 1215548

Summary: new coreutils-systemd breaks "uptime"
Product: [openSUSE] openSUSE Tumbleweed Reporter: Stefan Seyfried <seife>
Component: BasesystemAssignee: Bernhard Voelker <mail>
Status: NEW --- QA Contact: E-mail List <qa-bugs>
Severity: Normal    
Priority: P5 - None CC: emiliano.langella, kukuk
Version: Current   
Target Milestone: ---   
Hardware: aarch64   
OS: Other   
Whiteboard:
Found By: --- Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---

Description Stefan Seyfried 2023-09-21 06:31:22 UTC
The new coreutils-systemd's "uptime" command reports wrong values:

wrong, newer system:
raspi4c:~ # grep VERSION_ID /etc/os-release 
VERSION_ID="20230910"
raspi4c:~ # rpm -qf `which uptime`
coreutils-systemd-9.4-1.1.aarch64
raspi4c:~ # uptime
 06:28:33  up 4 days 21:40,  1 user,  load average: 0.16, 0.16, 0.11
raspi4c:~ # cat /proc/uptime
136079.24 225710.69

correct, older system:
raspi4a:~ # grep VERSION_ID /etc/os-release 
VERSION_ID="20230904"
raspi4a:~ # rpm -qf `which uptime`
coreutils-9.3-1.2.aarch64
raspi4a:~ # uptime
 06:28:51  up 1 day 13:48,  1 user,  load average: 0.09, 0.16, 0.12
raspi4a:~ # cat /proc/uptime 
136093.86 92370.61

These are raspberry pi4's which don't have a realtime clock, so the system clock is wrong on boot.

The broken version does not consult the kernel:
raspi4c:~ # strace -e file uptime
execve("/usr/bin/uptime", ["uptime"], 0xffffe61bb560 /* 48 vars */) = 0
faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=26215, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2515928, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2940, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/locale/de_DE.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=357744, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib64/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=27012, ...}, AT_EMPTY_PATH) = 0
faccessat(AT_FDCWD, "/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x1), ...}, AT_EMPTY_PATH) = 0
 06:30:05  up 4 days 21:41,  1 user,  load average: 0.20, 0.18, 0.11
+++ exited with 0 +++

The working version does:
raspi4a:~ # strace -e file uptime
execve("/usr/bin/uptime", ["uptime"], 0xffffe5952d00 /* 48 vars */) = 0
faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=23327, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2515928, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=2940, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib/locale/de_DE.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=357744, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/usr/lib64/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=27012, ...}, AT_EMPTY_PATH) = 0
faccessat(AT_FDCWD, "/var/run/utmpx", F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/var/run/utmp", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/proc/uptime", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x2), ...}, AT_EMPTY_PATH) = 0
 06:30:40  up 1 day 13:49,  1 user,  load average: 0.10, 0.15, 0.12
+++ exited with 0 +++
Comment 1 Thorsten Kukuk 2023-09-25 07:54:45 UTC
That's sounds like the "there is no reliable way to get the kernel boot time" workarounds in gnulib:

For /proc/uptime:
"Notice:
This module is deprecated because the "uptime" that it helps finding does
not include VM saved/sleep time. Use the module 'boot-time' instead."

And the new boot-time uses timestamps on the filesystem, which of course fails with hw having no RTC.
Comment 2 Stefan Seyfried 2023-09-25 18:18:45 UTC
for more than 20 years /proc/uptime was good enough.
I don't care about the boottime, but uptime certainly does not include the time the machine was suspended, so /proc/uptime is a reliable source of -- uptime! :-)

Worked around for now with "ln -s /usr/bin/busybox /usr/local/bin/uptime", as /usr/local/bin fortunately is in $PATH before /usr/bin and busybox uptime works just fine.
Comment 3 Thorsten Kukuk 2023-09-26 12:30:12 UTC
(In reply to Stefan Seyfried from comment #2)
> for more than 20 years /proc/uptime was good enough.
> I don't care about the boottime, but uptime certainly does not include the
> time the machine was suspended, so /proc/uptime is a reliable source of --
> uptime! :-)

I agree and all other uptime implementations I checked (e.g. busybox and procps) see it in the same way. But since this was an upstream gnulib/coreutils decision and I don't know the upstream bug reports and reasons why they changed it, the best way is to discuss that with them.
Comment 4 Stefan Seyfried 2023-09-29 05:51:20 UTC
OK, discussing with GNU coreutils maintainers looks rather futile.
How about we provide uptime via update-alternatives from different sources (busybox, procps, coreutils)?

I can in fact uninstall coreutils-systemd, but I cannot install busybox-coreutils because of...

 Problem: the to be installed busybox-coreutils-1.36.1-30.1.noarch conflicts with 'coreutils' provided by the installed coreutils-9.4-1.2.x86_64

So maybe we can make this co-installable? Or create a busybox-uptime and a coreutils-uptime which are conflicting over only the uptime job?
Comment 5 Bernhard Voelker 2024-02-07 07:47:59 UTC
New uptime(1) calls sysinfo(2):

$ strace -e sysinfo uptime         
sysinfo({uptime=1088088, loads=[12800, 20800, 30528], totalram=20879904768, freeram=11266564096, sharedram=1854656512, bufferram=479453184, totalswap=2147479552, freeswap=2147479552, procs=946, totalhigh=0, freehigh=0, mem_unit=1}) = 0
 08:44:26  up 12 days 14:14,  2 users,  load average: 0.20, 0.32, 0.47
+++ exited with 0 +++

So the question is why that yields odd values on pi4.