time-util: extract parse_calendar_date() from sysupdate
Move the YYYY-MM-DD date parsing and validation logic from sysupdate-resource.c into a shared parse_calendar_date() function in time-util, so it can be reused by other subsystems.
This commit is contained in:
@@ -1892,3 +1892,32 @@ TimestampStyle timestamp_style_from_string(const char *s) {
|
||||
return TIMESTAMP_US_UTC;
|
||||
return t;
|
||||
}
|
||||
|
||||
int parse_calendar_date(const char *s, usec_t *ret) {
|
||||
struct tm parsed_tm = {}, copy_tm;
|
||||
usec_t usec;
|
||||
const char *k;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
k = strptime(s, "%Y-%m-%d", &parsed_tm);
|
||||
if (!k || *k)
|
||||
return -EINVAL;
|
||||
|
||||
copy_tm = parsed_tm;
|
||||
r = mktime_or_timegm_usec(©_tm, /* utc= */ true, &usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Refuse non-normalized dates, e.g. Feb 30 */
|
||||
if (copy_tm.tm_mday != parsed_tm.tm_mday ||
|
||||
copy_tm.tm_mon != parsed_tm.tm_mon ||
|
||||
copy_tm.tm_year != parsed_tm.tm_year)
|
||||
return -EINVAL;
|
||||
|
||||
if (ret)
|
||||
*ret = usec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ const char* etc_localtime(void);
|
||||
|
||||
int mktime_or_timegm_usec(struct tm *tm, bool utc, usec_t *ret);
|
||||
int localtime_or_gmtime_usec(usec_t t, bool utc, struct tm *ret);
|
||||
int parse_calendar_date(const char *s, usec_t *ret);
|
||||
|
||||
uint32_t usec_to_jiffies(usec_t usec);
|
||||
usec_t jiffies_to_usec(uint32_t jiffies);
|
||||
|
||||
@@ -433,24 +433,10 @@ static int process_magic_file(
|
||||
if (iovec_memcmp(&IOVEC_MAKE(expected_hash, sizeof(expected_hash)), hash) != 0)
|
||||
log_warning("Hash of best before marker file '%s' has unexpected value, proceeding anyway.", fn);
|
||||
|
||||
struct tm parsed_tm = {};
|
||||
const char *n = strptime(e, "%Y-%m-%d", &parsed_tm);
|
||||
if (!n || *n != 0) {
|
||||
/* Doesn't parse? Then it's not a best-before date */
|
||||
log_warning("Found best before marker with an invalid date, ignoring: %s", fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tm copy_tm = parsed_tm;
|
||||
usec_t best_before;
|
||||
r = mktime_or_timegm_usec(©_tm, /* utc= */ true, &best_before);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to convert best before time: %m");
|
||||
if (copy_tm.tm_mday != parsed_tm.tm_mday ||
|
||||
copy_tm.tm_mon != parsed_tm.tm_mon ||
|
||||
copy_tm.tm_year != parsed_tm.tm_year) {
|
||||
/* date was not normalized? (e.g. "30th of feb") */
|
||||
log_warning("Found best before marker with a non-normalized data, ignoring: %s", fn);
|
||||
r = parse_calendar_date(e, &best_before);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Found best before marker with an invalid date, ignoring: %s", fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1281,4 +1281,30 @@ static int intro(void) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
TEST(parse_calendar_date) {
|
||||
usec_t usec;
|
||||
|
||||
/* Valid dates */
|
||||
ASSERT_OK(parse_calendar_date("2000-01-01", &usec));
|
||||
ASSERT_OK(parse_calendar_date("1970-01-01", &usec));
|
||||
ASSERT_EQ(usec, 0u); /* epoch */
|
||||
ASSERT_OK(parse_calendar_date("2000-02-29", &usec)); /* leap year */
|
||||
|
||||
/* NULL ret is allowed (validation only) */
|
||||
ASSERT_OK(parse_calendar_date("2000-06-15", NULL));
|
||||
|
||||
/* Non-normalized dates */
|
||||
ASSERT_ERROR(parse_calendar_date("2023-02-29", &usec), EINVAL); /* not a leap year */
|
||||
ASSERT_ERROR(parse_calendar_date("2023-04-31", &usec), EINVAL); /* April has 30 days */
|
||||
ASSERT_ERROR(parse_calendar_date("2023-13-01", &usec), EINVAL); /* month 13 */
|
||||
ASSERT_ERROR(parse_calendar_date("2023-00-01", &usec), EINVAL); /* month 0 */
|
||||
|
||||
/* Malformed input */
|
||||
ASSERT_ERROR(parse_calendar_date("", &usec), EINVAL);
|
||||
ASSERT_ERROR(parse_calendar_date("not-a-date", &usec), EINVAL);
|
||||
ASSERT_ERROR(parse_calendar_date("2023-06-15T00:00:00", &usec), EINVAL); /* trailing time */
|
||||
ASSERT_ERROR(parse_calendar_date("2023/06/15", &usec), EINVAL); /* wrong separator */
|
||||
ASSERT_ERROR(parse_calendar_date("06-15-2023", &usec), EINVAL); /* wrong order */
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
|
||||
|
||||
Reference in New Issue
Block a user