[Toybox] [PATCH] Fix several bugs in date.

enh enh at google.com
Mon Aug 10 20:39:05 PDT 2015


Fix several bugs in date.

We were exiting before actually setting the date, chkmktime was always
failing, and we would segfault in glibc's strftime for non-Unix dates.
Plus one of the tests was mangled.

Also fix existing tests and add some more, and stop using the overly
vague "bad" in errors.

diff --git a/tests/date.test b/tests/date.test
index d72e50c..e011a7d 100644
--- a/tests/date.test
+++ b/tests/date.test
@@ -4,7 +4,13 @@

 #testing "name" "command" "result" "infile" "stdin"

+# Test basic date parsing.
+testing "date -d @0" "date -d @0 2>&1" "Thu Jan  1 00:00:00 GMT 1970\n" "" ""
+testing "date -d @0x123" "date -d @0x123 2>&1" "date: couldn't parse
date '@0x123'\n" "" ""
+testing "date -d 06021234" "date -d 06021234 2>&1" "Sun Jun  2
12:34:00 PST 1900\n" "" ""
+testing "date -d 123" "date -d 123 2>&1" "date: couldn't parse date
'123'\n" "" ""
+
 # Accidentally given a Unix time, we should trivially reject that.
-testing "date Unix time" "date 1438053157 2>&1" "date: bad date
'1438053157'\n" "" ""
+testing "date Unix time" "date 1438053157 2>&1" "date: invalid date
'1438053157'\n" "" ""
 # But some invalid dates are more subtle, like Febuary 29th in a non-leap year.
-testing "date Feb 29th" "date 022900001975 2>&1" "date: bad date
+testing "date Feb 29th" "date 022900001975 2>&1" "date: invalid date
'022900001975'\n" "" ""
diff --git a/toys/posix/date.c b/toys/posix/date.c
index 5719fd2..570e7f3 100644
--- a/toys/posix/date.c
+++ b/toys/posix/date.c
@@ -56,18 +56,17 @@ GLOBALS(
 )

 // mktime(3) normalizes the struct tm fields, but date(1) shouldn't.
-static time_t chkmktime(struct tm *tm)
+static time_t chkmktime(struct tm *tm, const char *str)
 {
-  struct tm tm2;
+  struct tm tm0 = *tm;
+  struct tm tm1;
   time_t t = mktime(tm);
-  int *tt1 = (void *)tm, *tt2=(void *)&tm2, i;

-  if (t != -1 && localtime_r(&t, &tm2)) {
-    for (i=0; i<6; i++) if (tt1[i] != tt2[i]) break;
-    if (i == 5) return t;
-  }
-
-  return -1;
+  if (t == -1 || !localtime_r(&t, &tm1) ||
+      tm0.tm_sec != tm1.tm_sec || tm0.tm_min != tm1.tm_min ||
+      tm0.tm_hour != tm1.tm_hour || tm0.tm_mday != tm1.tm_mday ||
+      tm0.tm_mon != tm1.tm_mon) error_exit("invalid date '%s'", str);
+  return t;
 }

 static void utzset(void)
@@ -92,6 +91,8 @@ static int parse_default(char *str, struct tm *tm)
 {
   int len = 0;

+  memset(tm, 0, sizeof(*tm));
+
   // Parse @UNIXTIME[.FRACTION]
   if (*str == '@') {
     long long ll;
@@ -162,10 +163,10 @@ void date_main(void)
   if (TT.showdate) {
     setdate = TT.showdate;
     if (TT.setfmt) {
-      char *s = strptime(TT.showdate, TT.setfmt+(*TT.setfmt=='+'), &tm);
+      char *s = strptime(setdate, TT.setfmt+(*TT.setfmt=='+'), &tm);

       if (!s || *s) goto bad_date;
-    } else if (parse_default(TT.showdate, &tm)) goto bad_date;
+    } else if (parse_default(setdate, &tm)) goto bad_date;
   } else {
     time_t now;

@@ -196,13 +197,11 @@ void date_main(void)
     if (toys.optflags & FLAG_u) {
       // We can't just pass a timezone to mktime because posix.
       utzset();
-      tv.tv_sec = chkmktime(&tm);
+      tv.tv_sec = chkmktime(&tm, setdate);
       utzreset();
-    } else tv.tv_sec = chkmktime(&tm);
-    if (tv.tv_sec == (time_t)-1) goto bad_date;
+    } else tv.tv_sec = chkmktime(&tm, setdate);

     tv.tv_usec = TT.nano/1000;
-exit(1);
     if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date");
   }

@@ -214,5 +213,5 @@ exit(1);
   return;

 bad_date:
-  error_exit("bad date '%s'", setdate);
+  error_exit("couldn't parse date '%s'", setdate);
 }

 1439264345.0


More information about the Toybox mailing list