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. Signed-off-by: Alexander Bashmakov <pkunk...@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@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel