calendarspec: parse unix timestamps (@...) (#5947)

Fixes #5810.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2017-05-17 11:40:49 +02:00
committed by Lennart Poettering
parent a8b7e8a742
commit d80e5b74e8
3 changed files with 93 additions and 13 deletions
+87 -12
View File
@@ -487,22 +487,33 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
}
}
static int parse_one_number(const char *p, const char **e, unsigned long *ret) {
char *ee = NULL;
unsigned long value;
errno = 0;
value = strtoul(p, &ee, 10);
if (errno > 0)
return -errno;
if (ee == p)
return -EINVAL;
*ret = value;
*e = ee;
return 0;
}
static int parse_component_decimal(const char **p, bool usec, int *res) {
unsigned long value;
const char *e = NULL;
char *ee = NULL;
int r;
if (!isdigit(**p))
return -EINVAL;
errno = 0;
value = strtoul(*p, &ee, 10);
if (errno > 0)
return -errno;
if (ee == *p)
return -EINVAL;
e = ee;
r = parse_one_number(*p, &e, &value);
if (r < 0)
return r;
if (usec) {
if (value * USEC_PER_SEC / USEC_PER_SEC != value)
@@ -553,6 +564,47 @@ static int const_chain(int value, CalendarComponent **c) {
return 0;
}
static int calendarspec_from_time_t(CalendarSpec *c, time_t time) {
struct tm tm;
CalendarComponent *year = NULL, *month = NULL, *day = NULL, *hour = NULL, *minute = NULL, *us = NULL;
int r;
assert_se(gmtime_r(&time, &tm));
r = const_chain(tm.tm_year + 1900, &year);
if (r < 0)
return r;
r = const_chain(tm.tm_mon + 1, &month);
if (r < 0)
return r;
r = const_chain(tm.tm_mday, &day);
if (r < 0)
return r;
r = const_chain(tm.tm_hour, &hour);
if (r < 0)
return r;
r = const_chain(tm.tm_min, &minute);
if (r < 0)
return r;
r = const_chain(tm.tm_sec * USEC_PER_SEC, &us);
if (r < 0)
return r;
c->utc = true;
c->year = year;
c->month = month;
c->day = day;
c->hour = hour;
c->minute = minute;
c->microsecond = us;
return 0;
}
static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
int r, start, stop = -1, repeat = 0;
CalendarComponent *cc;
@@ -657,6 +709,27 @@ static int parse_date(const char **p, CalendarSpec *c) {
if (*t == 0)
return 0;
/* @TIMESTAMP — UNIX time in seconds since the epoch */
if (*t == '@') {
unsigned long value;
time_t time;
r = parse_one_number(t + 1, &t, &value);
if (r < 0)
return r;
time = value;
if ((unsigned long) time != value)
return -ERANGE;
r = calendarspec_from_time_t(c, time);
if (r < 0)
return r;
*p = t;
return 1; /* finito, don't parse H:M:S after that */
}
r = parse_chain(&t, false, &first);
if (r < 0)
return r;
@@ -832,7 +905,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
continue;
e = endswith_no_case(p, tzname[j]);
if(!e)
if (!e)
continue;
if (e == p)
continue;
@@ -986,9 +1059,11 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (r < 0)
goto fail;
r = parse_calendar_time(&p, c);
if (r < 0)
goto fail;
if (r == 0) {
r = parse_calendar_time(&p, c);
if (r < 0)
goto fail;
}
if (*p != 0) {
r = -EINVAL;