aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/hwclock.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/pending/hwclock.c')
-rw-r--r--toys/pending/hwclock.c122
1 files changed, 52 insertions, 70 deletions
diff --git a/toys/pending/hwclock.c b/toys/pending/hwclock.c
index 5ca035aa..c3dabdfb 100644
--- a/toys/pending/hwclock.c
+++ b/toys/pending/hwclock.c
@@ -4,7 +4,7 @@
*
* No standard, but see Documentation/rtc.txt in the linux kernel source..
*
-USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)w(systohc)s(hctosys)r(show)[-ul][!rtsw]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_USR|TOYFLAG_BIN))
config HWCLOCK
bool "hwclock"
@@ -54,105 +54,87 @@ static int rtc_find(struct dirtree* node)
return 0;
}
-// Your system should have a /dev/rtc symlink. If your system is misconfigured,
-// search /sys/class/rtc for RTC system clock set from, then try /dev/misc/rtc.
-static int rtc_open(int flag)
-{
- if (!TT.fname) {
- int fd;
-
- if ((fd = open((TT.fname = "/dev/rtc"), flag)) != -1) return fd;
- TT.fname = 0;
- dirtree_read("/sys/class/rtc", rtc_find);
- if (TT.fname) return xopen(TT.fname, flag);
- TT.fname = "/dev/misc/rtc";
- }
-
- return xopen(TT.fname, flag);
-}
-
-// Get current time in seconds from rtc device. We could get subsecond time by
-// waiting for next time change, but haven't implemented that yet.
-static time_t get_rtc_seconds()
-{
- struct tm time;
- time_t tm;
- char *ptz_old = ptz_old;
- int fd = rtc_open(O_RDONLY);
-
- xioctl(fd, RTC_RD_TIME, &time);
- close(fd);
-
- if (TT.utc) ptz_old = xtzset("UTC0");
- if ((tm = mktime(&time)) < 0) error_exit("mktime failed");
- if (TT.utc) {
- free(xtzset(ptz_old));
- free(ptz_old);
- }
-
- return tm;
-}
-
void hwclock_main()
{
struct timezone tzone;
struct timeval timeval;
+ struct tm tm;
+ time_t time;
+ int fd = -1;
// check for Grenich Mean Time
if (toys.optflags & FLAG_u) TT.utc = 1;
else {
- FILE *fp = fopen("/etc/adjtime", "r");
+ FILE *fp;
+ char *s = 0;
- if (fp) {
- for (;;) {
- char *line = 0;
+ for (fp = fopen("/etc/adjtime", "r");
+ fp && getline(&s, (void *)toybuf, fp)>0;
+ free(s), s = 0) TT.utc += !strncmp(s, "UTC", 3);
+ if (fp) fclose(fp);
+ }
+
+ if (!(toys.optflags&FLAG_t)) {
+ int w = toys.optflags & FLAG_w, flag = O_WRONLY*w;
- if (getline(&line, (void *)toybuf, fp) <= 0) break;
- TT.utc += !strncmp(line, "UTC", 3);
- free(line);
+ // Open /dev/rtc (if your system has no /dev/rtc symlink, search for it).
+ if (!TT.fname && (fd = open("/dev/rtc", flag)) == -1) {
+ dirtree_read("/sys/class/rtc", rtc_find);
+ if (!TT.fname) TT.fname = "/dev/misc/rtc";
+ }
+ if (fd == -1) fd = xopen(TT.fname, flag);
+
+ // Get current time in seconds from rtc device. todo: get subsecond time
+ if (!w) {
+ char *s = s;
+
+ xioctl(fd, RTC_RD_TIME, &tm);
+ if (TT.utc) s = xtzset("UTC0");
+ if ((time = mktime(&tm)) < 0) goto bad;
+ if (TT.utc) {
+ free(xtzset(s));
+ free(s);
}
- fclose(fp);
}
}
if (toys.optflags & FLAG_w) {
- struct tm tm;
- int fd = rtc_open(O_WRONLY);
-
- if (gettimeofday(&timeval, 0)) perror_exit("gettimeofday");
- if ((TT.utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm))
- error_exit("timeval");
+ if (gettimeofday(&timeval, 0)
+ || (TT.utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm)) goto bad;
/* The value of tm_isdst will 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, &time);
- close(fd);
} else if (toys.optflags & FLAG_s) {
tzone.tz_minuteswest = timezone / 60 - 60 * daylight;
- tzone.tz_dsttime = 0;
- timeval.tv_sec = get_rtc_seconds();
+ timeval.tv_sec = time;
timeval.tv_usec = 0;
- if (settimeofday(&timeval, &tzone) < 0) perror_exit("settimeofday");
+ tzone.tz_dsttime = 0;
+ if (settimeofday(&timeval, &tzone)) goto bad;
} else if (toys.optflags & FLAG_t) {
- struct tm *pb;
-
- if (gettimeofday(&timeval, NULL) < 0) perror_exit("gettimeofday");
- if (!(pb = localtime(&timeval.tv_sec))) error_exit("localtime failed");
+ if (gettimeofday(&timeval, NULL) || !localtime_r(&timeval.tv_sec, &tm))
+ goto bad;
+ // Adjust seconds for timezone and daylight saving time
// extern long timezone is defined in header sys/time.h
tzone.tz_minuteswest = timezone / 60;
- if (pb->tm_isdst) tzone.tz_minuteswest -= 60;
- tzone.tz_dsttime = 0; // daylight saving time is not in effect
- if (gettimeofday(&timeval, NULL) < 0) perror_exit("gettimeofday");
+ if (tm.tm_isdst) tzone.tz_minuteswest -= 60;
+ if (gettimeofday(&timeval, NULL)) goto bad;
if (!TT.utc) timeval.tv_sec += tzone.tz_minuteswest * 60;
- if (settimeofday(&timeval, &tzone) < 0) perror_exit("settimeofday");
+ tzone.tz_dsttime = 0;
+ if (settimeofday(&timeval, &tzone)) goto bad;
} else {
- time_t tm = get_rtc_seconds();
- char *pctm = ctime(&tm), *s = strrchr(pctm, '\n');
+ char *c = ctime(&time), *s = strrchr(c, '\n');
if (s) *s = '\0';
// TODO: implement this.
- xprintf("%s 0.000000 seconds\n", pctm);
+ xprintf("%s 0.000000 seconds\n", c);
}
+
+ if (fd != -1) close(fd);
+
+ return;
+bad:
+ perror_exit("failed");
}