1*cf5a6c84SAndroid Build Coastguard Worker /* hwclock.c - get and set the hwclock
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2014 Bilal Qureshi <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * No standard, but see Documentation/rtc.txt in the linux kernel source.
6*cf5a6c84SAndroid Build Coastguard Worker *
7*cf5a6c84SAndroid Build Coastguard Worker * TODO: get/set subsecond time
8*cf5a6c84SAndroid Build Coastguard Worker USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_SBIN))
9*cf5a6c84SAndroid Build Coastguard Worker
10*cf5a6c84SAndroid Build Coastguard Worker config HWCLOCK
11*cf5a6c84SAndroid Build Coastguard Worker bool "hwclock"
12*cf5a6c84SAndroid Build Coastguard Worker default y
13*cf5a6c84SAndroid Build Coastguard Worker help
14*cf5a6c84SAndroid Build Coastguard Worker usage: hwclock [-rswtlu] [-f FILE]
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker Get/set the hardware clock. Default is hwclock -ruf /dev/rtc0
17*cf5a6c84SAndroid Build Coastguard Worker
18*cf5a6c84SAndroid Build Coastguard Worker -f Use specified device FILE instead of /dev/rtc0 (--rtc)
19*cf5a6c84SAndroid Build Coastguard Worker -l Hardware clock uses localtime (--localtime)
20*cf5a6c84SAndroid Build Coastguard Worker -r Show hardware clock time (--show)
21*cf5a6c84SAndroid Build Coastguard Worker -s Set system time from hardware clock (--hctosys)
22*cf5a6c84SAndroid Build Coastguard Worker -t Inform kernel of non-UTC clock's timezone so it returns UTC (--systz)
23*cf5a6c84SAndroid Build Coastguard Worker -u Hardware clock uses UTC (--utc)
24*cf5a6c84SAndroid Build Coastguard Worker -w Set hardware clock from system time (--systohc)
25*cf5a6c84SAndroid Build Coastguard Worker */
26*cf5a6c84SAndroid Build Coastguard Worker
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker // Bug workaround for musl commit 5a105f19b5aa which removed a symbol the
29*cf5a6c84SAndroid Build Coastguard Worker // kernel headers have. (Can't copy it here, varies wildly by architecture.)
30*cf5a6c84SAndroid Build Coastguard Worker #if __has_include(<asm/unistd.h>)
31*cf5a6c84SAndroid Build Coastguard Worker #include <asm/unistd.h>
32*cf5a6c84SAndroid Build Coastguard Worker #endif
33*cf5a6c84SAndroid Build Coastguard Worker
34*cf5a6c84SAndroid Build Coastguard Worker #define FOR_hwclock
35*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
36*cf5a6c84SAndroid Build Coastguard Worker #include <linux/rtc.h>
37*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(char * f;)38*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
39*cf5a6c84SAndroid Build Coastguard Worker char *f;
40*cf5a6c84SAndroid Build Coastguard Worker )
41*cf5a6c84SAndroid Build Coastguard Worker
42*cf5a6c84SAndroid Build Coastguard Worker // Bug workaround for musl commit 2c2c3605d3b3 which rewrote the syscall
43*cf5a6c84SAndroid Build Coastguard Worker // wrapper to not use the syscall, which is the only way to set kernel's sys_tz
44*cf5a6c84SAndroid Build Coastguard Worker #ifdef _NR_settimeofday
45*cf5a6c84SAndroid Build Coastguard Worker #define settimeofday(x, tz) syscall(__NR_settimeofday, (void *)0, (void *)tz)
46*cf5a6c84SAndroid Build Coastguard Worker #else
47*cf5a6c84SAndroid Build Coastguard Worker #define settimeofday(x, tz) ((tz)->tz_minuteswest = 0)
48*cf5a6c84SAndroid Build Coastguard Worker #endif
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker void hwclock_main()
51*cf5a6c84SAndroid Build Coastguard Worker {
52*cf5a6c84SAndroid Build Coastguard Worker struct timezone tz = {0};
53*cf5a6c84SAndroid Build Coastguard Worker struct timespec ts = {0};
54*cf5a6c84SAndroid Build Coastguard Worker struct tm tm;
55*cf5a6c84SAndroid Build Coastguard Worker int fd = -1;
56*cf5a6c84SAndroid Build Coastguard Worker
57*cf5a6c84SAndroid Build Coastguard Worker // -t without -u implies -l
58*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(t)&&!FLAG(u)) toys.optflags |= FLAG_l;
59*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(l)) {
60*cf5a6c84SAndroid Build Coastguard Worker // sets globals timezone and daylight from sys/time.h
61*cf5a6c84SAndroid Build Coastguard Worker // Handle dst adjustment ourselves. (Rebooting during dst transition is
62*cf5a6c84SAndroid Build Coastguard Worker // just conceptually unpleasant, linux uses UTC for a reason.)
63*cf5a6c84SAndroid Build Coastguard Worker tzset();
64*cf5a6c84SAndroid Build Coastguard Worker tz.tz_minuteswest = timezone/60 - 60*daylight;
65*cf5a6c84SAndroid Build Coastguard Worker }
66*cf5a6c84SAndroid Build Coastguard Worker
67*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(t)) {
68*cf5a6c84SAndroid Build Coastguard Worker fd = xopen(TT.f ? : "/dev/rtc0", O_WRONLY*FLAG(w));
69*cf5a6c84SAndroid Build Coastguard Worker
70*cf5a6c84SAndroid Build Coastguard Worker // Get current time in seconds from rtc device.
71*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(w)) {
72*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, RTC_RD_TIME, &tm);
73*cf5a6c84SAndroid Build Coastguard Worker ts.tv_sec = xmktime(&tm, !FLAG(l));
74*cf5a6c84SAndroid Build Coastguard Worker }
75*cf5a6c84SAndroid Build Coastguard Worker }
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(w) || FLAG(t)) {
78*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(w)) {
79*cf5a6c84SAndroid Build Coastguard Worker if (clock_gettime(CLOCK_REALTIME, &ts)) perror_exit("clock_gettime");
80*cf5a6c84SAndroid Build Coastguard Worker if (!(FLAG(l) ? localtime_r : gmtime_r)(&ts.tv_sec, &tm))
81*cf5a6c84SAndroid Build Coastguard Worker error_exit("%s failed", FLAG(l) ? "localtime_r" : "gmtime_r");
82*cf5a6c84SAndroid Build Coastguard Worker xioctl(fd, RTC_SET_TIME, &tm);
83*cf5a6c84SAndroid Build Coastguard Worker }
84*cf5a6c84SAndroid Build Coastguard Worker if (settimeofday(0, &tz)) perror_exit("settimeofday");
85*cf5a6c84SAndroid Build Coastguard Worker } else if (FLAG(s)) {
86*cf5a6c84SAndroid Build Coastguard Worker if (clock_settime(CLOCK_REALTIME, &ts)) perror_exit("clock_settime");
87*cf5a6c84SAndroid Build Coastguard Worker } else {
88*cf5a6c84SAndroid Build Coastguard Worker strftime(toybuf, sizeof(toybuf), "%F %T%z", &tm);
89*cf5a6c84SAndroid Build Coastguard Worker xputs(toybuf);
90*cf5a6c84SAndroid Build Coastguard Worker }
91*cf5a6c84SAndroid Build Coastguard Worker
92*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) xclose(fd);
93*cf5a6c84SAndroid Build Coastguard Worker }
94