diff options
Diffstat (limited to 'toys/pending/hwclock.c')
-rw-r--r-- | toys/pending/hwclock.c | 122 |
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"); } |