]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
calendarspec: be more graceful with two kinds of calendar expressions
authorLennart Poettering <lennart@poettering.net>
Thu, 30 Apr 2020 11:24:31 +0000 (13:24 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 5 May 2020 06:57:14 +0000 (08:57 +0200)
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
src/test/test-calendarspec.c

index 084965e64e7b89727b320a4e875013fd1d5c5939..b162224d9db8c5872defa024c2a3d4ff7d33102a 100644 (file)
@@ -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, ' ', ',', '-', '~', ':'))
index 9c2be7f44566cc342583d6865ef93d68e888a2e9..9e2ae55ab60c8f9d9f9aff904184f5d151f752f7 100644 (file)
@@ -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);