diff options
Diffstat (limited to 'toys/other/hwclock.c')
-rw-r--r-- | toys/other/hwclock.c | 81 |
1 files changed, 41 insertions, 40 deletions
diff --git a/toys/other/hwclock.c b/toys/other/hwclock.c index 4087ec93..5186a2d1 100644 --- a/toys/other/hwclock.c +++ b/toys/other/hwclock.c @@ -2,27 +2,35 @@ * * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com> * - * No standard, but see Documentation/rtc.txt in the linux kernel source.. + * No standard, but see Documentation/rtc.txt in the linux kernel source. * + * TODO: get/set subsecond time USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_SBIN)) config HWCLOCK bool "hwclock" default y help - usage: hwclock [-rswtluf] + usage: hwclock [-rswtlu] [-f FILE] - Get/set the hardware clock. + Get/set the hardware clock. Default is hwclock -ruf /dev/rtc0 - -f FILE Use specified device file instead of /dev/rtc0 (--rtc) + -f 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) - -t Set the system time based on the current timezone (--systz) + -t Inform kernel of non-UTC clock's timezone so it returns UTC (--systz) -u Hardware clock uses UTC (--utc) -w Set hardware clock from system time (--systohc) */ + +// Bug workaround for musl commit 5a105f19b5aa which removed a symbol the +// kernel headers have. (Can't copy it here, varies wildly by architecture.) +#if __has_include(<asm/unistd.h>) +#include <asm/unistd.h> +#endif + #define FOR_hwclock #include "toys.h" #include <linux/rtc.h> @@ -31,58 +39,51 @@ GLOBALS( char *f; ) +// Bug workaround for musl commit 2c2c3605d3b3 which rewrote the syscall +// wrapper to not use the syscall, which is the only way to set kernel's sys_tz +#define settimeofday(x, tz) syscall(__NR_settimeofday, (void *)0, (void *)tz) + void hwclock_main() { - struct timezone tzone; - struct timeval timeval; + struct timezone tz = {0}; + struct timespec ts = {0}; struct tm tm; - int fd = -1, utc; + int fd = -1; - if (FLAG(u)) utc = 1; - else if (FLAG(l)) utc = 0; - else utc = !readfile("/etc/adjtime", toybuf, sizeof(toybuf)) || - !!strstr(toybuf, "UTC"); + // -t without -u implies -l + if (FLAG(t)&&!FLAG(u)) toys.optflags |= FLAG_l; + if (FLAG(l)) { + // sets globals timezone and daylight from sys/time.h + // Handle dst adjustment ourselves. (Rebooting during dst transition is + // just conceptually unpleasant, linux uses UTC for a reason.) + tzset(); + tz.tz_minuteswest = timezone/60 - 60*daylight; + } if (!FLAG(t)) { - if (!TT.f) TT.f = "/dev/rtc0"; - fd = xopen(TT.f, O_WRONLY*FLAG(w)); + fd = xopen(TT.f ? : "/dev/rtc0", O_WRONLY*FLAG(w)); - // Get current time in seconds from rtc device. TODO: get subsecond time + // Get current time in seconds from rtc device. if (!FLAG(w)) { xioctl(fd, RTC_RD_TIME, &tm); - timeval.tv_sec = xmktime(&tm, utc); - timeval.tv_usec = 0; // TODO: fixit + ts.tv_sec = xmktime(&tm, !FLAG(l)); } } if (FLAG(w) || FLAG(t)) { - if (gettimeofday(&timeval, 0)) perror_exit("gettimeofday failed"); - if (!(utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm)) - error_exit(utc ? "gmtime_r failed" : "localtime_r failed"); - } - - if (FLAG(w)) { - /* The value of tm_isdst is positive if daylight saving time is in effect, - * zero if it is not and negative if the information is not available. - * TODO: so why isn't this negative...? */ - tm.tm_isdst = 0; - xioctl(fd, RTC_SET_TIME, &tm); + if (FLAG(w)) { + if (clock_gettime(CLOCK_REALTIME, &ts)) perror_exit("clock_gettime"); + if (!(FLAG(l) ? localtime_r : gmtime_r)(&ts.tv_sec, &tm)) + error_exit("%s failed", FLAG(l) ? "localtime_r" : "gmtime_r"); + xioctl(fd, RTC_SET_TIME, &tm); + } + if (settimeofday(0, &tz)) perror_exit("settimeofday"); } else if (FLAG(s)) { - tzone.tz_minuteswest = timezone / 60 - 60 * daylight; - } else if (FLAG(t)) { - // Adjust seconds for timezone and daylight saving time - // extern long timezone is defined in header sys/time.h - tzone.tz_minuteswest = timezone / 60; - if (tm.tm_isdst) tzone.tz_minuteswest -= 60; - if (!utc) timeval.tv_sec += tzone.tz_minuteswest * 60; + if (clock_settime(CLOCK_REALTIME, &ts)) perror_exit("clock_settime"); } else { strftime(toybuf, sizeof(toybuf), "%F %T%z", &tm); xputs(toybuf); } - if (FLAG(t) || FLAG(s)) { - tzone.tz_dsttime = 0; - if (settimeofday(&timeval, &tzone)) perror_exit("settimeofday failed"); - } - xclose(fd); + if (CFG_TOYBOX_FREE) xclose(fd); } |