[systemd-devel] [PATCH] timer: allow user to control activation time of cron-like timers

Dave Reisner d at falconindy.com
Sun May 11 09:09:01 PDT 2014


On Sun, May 11, 2014 at 07:53:55PM +0400, Alexander Bashmakov wrote:
> Issue was rised in this thread:
> https://mailman.archlinux.org/pipermail/arch-general/2014-May/036162.html
> 
> Disclaimer:
> I almost have no expereince in C.
> So this patch can contain some silly mistakes. But it 'works for me'.
> Please consider it as RFC.
> 
> -8<-------
> Cron-like timers are useful for maintenance tasks
> and already used in some distros by default.
> But midnight is not best time for this.
> Just add a new option allowing user to specify
> activation time (and date) for such timers globally.

"daily" is just syntactic sugar for "*-*-* 00:00:00". If you don't want
to run at midnight, modify the normalized form to run at the time you
want.

> Signed-off-by: Alexander Bashmakov <pkunk.ab at gmail.com>
> ---
>  man/systemd-system.conf.xml  | 19 +++++++++++++
>  man/systemd.time.xml         |  6 ++++-
>  src/core/load-fragment.c     |  2 +-
>  src/core/main.c              |  7 +++++
>  src/core/manager.c           | 42 +++++++++++++++++++++++++++++
>  src/core/manager.h           |  4 +++
>  src/core/system.conf         |  1 +
>  src/core/user.conf           |  1 +
>  src/shared/calendarspec.c    | 64 +++++++++++++++++++++++++++++++-------------
>  src/shared/calendarspec.h    |  4 ++-
>  src/test/test-calendarspec.c | 20 +++++++++-----
>  11 files changed, 141 insertions(+), 29 deletions(-)
> 
> diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
> index 3814bd2..e38e70a 100644
> --- a/man/systemd-system.conf.xml
> +++ b/man/systemd-system.conf.xml
> @@ -302,6 +302,25 @@
>                          </varlistentry>
>  
>                          <varlistentry>
> +                                <term><varname>DefaultTimerEventTime=</varname></term>
> +
> +                                <listitem><para>Sets the default
> +                                elapsing time for cron-like timer units.
> +                                This controls
> +                                the global default for
> +                                timer units with
> +                                <varname>OnCalendar=</varname>
> +                                set on
> +                                <literal>hourly</literal>, <literal>daily</literal>,
> +                                <literal>monthly</literal>, <literal>yearly</literal>
> +                                or <literal>weekly</literal>.
> +                                Only relevant fields are used.
> +                                See
> +                                <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>5</manvolnum></citerefentry>
> +                                for details.</para></listitem>
> +                        </varlistentry>
> +
> +                        <varlistentry>
>                                  <term><varname>DefaultCPUQuotaPeriodSec=</varname></term>
>  
>                                  <listitem><para>Sets the default CPU
> diff --git a/man/systemd.time.xml b/man/systemd.time.xml
> index 0706cdf..776b6bf 100644
> --- a/man/systemd.time.xml
> +++ b/man/systemd.time.xml
> @@ -248,7 +248,11 @@
>                  <literal>*-*-* *:00:00</literal>, <literal>*-*-*
>                  00:00:00</literal>, <literal>*-*-01 00:00:00</literal> and
>                  <literal>Mon *-*-* 00:00:00</literal>,
> -                respectively.</para>
> +                respectively.
> +                Note that exact time for these expressions depends on
> +                <varname>DefaultTimerEventTime=</varname>
> +                setting.
> +                </para>
>  
>                  <para>Examples for valid timestamps and their
>                  normalized form:</para>
> diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
> index 14c194b..7f9d71f 100644
> --- a/src/core/load-fragment.c
> +++ b/src/core/load-fragment.c
> @@ -1273,7 +1273,7 @@ int config_parse_timer(const char *unit,
>          }
>  
>          if (b == TIMER_CALENDAR) {
> -                if (calendar_spec_from_string(rvalue, &c) < 0) {
> +                if (calendar_spec_from_string(rvalue, &c, t->meta.manager->default_timer_event_time) < 0) {
>                          log_syntax(unit, LOG_ERR, filename, line, EINVAL,
>                                     "Failed to parse calendar specification, ignoring: %s",
>                                     rvalue);
> diff --git a/src/core/main.c b/src/core/main.c
> index c1b0ffd..78c9711 100644
> --- a/src/core/main.c
> +++ b/src/core/main.c
> @@ -109,6 +109,7 @@ static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
>  static uint64_t arg_capability_bounding_set_drop = 0;
>  static nsec_t arg_timer_slack_nsec = (nsec_t) -1;
>  static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
> +static char* arg_default_timer_event_time = NULL;
>  static usec_t arg_default_cpu_quota_period_usec = 100 * USEC_PER_MSEC;
>  static Set* arg_syscall_archs = NULL;
>  static FILE* arg_serialization = NULL;
> @@ -684,6 +685,7 @@ static int parse_config_file(void) {
>  #endif
>                  { "Manager", "TimerSlackNSec",            config_parse_nsec,             0, &arg_timer_slack_nsec                  },
>                  { "Manager", "DefaultTimerAccuracySec",   config_parse_sec,              0, &arg_default_timer_accuracy_usec       },
> +                { "Manager", "DefaultTimerEventTime",     config_parse_string,           0, &arg_default_timer_event_time          },
>                  { "Manager", "DefaultCPUQuotaPeriodSec",  config_parse_sec,              0, &arg_default_cpu_quota_period_usec     },
>                  { "Manager", "DefaultStandardOutput",     config_parse_output,           0, &arg_default_std_output                },
>                  { "Manager", "DefaultStandardError",      config_parse_output,           0, &arg_default_std_error                 },
> @@ -1619,6 +1621,11 @@ int main(int argc, char *argv[]) {
>  
>          m->confirm_spawn = arg_confirm_spawn;
>          m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec;
> +
> +        r = manager_set_default_timer_event_time(m, arg_default_timer_event_time);
> +        if (r < 0)
> +            goto finish;
> +
>          m->default_cpu_quota_period_usec = arg_default_cpu_quota_period_usec;
>          m->default_std_output = arg_default_std_output;
>          m->default_std_error = arg_default_std_error;
> diff --git a/src/core/manager.c b/src/core/manager.c
> index 5772f40..b2d31eb 100644
> --- a/src/core/manager.c
> +++ b/src/core/manager.c
> @@ -429,6 +429,11 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
>          m->running_as = running_as;
>          m->exit_code = _MANAGER_EXIT_CODE_INVALID;
>          m->default_timer_accuracy_usec = USEC_PER_MINUTE;
> +
> +        r = manager_set_default_timer_event_time(m, NULL);
> +        if (r < 0)
> +                goto fail;
> +
>          m->default_cpu_quota_period_usec = 100 * USEC_PER_MSEC;
>  
>          m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
> @@ -821,6 +826,8 @@ void manager_free(Manager *m) {
>          hashmap_free(m->cgroup_unit);
>          set_free_free(m->unit_path_cache);
>  
> +        calendar_spec_free(m->default_timer_event_time);
> +
>          free(m->switch_root);
>          free(m->switch_root_init);
>  
> @@ -2720,6 +2727,41 @@ int manager_environment_add(Manager *m, char **minus, char **plus) {
>          return 0;
>  }
>  
> +int manager_set_default_timer_event_time(Manager *m, const char *default_event_time) {
> +        int r;
> +
> +        assert(m);
> +        CalendarSpec *c;
> +
> +        if (isempty(default_event_time)
> +                || strcaseeq(default_event_time, "hourly")
> +                || strcaseeq(default_event_time, "daily")
> +                || strcaseeq(default_event_time, "weekly")
> +                || strcaseeq(default_event_time, "monthly")
> +                || strcaseeq(default_event_time, "anually")
> +                || strcaseeq(default_event_time, "yearly")) {
> +
> +                c = new0(CalendarSpec, 1);
> +                if (!c)
> +                        return -ENOMEM;
> +
> +                r = calendar_spec_default(c);
> +                if (r < 0)
> +                        goto fail;
> +        } else {
> +                r = calendar_spec_from_string(default_event_time, &c, NULL);
> +                if (r < 0)
> +                        goto fail;
> +        }
> +
> +        m->default_timer_event_time = c;
> +        return 0;
> +
> +fail:
> +        calendar_spec_free(c);
> +        return r;
> +}
> +
>  int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
>          int i;
>  
> diff --git a/src/core/manager.h b/src/core/manager.h
> index a3de351..3dc570b 100644
> --- a/src/core/manager.h
> +++ b/src/core/manager.h
> @@ -29,6 +29,7 @@
>  #include "sd-event.h"
>  #include "fdset.h"
>  #include "cgroup-util.h"
> +#include "calendarspec.h"
>  
>  /* Enforce upper limit how many names we allow */
>  #define MANAGER_MAX_NAMES 131072 /* 128K */
> @@ -244,6 +245,8 @@ struct Manager {
>  
>          usec_t default_timer_accuracy_usec;
>  
> +        CalendarSpec *default_timer_event_time;
> +
>          struct rlimit *rlimit[_RLIMIT_MAX];
>  
>          /* non-zero if we are reloading or reexecuting, */
> @@ -301,6 +304,7 @@ void manager_clear_jobs(Manager *m);
>  unsigned manager_dispatch_load_queue(Manager *m);
>  
>  int manager_environment_add(Manager *m, char **minus, char **plus);
> +int manager_set_default_timer_event_time(Manager *m, const char *default_event_time);
>  int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
>  
>  int manager_loop(Manager *m);
> diff --git a/src/core/system.conf b/src/core/system.conf
> index 4d775fa..3ef8b1b 100644
> --- a/src/core/system.conf
> +++ b/src/core/system.conf
> @@ -24,6 +24,7 @@
>  #SystemCallArchitectures=
>  #TimerSlackNSec=
>  #DefaultTimerAccuracySec=1min
> +#DefaultTimerEventTime=
>  #DefaultCPUQuotaPeriodSec=100ms
>  #DefaultStandardOutput=journal
>  #DefaultStandardError=inherit
> diff --git a/src/core/user.conf b/src/core/user.conf
> index 8c7ecde..c108722 100644
> --- a/src/core/user.conf
> +++ b/src/core/user.conf
> @@ -15,6 +15,7 @@
>  #SystemCallArchitectures=
>  #TimerSlackNSec=
>  #DefaultTimerAccuracySec=1min
> +#DefaultTimerEventTime=
>  #DefaultStandardOutput=inherit
>  #DefaultStandardError=inherit
>  #DefaultTimeoutStartSec=90s
> diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c
> index 69b7427..7720cf6 100644
> --- a/src/shared/calendarspec.c
> +++ b/src/shared/calendarspec.c
> @@ -639,7 +639,7 @@ fail:
>          return r;
>  }
>  
> -int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
> +int calendar_spec_from_string(const char *p, CalendarSpec **spec, const CalendarSpec *d) {
>          CalendarSpec *c;
>          int r;
>  
> @@ -654,66 +654,66 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
>                  return -ENOMEM;
>  
>          if (strcaseeq(p, "hourly")) {
> -                r = const_chain(0, &c->minute);
> +                r = const_chain(d->minute->value, &c->minute);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->second);
> +                r = const_chain(d->second->value, &c->second);
>                  if (r < 0)
>                          goto fail;
>  
>          } else if (strcaseeq(p, "daily")) {
> -                r = const_chain(0, &c->hour);
> +                r = const_chain(d->hour->value, &c->hour);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->minute);
> +                r = const_chain(d->minute->value, &c->minute);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->second);
> +                r = const_chain(d->second->value, &c->second);
>                  if (r < 0)
>                          goto fail;
>  
>          } else if (strcaseeq(p, "monthly")) {
> -                r = const_chain(1, &c->day);
> +                r = const_chain(d->day->value, &c->day);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->hour);
> +                r = const_chain(d->hour->value, &c->hour);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->minute);
> +                r = const_chain(d->minute->value, &c->minute);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->second);
> +                r = const_chain(d->second->value, &c->second);
>                  if (r < 0)
>                          goto fail;
>  
>          } else if (strcaseeq(p, "anually") || strcaseeq(p, "yearly")) {
> -                r = const_chain(1, &c->month);
> +                r = const_chain(d->month->value, &c->month);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(1, &c->day);
> +                r = const_chain(d->day->value, &c->day);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->hour);
> +                r = const_chain(d->hour->value, &c->hour);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->minute);
> +                r = const_chain(d->minute->value, &c->minute);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->second);
> +                r = const_chain(d->second->value, &c->second);
>                  if (r < 0)
>                          goto fail;
>  
>          } else if (strcaseeq(p, "weekly")) {
>  
> -                c->weekdays_bits = 1;
> +                c->weekdays_bits = d->weekdays_bits;
>  
> -                r = const_chain(0, &c->hour);
> +                r = const_chain(d->hour->value, &c->hour);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->minute);
> +                r = const_chain(d->minute->value, &c->minute);
>                  if (r < 0)
>                          goto fail;
> -                r = const_chain(0, &c->second);
> +                r = const_chain(d->second->value, &c->second);
>                  if (r < 0)
>                          goto fail;
>  
> @@ -919,6 +919,32 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
>          }
>  }
>  
> +int calendar_spec_default(CalendarSpec *c) {
> +        int r;
> +
> +        assert(c);
> +
> +        c->weekdays_bits = 1;
> +
> +        r = const_chain(1, &c->month);
> +        if (r < 0)
> +                return r;
> +        r = const_chain(1, &c->day);
> +        if (r < 0)
> +                return r;
> +        r = const_chain(0, &c->hour);
> +        if (r < 0)
> +                return r;
> +        r = const_chain(0, &c->minute);
> +        if (r < 0)
> +                return r;
> +        r = const_chain(0, &c->second);
> +        if (r < 0)
> +                return r;
> +
> +        return 0;
> +}
> +
>  int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
>          struct tm tm;
>          time_t t;
> diff --git a/src/shared/calendarspec.h b/src/shared/calendarspec.h
> index 7baf318..7415455 100644
> --- a/src/shared/calendarspec.h
> +++ b/src/shared/calendarspec.h
> @@ -52,6 +52,8 @@ int calendar_spec_normalize(CalendarSpec *spec);
>  bool calendar_spec_valid(CalendarSpec *spec);
>  
>  int calendar_spec_to_string(const CalendarSpec *spec, char **p);
> -int calendar_spec_from_string(const char *p, CalendarSpec **spec);
> +int calendar_spec_from_string(const char *p, CalendarSpec **spec, const CalendarSpec *d);
> +
> +int calendar_spec_default(CalendarSpec *c);
>  
>  int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next);
> diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
> index 21b0024..4660032 100644
> --- a/src/test/test-calendarspec.c
> +++ b/src/test/test-calendarspec.c
> @@ -25,13 +25,18 @@
>  #include "util.h"
>  
>  static void test_one(const char *input, const char *output) {
> -        CalendarSpec *c;
> +        CalendarSpec *c, *d;
>          _cleanup_free_ char *p = NULL, *q = NULL;
>          usec_t u;
>          char buf[FORMAT_TIMESTAMP_MAX];
>          int r;
>  
> -        assert_se(calendar_spec_from_string(input, &c) >= 0);
> +        d = new0(CalendarSpec, 1);
> +        assert_se(d);
> +        r = calendar_spec_default(d);
> +        assert_se(r >= 0);
> +
> +        assert_se(calendar_spec_from_string(input, &c, d) >= 0);
>  
>          assert_se(calendar_spec_to_string(c, &p) >= 0);
>          printf("\"%s\" → \"%s\"\n", input, p);
> @@ -43,9 +48,10 @@ static void test_one(const char *input, const char *output) {
>          printf("Next: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
>          calendar_spec_free(c);
>  
> -        assert_se(calendar_spec_from_string(p, &c) >= 0);
> +        assert_se(calendar_spec_from_string(p, &c, d) >= 0);
>          assert_se(calendar_spec_to_string(c, &q) >= 0);
>          calendar_spec_free(c);
> +        calendar_spec_free(d);
>  
>          assert_se(streq(q, p));
>  }
> @@ -79,10 +85,10 @@ int main(int argc, char* argv[]) {
>          test_one("weekly", "Mon *-*-* 00:00:00");
>          test_one("*:2/3", "*-*-* *:02/3:00");
>  
> -        assert_se(calendar_spec_from_string("test", &c) < 0);
> -        assert_se(calendar_spec_from_string("", &c) < 0);
> -        assert_se(calendar_spec_from_string("7", &c) < 0);
> -        assert_se(calendar_spec_from_string("121212:1:2", &c) < 0);
> +        assert_se(calendar_spec_from_string("test", &c, NULL) < 0);
> +        assert_se(calendar_spec_from_string("", &c, NULL) < 0);
> +        assert_se(calendar_spec_from_string("7", &c, NULL) < 0);
> +        assert_se(calendar_spec_from_string("121212:1:2", &c, NULL) < 0);
>  
>          return 0;
>  }
> -- 
> 1.9.2
> 
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel


More information about the systemd-devel mailing list