aboutsummaryrefslogtreecommitdiff
path: root/toys/other/hwclock.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/other/hwclock.c')
-rw-r--r--toys/other/hwclock.c81
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);
}