changeset 1689:bb4232e883d5 draft

Inline rtc_open() and get_rtc_seconds(), perform resulting cleanups.
author Rob Landley <rob@landley.net>
date Mon, 09 Feb 2015 17:33:59 -0600
parents ae981311e232
children 7b6437d0e754
files toys/pending/hwclock.c
diffstat 1 files changed, 52 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/toys/pending/hwclock.c	Mon Feb 09 16:34:24 2015 -0600
+++ b/toys/pending/hwclock.c	Mon Feb 09 17:33:59 2015 -0600
@@ -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 @@
   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;
+    timeval.tv_sec = time;
+    timeval.tv_usec = 0;
     tzone.tz_dsttime = 0;
-    timeval.tv_sec = get_rtc_seconds();
-    timeval.tv_usec = 0;
-    if (settimeofday(&timeval, &tzone) < 0) perror_exit("settimeofday");
+    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");
 }