From 70e2232ce61c87f1dca869107b2998b7a4dfd0d2 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 11 Jun 2020 14:19:34 -0700 Subject: hwclock: just assume /dev/rtc0. (Apologies for the length of this commit message, but it's not entirely clear how we arrived at our present state, and right now all three of toybox, busybox, and util-linux differ from each other. And it took a week of arguments behind the scenes to agree on what we thought was the right behavior, which seemed worth capturing for posterity.) This reverts my change ef0546d4f536f42a57af4c32bd37f7fd752d10c2 from 2015. The commit message back then claimed: For systems using /dev/rtcN, /dev/rtc0 isn't necessarily the RTC that's used to provide the system time at boot time. We need to search for the RTC whose /sys/class/rtc/rtcN/hctosys contains "1". A few things to note here: 1. I can't find any historical motivation for this change. There's no bug, there's no internal email thread, and I can't even find anything referring to devices using anything other than /dev/rtc0. 2. It turns out (though this wasn't true at the time) that the kernel since 4.19 interprets hctosys as the RTC that *did* set the clock, not the RTC that *should* set the clock. 3. That's not an academic difference. If you have a cheap RTC that isn't battery-backed, or you have an RTC whose battery died, and you're using Linux 4.19 or later, you will boot with no RTC having hctosys=1. 4. An actual SoC vendor has hit this in practice. My original toybox patch appears to be equivalent to code in the Android frameworks, which -- under the auspices of the SoC vendor's bug -- I'm about to replace with code that checks "/dev/rtc" first, then "/dev/rtc0", then fails hard. (Strictly, it's this copy of the search that's causing the SoC vendor issues. AFAIK no-one's using hwclock/rtcwake except interactively. And even if they are, Android devices ship with [at least] two copies of toybox, so code/scripts on the vendor partition will continue to run the vendor copy of toybox they were developed against, and a newer toybox elsewhere on the system won't affect them.) All Android devices (and emulators) available to me at the moment use /dev/rtc0, but supporting /dev/rtc gives a workaround for anyone who really insists on using an RTC other than /dev/rtc0. That said, the Generic Kernel Image (GKI) always assumes /dev/rtc0, so going forward /dev/rtc0 is always the right choice. I did consider making toybox hwclock try /dev/rtc, /dev/rtc0, and /dev/misc/rtc -- and even wrote the code for that first -- but strace shows that busybox and util-linux's hwclock implementations differ in the order in which they try these (busybox tries /dev/rtc first, util-linux tries /dev/rtc0 first). Given that util-linux seems like the more canonical precedent, trying /dev/rtc0 and then falling back to /dev/rtc would offer no advantage to Android users (and would seem to be just another stumbling block in getting everyone to a world where /dev/rtc0 is "the" system RTC). Note that rtcwake is unaffected by all this, because the toybox and util-linux implementations both default to only trying /dev/rtc0 already. Bug: https://issuetracker.google.com/158051176 --- toys/other/hwclock.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) (limited to 'toys/other') diff --git a/toys/other/hwclock.c b/toys/other/hwclock.c index 3b3ff690..ba28cc3d 100644 --- a/toys/other/hwclock.c +++ b/toys/other/hwclock.c @@ -14,7 +14,7 @@ config HWCLOCK Get/set the hardware clock. - -f FILE Use specified device file instead of /dev/rtc (--rtc) + -f FILE Use specified device file instead of /dev/rtc0 (--rtc) -l Hardware clock uses localtime (--localtime) -r Show hardware clock time (--show) -s Set system time from hardware clock (--hctosys) @@ -31,29 +31,6 @@ GLOBALS( char *f; ) -static int rtc_find(struct dirtree* node) -{ - FILE *fp; - - if (!node->parent) return DIRTREE_RECURSE; - - sprintf(toybuf, "/sys/class/rtc/%s/hctosys", node->name); - fp = fopen(toybuf, "r"); - if (fp) { - int hctosys = 0, items = fscanf(fp, "%d", &hctosys); - - fclose(fp); - if (items == 1 && hctosys == 1) { - sprintf(toybuf, "/dev/%s", node->name); - TT.f = toybuf; - - return DIRTREE_ABORT; - } - } - - return 0; -} - void hwclock_main() { struct timezone tzone; @@ -69,14 +46,8 @@ void hwclock_main() } if (!FLAG(t)) { - int flag = O_WRONLY*FLAG(w); - - // Open /dev/rtc (if your system has no /dev/rtc symlink, search for it). - if (!TT.f && (fd = open("/dev/rtc", flag)) == -1) { - dirtree_read("/sys/class/rtc", rtc_find); - if (!TT.f) TT.f = "/dev/misc/rtc"; - } - if (fd == -1) fd = xopen(TT.f, flag); + if (!TT.f) TT.f = "/dev/rtc0"; + fd = xopen(TT.f, O_WRONLY*FLAG(w)); // Get current time in seconds from rtc device. todo: get subsecond time if (!FLAG(w)) { -- cgit v1.2.3