[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