]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
calendarspec: fix possibly skips next elapse
authorGibeom Gwon <gb.gwon@stackframe.dev>
Sun, 6 Mar 2022 00:45:38 +0000 (09:45 +0900)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 7 Apr 2022 15:44:35 +0000 (17:44 +0200)
If the time unit changes after adding the repetition value, the
timer may skip the next elapse. This patch reset sub time units
to minimum value when upper unit is changed.

Fixes #22665.

src/shared/calendarspec.c
src/test/test-calendarspec.c

index 71256de8e1439f4f2bd336ed6b868231f4e7900a..79fd1359b665388b8a0f688cf5b26f19af50d7d2 100644 (file)
@@ -1181,6 +1181,7 @@ static int find_matching_component(
 
 static int tm_within_bounds(struct tm *tm, bool utc) {
         struct tm t;
+        int cmp;
         assert(tm);
 
         /*
@@ -1195,13 +1196,25 @@ static int tm_within_bounds(struct tm *tm, bool utc) {
         if (mktime_or_timegm(&t, utc) < 0)
                 return negative_errno();
 
-        /* Did any normalization take place? If so, it was out of bounds before */
-        int cmp = CMP(t.tm_year, tm->tm_year) ?:
-                  CMP(t.tm_mon, tm->tm_mon) ?:
-                  CMP(t.tm_mday, tm->tm_mday) ?:
-                  CMP(t.tm_hour, tm->tm_hour) ?:
-                  CMP(t.tm_min, tm->tm_min) ?:
-                  CMP(t.tm_sec, tm->tm_sec);
+        /*
+         * Did any normalization take place? If so, it was out of bounds before.
+         * Normalization could skip next elapse, e.g. result of normalizing 3-33
+         * is 4-2. This skips 4-1. So reset the sub time unit if upper unit was
+         * out of bounds. Normalization has occurred implies find_matching_component() > 0,
+         * other sub time units are already reset in find_next().
+         */
+        if ((cmp = CMP(t.tm_year, tm->tm_year)) != 0)
+                t.tm_mon = 0;
+        else if ((cmp = CMP(t.tm_mon, tm->tm_mon)) != 0)
+                t.tm_mday = 1;
+        else if ((cmp = CMP(t.tm_mday, tm->tm_mday)) != 0)
+                t.tm_hour = 0;
+        else if ((cmp = CMP(t.tm_hour, tm->tm_hour)) != 0)
+                t.tm_min = 0;
+        else if ((cmp = CMP(t.tm_min, tm->tm_min)) != 0)
+                t.tm_sec = 0;
+        else
+                cmp = CMP(t.tm_sec, tm->tm_sec);
 
         if (cmp < 0)
                 return -EDEADLK; /* Refuse to go backward */
index e1862f4eb88e2825a6a46d2f5663ad94e66ba461..71814e3115b4c4c39fcb4ff7528f0a86afbec4e0 100644 (file)
@@ -199,6 +199,8 @@ TEST(calendar_spec_next) {
         test_next("2016-02~01 UTC", "", 12345, 1456704000000000);
         test_next("Mon 2017-05~01..07 UTC", "", 12345, 1496016000000000);
         test_next("Mon 2017-05~07/1 UTC", "", 12345, 1496016000000000);
+        test_next("*-*-01/5 04:00:00 UTC", "", 1646010000000000, 1646107200000000);
+        test_next("*-01/7-01 04:00:00 UTC", "", 1664607600000000, 1672545600000000);
         test_next("2017-08-06 9,11,13,15,17:00 UTC", "", 1502029800000000, 1502031600000000);
         test_next("2017-08-06 9..17/2:00 UTC", "", 1502029800000000, 1502031600000000);
         test_next("2016-12-* 3..21/6:00 UTC", "", 1482613200000001, 1482634800000000);