aboutsummaryrefslogtreecommitdiff
path: root/toys/posix
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2015-08-08 13:39:01 -0500
committerRob Landley <rob@landley.net>2015-08-08 13:39:01 -0500
commit400dacdeb69bc13868a625fc2ce8b49b6acd5ae3 (patch)
tree4bb640b14bf3d65d67c20bb3e26587dc6325b42b /toys/posix
parent1203ddf0e1110a107cbabf4855e07055fabe1e42 (diff)
downloadtoybox-400dacdeb69bc13868a625fc2ce8b49b6acd5ae3.tar.gz
Reject invalid dates in date(1).
Humans get upset when date(1) lets mktime(3) work out what the 99th day of the 99th month would be rather than rejecting the invalid date. For the subtly wrong cases, rather than get into the leap year business, let's rely on localtime_r(3).
Diffstat (limited to 'toys/posix')
-rw-r--r--toys/posix/date.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/toys/posix/date.c b/toys/posix/date.c
index 3093f815..84e04fcc 100644
--- a/toys/posix/date.c
+++ b/toys/posix/date.c
@@ -51,6 +51,24 @@ GLOBALS(
char *showdate;
)
+// mktime(3) normalizes the struct tm fields, but date(1) shouldn't.
+// If we round trip via localtime_r(3) and get back where we started,
+// we know 'tm' is already in normal form.
+static time_t non_normalizing_mktime(struct tm *tm)
+{
+ struct tm tm0 = *tm;
+ time_t t = mktime(tm);
+ struct tm tm1;
+
+ 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)
+ return -1;
+
+ return t;
+}
+
// Handle default posix date format: mmddhhmm[[cc]yy]
// returns 0 success, nonzero for error
static int parse_posixdate(char *str, struct tm *tm)
@@ -145,13 +163,13 @@ void date_main(void)
// We can't just pass a timezone to mktime because posix.
setenv("TZ", "UTC", 1);
tzset();
- tv.tv_sec = mktime(&tm);
+ tv.tv_sec = non_normalizing_mktime(&tm);
if (CFG_TOYBOX_FREE) {
if (tz) setenv("TZ", tz, 1);
else unsetenv("TZ");
tzset();
}
- } else tv.tv_sec = mktime(&tm);
+ } else tv.tv_sec = non_normalizing_mktime(&tm);
if (tv.tv_sec == (time_t)-1) goto bad_date;
tv.tv_usec = 0;