[systemd-devel] [PATCH] timer: allow user to control activation time of cron-like timers
Alexander Bashmakov
pkunk.ab at gmail.com
Sun May 11 08:53:55 PDT 2014
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.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
More information about the systemd-devel
mailing list