core: optionally, trigger .timer units on timezone and clock changes
Fixes: #6228
This commit is contained in:
parent
787be190a8
commit
efebb613c7
|
@ -335,10 +335,12 @@ All automount unit setting is available to transient units:
|
||||||
Most timer unit settings are available to transient units.
|
Most timer unit settings are available to transient units.
|
||||||
|
|
||||||
```
|
```
|
||||||
✓ OnCalendar=
|
|
||||||
✓ OnActiveSec=
|
✓ OnActiveSec=
|
||||||
✓ OnBootSec=
|
✓ OnBootSec=
|
||||||
|
✓ OnCalendar=
|
||||||
|
✓ OnClockChange=
|
||||||
✓ OnStartupSec=
|
✓ OnStartupSec=
|
||||||
|
✓ OnTimezoneChange
|
||||||
✓ OnUnitActiveSec=
|
✓ OnUnitActiveSec=
|
||||||
✓ OnUnitInactiveSec=
|
✓ OnUnitInactiveSec=
|
||||||
✓ Persistent=
|
✓ Persistent=
|
||||||
|
|
|
@ -123,6 +123,8 @@ const sd_bus_vtable bus_timer_vtable[] = {
|
||||||
SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||||
SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
|
||||||
|
SD_BUS_PROPERTY("OnClockChange", "b", bus_property_get_bool, offsetof(Timer, on_clock_change), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("OnTimezoneChange", "b", bus_property_get_bool, offsetof(Timer, on_timezone_change), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||||
SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||||
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||||
|
@ -171,6 +173,12 @@ static int bus_timer_set_transient_property(
|
||||||
if (streq(name, "RemainAfterElapse"))
|
if (streq(name, "RemainAfterElapse"))
|
||||||
return bus_set_transient_bool(u, name, &t->remain_after_elapse, message, flags, error);
|
return bus_set_transient_bool(u, name, &t->remain_after_elapse, message, flags, error);
|
||||||
|
|
||||||
|
if (streq(name, "OnTimezoneChange"))
|
||||||
|
return bus_set_transient_bool(u, name, &t->on_timezone_change, message, flags, error);
|
||||||
|
|
||||||
|
if (streq(name, "OnClockChange"))
|
||||||
|
return bus_set_transient_bool(u, name, &t->on_clock_change, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "TimersMonotonic")) {
|
if (streq(name, "TimersMonotonic")) {
|
||||||
const char *base_name;
|
const char *base_name;
|
||||||
usec_t usec = 0;
|
usec_t usec = 0;
|
||||||
|
|
|
@ -433,6 +433,8 @@ Timer.OnBootSec, config_parse_timer, TIMER_BOOT,
|
||||||
Timer.OnStartupSec, config_parse_timer, TIMER_STARTUP, 0
|
Timer.OnStartupSec, config_parse_timer, TIMER_STARTUP, 0
|
||||||
Timer.OnUnitActiveSec, config_parse_timer, TIMER_UNIT_ACTIVE, 0
|
Timer.OnUnitActiveSec, config_parse_timer, TIMER_UNIT_ACTIVE, 0
|
||||||
Timer.OnUnitInactiveSec, config_parse_timer, TIMER_UNIT_INACTIVE, 0
|
Timer.OnUnitInactiveSec, config_parse_timer, TIMER_UNIT_INACTIVE, 0
|
||||||
|
Timer.OnClockChange, config_parse_bool, 0, offsetof(Timer, on_clock_change)
|
||||||
|
Timer.OnTimezoneChange, config_parse_bool, 0, offsetof(Timer, on_timezone_change)
|
||||||
Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
|
Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
|
||||||
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
|
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
|
||||||
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
|
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
|
||||||
|
|
|
@ -77,7 +77,7 @@ static int timer_verify(Timer *t) {
|
||||||
if (UNIT(t)->load_state != UNIT_LOADED)
|
if (UNIT(t)->load_state != UNIT_LOADED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!t->values) {
|
if (!t->values && !t->on_clock_change && !t->on_timezone_change) {
|
||||||
log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
|
log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
@ -215,14 +215,18 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
|
||||||
"%sPersistent: %s\n"
|
"%sPersistent: %s\n"
|
||||||
"%sWakeSystem: %s\n"
|
"%sWakeSystem: %s\n"
|
||||||
"%sAccuracy: %s\n"
|
"%sAccuracy: %s\n"
|
||||||
"%sRemainAfterElapse: %s\n",
|
"%sRemainAfterElapse: %s\n"
|
||||||
|
"%sOnClockChange: %s\n"
|
||||||
|
"%sOnTimeZoneChange %s\n",
|
||||||
prefix, timer_state_to_string(t->state),
|
prefix, timer_state_to_string(t->state),
|
||||||
prefix, timer_result_to_string(t->result),
|
prefix, timer_result_to_string(t->result),
|
||||||
prefix, trigger ? trigger->id : "n/a",
|
prefix, trigger ? trigger->id : "n/a",
|
||||||
prefix, yes_no(t->persistent),
|
prefix, yes_no(t->persistent),
|
||||||
prefix, yes_no(t->wake_system),
|
prefix, yes_no(t->wake_system),
|
||||||
prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
|
prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
|
||||||
prefix, yes_no(t->remain_after_elapse));
|
prefix, yes_no(t->remain_after_elapse),
|
||||||
|
prefix, yes_no(t->on_clock_change),
|
||||||
|
prefix, yes_no(t->on_timezone_change));
|
||||||
|
|
||||||
LIST_FOREACH(value, v, t->values) {
|
LIST_FOREACH(value, v, t->values) {
|
||||||
|
|
||||||
|
@ -474,7 +478,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found_monotonic && !found_realtime) {
|
if (!found_monotonic && !found_realtime && !t->on_timezone_change && !t->on_clock_change) {
|
||||||
log_unit_debug(UNIT(t), "Timer is elapsed.");
|
log_unit_debug(UNIT(t), "Timer is elapsed.");
|
||||||
timer_enter_elapsed(t, leave_around);
|
timer_enter_elapsed(t, leave_around);
|
||||||
return;
|
return;
|
||||||
|
@ -815,8 +819,13 @@ static void timer_time_change(Unit *u) {
|
||||||
if (t->last_trigger.realtime > ts)
|
if (t->last_trigger.realtime > ts)
|
||||||
t->last_trigger.realtime = ts;
|
t->last_trigger.realtime = ts;
|
||||||
|
|
||||||
log_unit_debug(u, "Time change, recalculating next elapse.");
|
if (t->on_clock_change) {
|
||||||
timer_enter_waiting(t, true);
|
log_unit_debug(u, "Time change, triggering activation.");
|
||||||
|
timer_enter_running(t);
|
||||||
|
} else {
|
||||||
|
log_unit_debug(u, "Time change, recalculating next elapse.");
|
||||||
|
timer_enter_waiting(t, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void timer_timezone_change(Unit *u) {
|
static void timer_timezone_change(Unit *u) {
|
||||||
|
@ -827,8 +836,13 @@ static void timer_timezone_change(Unit *u) {
|
||||||
if (t->state != TIMER_WAITING)
|
if (t->state != TIMER_WAITING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
log_unit_debug(u, "Timezone change, recalculating next elapse.");
|
if (t->on_timezone_change) {
|
||||||
timer_enter_waiting(t, false);
|
log_unit_debug(u, "Timezone change, triggering activation.");
|
||||||
|
timer_enter_running(t);
|
||||||
|
} else {
|
||||||
|
log_unit_debug(u, "Timezone change, recalculating next elapse.");
|
||||||
|
timer_enter_waiting(t, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
|
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct Timer {
|
||||||
bool persistent;
|
bool persistent;
|
||||||
bool wake_system;
|
bool wake_system;
|
||||||
bool remain_after_elapse;
|
bool remain_after_elapse;
|
||||||
|
bool on_clock_change;
|
||||||
|
bool on_timezone_change;
|
||||||
|
|
||||||
char *stamp_path;
|
char *stamp_path;
|
||||||
};
|
};
|
||||||
|
|
|
@ -124,6 +124,8 @@ static int help(void) {
|
||||||
" --on-unit-active=SECONDS Run SECONDS after the last activation\n"
|
" --on-unit-active=SECONDS Run SECONDS after the last activation\n"
|
||||||
" --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
|
" --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
|
||||||
" --on-calendar=SPEC Realtime timer\n"
|
" --on-calendar=SPEC Realtime timer\n"
|
||||||
|
" --on-timezone-change Run when the timezone changes\n"
|
||||||
|
" --on-clock-change Run when the realtime clock jumps\n"
|
||||||
" --timer-property=NAME=VALUE Set timer unit property\n"
|
" --timer-property=NAME=VALUE Set timer unit property\n"
|
||||||
"\nSee the %s for details.\n"
|
"\nSee the %s for details.\n"
|
||||||
, program_invocation_short_name
|
, program_invocation_short_name
|
||||||
|
@ -170,6 +172,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_ON_UNIT_ACTIVE,
|
ARG_ON_UNIT_ACTIVE,
|
||||||
ARG_ON_UNIT_INACTIVE,
|
ARG_ON_UNIT_INACTIVE,
|
||||||
ARG_ON_CALENDAR,
|
ARG_ON_CALENDAR,
|
||||||
|
ARG_ON_TIMEZONE_CHANGE,
|
||||||
|
ARG_ON_CLOCK_CHANGE,
|
||||||
ARG_TIMER_PROPERTY,
|
ARG_TIMER_PROPERTY,
|
||||||
ARG_PATH_PROPERTY,
|
ARG_PATH_PROPERTY,
|
||||||
ARG_SOCKET_PROPERTY,
|
ARG_SOCKET_PROPERTY,
|
||||||
|
@ -210,6 +214,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
|
{ "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
|
||||||
{ "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
|
{ "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
|
||||||
{ "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
|
{ "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
|
||||||
|
{ "on-timezone-change",no_argument, NULL, ARG_ON_TIMEZONE_CHANGE},
|
||||||
|
{ "on-clock-change", no_argument, NULL, ARG_ON_CLOCK_CHANGE },
|
||||||
{ "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
|
{ "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
|
||||||
{ "path-property", required_argument, NULL, ARG_PATH_PROPERTY },
|
{ "path-property", required_argument, NULL, ARG_PATH_PROPERTY },
|
||||||
{ "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY },
|
{ "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY },
|
||||||
|
@ -382,6 +388,22 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
arg_with_timer = true;
|
arg_with_timer = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_ON_TIMEZONE_CHANGE:
|
||||||
|
r = add_timer_property("OnTimezoneChange", "yes");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
arg_with_timer = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_ON_CLOCK_CHANGE:
|
||||||
|
r = add_timer_property("OnClockChange", "yes");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
arg_with_timer = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case ARG_TIMER_PROPERTY:
|
case ARG_TIMER_PROPERTY:
|
||||||
|
|
||||||
if (strv_extend(&arg_timer_property, optarg) < 0)
|
if (strv_extend(&arg_timer_property, optarg) < 0)
|
||||||
|
|
|
@ -1499,7 +1499,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
|
||||||
static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
|
static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent"))
|
if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
|
||||||
|
"OnTimezoneChange", "OnClockChange"))
|
||||||
|
|
||||||
return bus_append_parse_boolean(m, field, eq);
|
return bus_append_parse_boolean(m, field, eq);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue