From a4d6d711cf0a96aa282ace6afe49b3df9c1bf334 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 13:18:45 +0200 Subject: [PATCH 1/6] =?UTF-8?q?calendarspec:=20encode=20that=20it's=20OK?= =?UTF-8?q?=20to=20store=20=C2=B5s=20in=20'int's?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/calendarspec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 4103cf3ef0..7da3fb7211 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -30,6 +30,9 @@ * linked compenents anyway. */ #define CALENDARSPEC_COMPONENTS_MAX 240 +/* Let's make sure that the microsecond component is safe to be stored in an 'int' */ +assert_cc(INT_MAX >= USEC_PER_SEC); + static void chain_free(CalendarComponent *c) { CalendarComponent *n; From 80b19994a420488271ff0b8218abf0c30fc3995c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 13:18:58 +0200 Subject: [PATCH 2/6] calendarspec: pack our flags a bit --- src/shared/calendarspec.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/calendarspec.h b/src/shared/calendarspec.h index 3bf8a39e1a..0a5d95b4b1 100644 --- a/src/shared/calendarspec.h +++ b/src/shared/calendarspec.h @@ -19,9 +19,9 @@ typedef struct CalendarComponent { typedef struct CalendarSpec { int weekdays_bits; - bool end_of_month; - bool utc; - int dst; + bool end_of_month:1; + bool utc:1; + signed int dst:2; char *timezone; CalendarComponent *year; From 3c6f0300aec0d101a29806e84a501f3e0df1d7e1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 13:19:14 +0200 Subject: [PATCH 3/6] calendarspec: drop _pure_ from static function For static functions the compiler should be able to determine this on its own, let's not add needless decorators. --- src/shared/calendarspec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 7da3fb7211..65afcd0581 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -165,7 +165,7 @@ int calendar_spec_normalize(CalendarSpec *c) { return 0; } -_pure_ static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) { +static bool chain_valid(CalendarComponent *c, int from, int to, bool end_of_month) { assert(to >= from); if (!c) From 05851cb9df1305d53b99f1a0ee9d2acb7e1ffb52 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 13:20:23 +0200 Subject: [PATCH 4/6] calendarspec: minor simplification --- src/shared/calendarspec.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 65afcd0581..084965e64e 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -369,14 +369,13 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { } r = fflush_and_check(f); + fclose(f); + if (r < 0) { free(buf); - fclose(f); return r; } - fclose(f); - *p = buf; return 0; } From c9c9f6f450f678a0d5e5b929ba238d4a5254bded Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 13:24:31 +0200 Subject: [PATCH 5/6] calendarspec: be more graceful with two kinds of calendar expressions This changes the calendarspec parser to allow expressions such as "00:05..05", i.e. a range where start and end is the same. It also allows expressions such as "00:1-2/3", i.e. where the repetition value does not fit even once in the specified range. With this patch both cases will now be optimized away, i.e. the range is removed and a fixed value is used, which is functionally equivalent. See #15030 for an issue where the inability to parse such expressions caused confusion. I think it's probably better to accept these gracefully and optimizing them away instead of refusing them with a plain EINVAL. With a tool such as "systemd-analyze" calendar it should be easy to figure out the normalized form with the redundant bits optimized away. --- src/shared/calendarspec.c | 16 ++++++++++++++++ src/test/test-calendarspec.c | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 084965e64e..b162224d9d 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -91,6 +91,16 @@ static void normalize_chain(CalendarComponent **c) { if (i->stop > i->start && i->repeat > 0) i->stop -= (i->stop - i->start) % i->repeat; + /* If a repeat value is specified, but it cannot even be triggered once, let's suppress + * it. + * + * Similar, if the stop value is the same as the start value, then let's just make this a + * non-repeating chain element */ + if ((i->stop > i->start && i->repeat > 0 && i->start + i->repeat > i->stop) || + i->start == i->stop) { + i->repeat = 0; + i->stop = -1; + } } if (n <= 1) @@ -645,6 +655,12 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend if (repeat == 0) return -ERANGE; + } else { + /* If no repeat value is specified for the µs component, then let's explicitly refuse ranges + * below 1s because our default repeat granularity is beyond that. */ + + if (usec && stop >= 0 && start + repeat > stop) + return -EINVAL; } if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':')) diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 9c2be7f445..9e2ae55ab6 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -185,6 +185,8 @@ int main(int argc, char* argv[]) { test_one("@1493187147 UTC", "2017-04-26 06:12:27 UTC"); test_one("@0", "1970-01-01 00:00:00 UTC"); test_one("@0 UTC", "1970-01-01 00:00:00 UTC"); + test_one("*:05..05", "*-*-* *:05:00"); + test_one("*:05..10/6", "*-*-* *:05:00"); test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000); test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000); @@ -237,8 +239,6 @@ int main(int argc, char* argv[]) { assert_se(calendar_spec_from_string("*~29", &c) < 0); assert_se(calendar_spec_from_string("*~16..31", &c) < 0); assert_se(calendar_spec_from_string("12..1/2-*", &c) < 0); - assert_se(calendar_spec_from_string("*:05..05", &c) < 0); - assert_se(calendar_spec_from_string("*:05..10/6", &c) < 0); assert_se(calendar_spec_from_string("20/4:00", &c) < 0); assert_se(calendar_spec_from_string("00:00/60", &c) < 0); assert_se(calendar_spec_from_string("00:00:2300", &c) < 0); From 2edc7aea7a95dc0dc0fb3e9ef5ffbe413a477593 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 13:42:59 +0200 Subject: [PATCH 6/6] =?UTF-8?q?man:=20expand=20on=20the=20star=E2=80=A6end?= =?UTF-8?q?/repetition=20time=20expressions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And attempt to explain what is requested in #15030, but still be concise. Fixes: #15030 --- man/systemd.time.xml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/man/systemd.time.xml b/man/systemd.time.xml index dc1e78a187..b4656b05d1 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -199,15 +199,14 @@ tomorrow Pacific/Auckland → Thu 2012-11-23 19:00:00 continuous weekdays. , and .. may be combined freely. - In the date and time specifications, any component may be - specified as * in which case any value will - match. Alternatively, each component can be specified as a list of - values separated by commas. Values may be suffixed with - / and a repetition value, which indicates that - the value itself and the value plus all multiples of the repetition value - are matched. Two values separated by .. may be used - to indicate a range of values; ranges may also be followed with - / and a repetition value. + In the date and time specifications, any component may be specified as * in + which case any value will match. Alternatively, each component can be specified as a list of values + separated by commas. Values may be suffixed with / and a repetition value, which + indicates that the value itself and the value plus all multiples of the repetition value are matched. + Two values separated by .. may be used to indicate a range of values; ranges may also + be followed with / and a repetition value, in which case the expression matches all + times starting with the start value, and continuing with all multiples of the repetition value relative + to the start value, ending at the end value the latest. A date specification may use ~ to indicate the last day(s) in a month. For example, *-02~03 means