Welcome to little lamb

Code » slicd » commit a1f13b1

Special DST: Allow on (de)activation only

author Olivier Brunel
2016-05-28 14:33:22 UTC
committer Olivier Brunel
2016-05-28 16:09:28 UTC
parent eab57150833588950f0998d509983f7f1b6871bb

Special DST: Allow on (de)activation only

Making use of our newly available bit, we can now use '<' to enable the special
DST mode on deactivation only, '>' on activation only, or '<>' for both
(replacing '$').

doc/slicd-parser.pod +5 -3
doc/slicd-sched.pod +3 -2
src/include/slicd/fields.h +2 -3
src/include/slicd/job.h +12 -3
src/libslicd/slicd_add_job_from_cronline.c +13 -3
src/libslicd/slicd_job.c +16 -6
src/libslicd/slicd_job_next_run.c +5 -3
src/slicd/slicd-dump.c +13 -2

diff --git a/doc/slicd-parser.pod b/doc/slicd-parser.pod
index dc9e4ac..d77fb5a 100644
--- a/doc/slicd-parser.pod
+++ b/doc/slicd-parser.pod
@@ -113,9 +113,11 @@ Each field can have its value prefixed with an exclamation point (!) in order to
 invert it. For example, using "!15,20" as value for days will mean every day
 but the 15th and 20th; the invertion being applied to the entire list of values.
 
-The hour field can also have its value prefixed with a dollar sign ($) to enable
-the special DST mode for the job; See B<slicd-sched>(1) for more. Note that when
-also using the invertion flag (!), the dollar sign should come first.
+The hour field can also have its value prefixed with either the less than sign
+(<), the greater than sign (>), or both (<>), to enable the special DST mode for
+the job only on deactivation, only on activation, or both respectively.
+See B<slicd-sched>(1) for more. Note that when also using the invertion flag
+(!), the DST flag(s) should come first.
 
 System crontabs have an extra field for the username to run under.
 
diff --git a/doc/slicd-sched.pod b/doc/slicd-sched.pod
index e3b19e9..93dba78 100644
--- a/doc/slicd-sched.pod
+++ b/doc/slicd-sched.pod
@@ -76,9 +76,10 @@ at 01:30 (DST off) then an hour later at 03:30 (DST on).
 
 A special DST handling mode can be activated on a per-job basis (see
 B<slicd-parser>(1)), in which case time changes due to DST are handled
-differently than described above.
+differently than described above. It can be enabled only on deactivation (time
+jumps backward), only on activation (time jumps forward), or both.
 
-When time jumps backwards, jobs will only run during the "first pass" - or when
+When time jumps backward, jobs will only run during the "first pass" - or when
 DST was activated. When the time "repeats" but with DST deactivated, they will
 not run. So using the same example, our job would run at 02:30 (DST on), and
 then only two hours later, at 03:30 (DST off).
diff --git a/src/include/slicd/fields.h b/src/include/slicd/fields.h
index cf686f3..967de18 100644
--- a/src/include/slicd/fields.h
+++ b/src/include/slicd/fields.h
@@ -29,8 +29,7 @@
  * 31   days (0-30)
  * 12   months (0-11)
  *  7   days of week (0-6; 0=sunday, 1=monday, etc)
- *  1   special DST: to enable special handling for DST changes
- *  1   unused
+ *  2   special DST: to enable special handling for DST changes
  *
  * 136 bits total; hence an array of 17 char-s
  *
@@ -42,7 +41,7 @@
 #define _SLICD_BITS_OFFSET_DAYS         _SLICD_BITS_OFFSET_HOURS + 24
 #define _SLICD_BITS_OFFSET_MONTHS       _SLICD_BITS_OFFSET_DAYS + 31
 #define _SLICD_BITS_OFFSET_DOW          _SLICD_BITS_OFFSET_MONTHS + 12
-#define _SLICD_BIT_DST_SPECIAL          _SLICD_BITS_OFFSET_DOW + 7
+#define _SLICD_BITS_DST_SPECIAL         _SLICD_BITS_OFFSET_DOW + 7
 
 static struct
 {
diff --git a/src/include/slicd/job.h b/src/include/slicd/job.h
index 35526ef..c743d4d 100644
--- a/src/include/slicd/job.h
+++ b/src/include/slicd/job.h
@@ -42,16 +42,25 @@ typedef enum
 } slicd_field_t;
 #define SLICD_DOW   SLICD_DAYS_OF_WEEK
 
+typedef enum
+{
+    SLICD_DST_OFF               = 0,
+    SLICD_DST_ON_DEACTIVATION   = (1 << 0),
+    SLICD_DST_ON_ACTIVATION     = (1 << 1),
+    SLICD_DST_ON_BOTH           = SLICD_DST_ON_DEACTIVATION | SLICD_DST_ON_ACTIVATION
+} slicd_dst_special_t;
+
 extern int slicd_job_has            (slicd_job_t    *job,
                                      slicd_field_t   field,
                                      int             which);
 
 extern int slicd_job_has_days_combo (slicd_job_t    *job);
 
-extern int slicd_job_has_dst_special(slicd_job_t    *job);
+extern slicd_dst_special_t
+        slicd_job_get_dst_special   (slicd_job_t    *job);
 
-extern int slicd_job_set_dst_special(slicd_job_t    *job,
-                                     int             what);
+extern int slicd_job_set_dst_special(slicd_job_t        *job,
+                                     slicd_dst_special_t dst);
 
 extern int slicd_job_clearset       (slicd_job_t    *job,
                                      slicd_field_t   field,
diff --git a/src/libslicd/slicd_add_job_from_cronline.c b/src/libslicd/slicd_add_job_from_cronline.c
index 63a3b75..b0dd8b0 100644
--- a/src/libslicd/slicd_add_job_from_cronline.c
+++ b/src/libslicd/slicd_add_job_from_cronline.c
@@ -87,11 +87,21 @@ parse_interval (slicd_job_t *job, slicd_field_t field, const char **s)
     int from, to, step;
     int swap = 0;
 
-    if (field == SLICD_HOURS && **s == '$')
+    if (field == SLICD_HOURS)
     {
-        slicd_job_set_dst_special (job, 1);
-        ++*s;
+        slicd_dst_special_t dst = SLICD_DST_OFF;
 
+        if (**s == '<')
+        {
+            dst |= SLICD_DST_ON_DEACTIVATION;
+            ++*s;
+        }
+        if (**s == '>')
+        {
+            dst |= SLICD_DST_ON_ACTIVATION;
+            ++*s;
+        }
+        slicd_job_set_dst_special (job, dst);
     }
 
     if (**s == '!')
diff --git a/src/libslicd/slicd_job.c b/src/libslicd/slicd_job.c
index ff69b25..7b0ab39 100644
--- a/src/libslicd/slicd_job.c
+++ b/src/libslicd/slicd_job.c
@@ -57,20 +57,30 @@ slicd_job_has_days_combo (slicd_job_t    *job)
         && slicd_job_first (job, SLICD_DAYS, 1, 6, 0) <= 6;
 }
 
-int
-slicd_job_has_dst_special (slicd_job_t    *job)
+slicd_dst_special_t
+slicd_job_get_dst_special (slicd_job_t    *job)
 {
+    slicd_dst_special_t dst = SLICD_DST_OFF;
+
     assert (job != NULL);
-    return bitarray_isset (job->bits, _SLICD_BIT_DST_SPECIAL);
+
+    if (bitarray_peek (job->bits, _SLICD_BITS_DST_SPECIAL))
+        dst |= SLICD_DST_ON_DEACTIVATION;
+    if (bitarray_peek (job->bits, _SLICD_BITS_DST_SPECIAL + 1))
+        dst |= SLICD_DST_ON_ACTIVATION;
+
+    return dst;
 }
 
 int
-slicd_job_set_dst_special (slicd_job_t    *job,
-                           int             what)
+slicd_job_set_dst_special (slicd_job_t        *job,
+                           slicd_dst_special_t dst)
 {
     assert (job != NULL);
+    assert (dst <= SLICD_DST_ON_BOTH);
 
-    bitarray_clearsetn (job->bits, _SLICD_BIT_DST_SPECIAL, 1, what);
+    bitarray_poke (job->bits, _SLICD_BITS_DST_SPECIAL, dst & SLICD_DST_ON_DEACTIVATION);
+    bitarray_poke (job->bits, _SLICD_BITS_DST_SPECIAL + 1, dst & SLICD_DST_ON_ACTIVATION);
     return 0;
 }
 
diff --git a/src/libslicd/slicd_job_next_run.c b/src/libslicd/slicd_job_next_run.c
index 9c1031a..4651a48 100644
--- a/src/libslicd/slicd_job_next_run.c
+++ b/src/libslicd/slicd_job_next_run.c
@@ -208,7 +208,8 @@ again:
          * before was off, in which case we're right after the "skipped period"
          * and need to see if the job would have been ran then, to run it now
          * instead ("catching up") */
-        if (dst == -2 && slicd_job_has_dst_special (job) && next->tm_isdst == 1)
+        if (dst == -2 && (slicd_job_get_dst_special (job) & SLICD_DST_ON_ACTIVATION)
+                && next->tm_isdst == 1)
         {
             time_t t = time - 60;
             struct tm *tm;
@@ -241,7 +242,7 @@ again:
 
         /* DST special: if DST is on, check if it would have ran during the
          * "skipped period" and if so, match this first minute of new DST */
-        if (dst == 1 && slicd_job_has_dst_special (job))
+        if (dst == 1 && (slicd_job_get_dst_special (job) & SLICD_DST_ON_ACTIVATION))
         {
             n = would_have_ran (job, next);
             if (n < 0)
@@ -349,7 +350,8 @@ bump_day:
     /* DST special: if DST is off, get the first minute since it's been off, and
      * make sure this job isn't in the "repeating time period" and if so, start
      * again after said period */
-    if (slicd_job_has_dst_special (job) && next->tm_isdst == 0)
+    if ((slicd_job_get_dst_special (job) & SLICD_DST_ON_DEACTIVATION)
+            && next->tm_isdst == 0)
     {
         time_t t;
         struct tm tm;
diff --git a/src/slicd/slicd-dump.c b/src/slicd/slicd-dump.c
index adf0be6..3e8cd63 100644
--- a/src/slicd/slicd-dump.c
+++ b/src/slicd/slicd-dump.c
@@ -176,8 +176,19 @@ out:
             buffer_puts (buffer_1small, "\n");
         }
 
-        if (slicd_job_has_dst_special (job))
-            buffer_puts (buffer_1small, "Special DST mode enabled.\n");
+        {
+            slicd_dst_special_t dst = slicd_job_get_dst_special (job);
+
+            if (dst)
+            {
+                buffer_puts (buffer_1small, "Special DST mode enabled");
+                if (dst == SLICD_DST_ON_DEACTIVATION)
+                    buffer_puts (buffer_1small, " on deactivation only");
+                else if (dst == SLICD_DST_ON_ACTIVATION)
+                    buffer_puts (buffer_1small, " on activation only");
+                buffer_puts (buffer_1small, ".\n");
+            }
+        }
         if (slicd_job_has_days_combo (job))
             buffer_puts (buffer_1small, "Note: Days Combo activated.\n");
         buffer_putsflush (buffer_1small, "\n");