Merge pull request #12007 from poettering/clock-change
.timer OnClockChange= and OnTimezoneChange= settings
This commit is contained in:
@@ -144,9 +144,6 @@ Features:
|
||||
* When reloading configuration PID 1 should reset all its properties to the
|
||||
original defaults before calling parse_config()
|
||||
|
||||
* Add OnTimezoneChange= and OnTimeChange= stanzas to .timer units in order to
|
||||
schedule events based on time and timezone changes.
|
||||
|
||||
* nspawn: greater control over selinux label?
|
||||
|
||||
* hibernate/s2h: make this robust and safe to enable in Fedora by default.
|
||||
@@ -828,9 +825,7 @@ Features:
|
||||
|
||||
* timer units:
|
||||
- timer units should get the ability to trigger when:
|
||||
o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET)
|
||||
o DST changes
|
||||
o timezone changes
|
||||
- Modulate timer frequency based on battery state
|
||||
|
||||
* add libsystemd-password or so to query passwords during boot using the password agent logic
|
||||
|
||||
@@ -335,10 +335,12 @@ All automount unit setting is available to transient units:
|
||||
Most timer unit settings are available to transient units.
|
||||
|
||||
```
|
||||
✓ OnCalendar=
|
||||
✓ OnActiveSec=
|
||||
✓ OnBootSec=
|
||||
✓ OnCalendar=
|
||||
✓ OnClockChange=
|
||||
✓ OnStartupSec=
|
||||
✓ OnTimezoneChange
|
||||
✓ OnUnitActiveSec=
|
||||
✓ OnUnitInactiveSec=
|
||||
✓ Persistent=
|
||||
|
||||
@@ -316,6 +316,18 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--on-clock-change</option></term>
|
||||
<term><option>--on-timezone-change</option></term>
|
||||
|
||||
<listitem><para>Defines a trigger based on system clock jumps or timezone changes for starting the
|
||||
specified command. See <varname>OnClockChange=</varname> and <varname>OnTimezoneChange=</varname> in
|
||||
<citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. These
|
||||
options are shortcuts for <command>--timer-property=OnClockChange=yes</command> and
|
||||
<command>--timer-property=OnTimezoneChange=yes</command>. These options may not be combined with
|
||||
<option>--scope</option> or <option>--pty</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--path-property=</option></term>
|
||||
<term><option>--socket-property=</option></term>
|
||||
|
||||
@@ -259,6 +259,17 @@
|
||||
<varname>AccuracySec=1us</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>OnClockChange=</varname></term>
|
||||
<term><varname>OnTimezoneChange=</varname></term>
|
||||
|
||||
<listitem><para>These options take boolean arguments. When true, the service unit will be triggered
|
||||
when the system clock (<constant>CLOCK_REALTIME</constant>) jumps relative to the monotonic clock
|
||||
(<constant>CLOCK_MONOTONIC</constant>), or when the local system timezone is modified. These options
|
||||
can be used alone or in combination with other timer expressions (see above) within the same timer
|
||||
unit. These options default to false.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Unit=</varname></term>
|
||||
|
||||
|
||||
+28
-12
@@ -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("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("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("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),
|
||||
@@ -171,6 +173,12 @@ static int bus_timer_set_transient_property(
|
||||
if (streq(name, "RemainAfterElapse"))
|
||||
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")) {
|
||||
const char *base_name;
|
||||
usec_t usec = 0;
|
||||
@@ -194,12 +202,14 @@ static int bus_timer_set_transient_property(
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", base_name,
|
||||
format_timespan(ts, sizeof(ts), usec, USEC_PER_MSEC));
|
||||
|
||||
v = new0(TimerValue, 1);
|
||||
v = new(TimerValue, 1);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
v->base = b;
|
||||
v->value = usec;
|
||||
*v = (TimerValue) {
|
||||
.base = b,
|
||||
.value = usec,
|
||||
};
|
||||
|
||||
LIST_PREPEND(value, t->values, v);
|
||||
}
|
||||
@@ -247,12 +257,14 @@ static int bus_timer_set_transient_property(
|
||||
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", base_name, str);
|
||||
|
||||
v = new0(TimerValue, 1);
|
||||
v = new(TimerValue, 1);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
v->base = b;
|
||||
v->calendar_spec = TAKE_PTR(c);
|
||||
*v = (TimerValue) {
|
||||
.base = b,
|
||||
.calendar_spec = TAKE_PTR(c),
|
||||
};
|
||||
|
||||
LIST_PREPEND(value, t->values, v);
|
||||
}
|
||||
@@ -300,12 +312,14 @@ static int bus_timer_set_transient_property(
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name,
|
||||
format_timespan(time, sizeof(time), usec, USEC_PER_MSEC));
|
||||
|
||||
v = new0(TimerValue, 1);
|
||||
v = new(TimerValue, 1);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
v->base = b;
|
||||
v->value = usec;
|
||||
*v = (TimerValue) {
|
||||
.base = b,
|
||||
.value = usec,
|
||||
};
|
||||
|
||||
LIST_PREPEND(value, t->values, v);
|
||||
}
|
||||
@@ -333,12 +347,14 @@ static int bus_timer_set_transient_property(
|
||||
|
||||
unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, str);
|
||||
|
||||
v = new0(TimerValue, 1);
|
||||
v = new(TimerValue, 1);
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
v->base = TIMER_CALENDAR;
|
||||
v->calendar_spec = TAKE_PTR(c);
|
||||
*v = (TimerValue) {
|
||||
.base = TIMER_CALENDAR,
|
||||
.calendar_spec = TAKE_PTR(c),
|
||||
};
|
||||
|
||||
LIST_PREPEND(value, t->values, v);
|
||||
}
|
||||
|
||||
@@ -433,6 +433,8 @@ Timer.OnBootSec, config_parse_timer, TIMER_BOOT,
|
||||
Timer.OnStartupSec, config_parse_timer, TIMER_STARTUP, 0
|
||||
Timer.OnUnitActiveSec, config_parse_timer, TIMER_UNIT_ACTIVE, 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.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
|
||||
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
|
||||
|
||||
+22
-8
@@ -77,7 +77,7 @@ static int timer_verify(Timer *t) {
|
||||
if (UNIT(t)->load_state != UNIT_LOADED)
|
||||
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.");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
@@ -215,14 +215,18 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
"%sPersistent: %s\n"
|
||||
"%sWakeSystem: %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_result_to_string(t->result),
|
||||
prefix, trigger ? trigger->id : "n/a",
|
||||
prefix, yes_no(t->persistent),
|
||||
prefix, yes_no(t->wake_system),
|
||||
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) {
|
||||
|
||||
@@ -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.");
|
||||
timer_enter_elapsed(t, leave_around);
|
||||
return;
|
||||
@@ -815,8 +819,13 @@ static void timer_time_change(Unit *u) {
|
||||
if (t->last_trigger.realtime > ts)
|
||||
t->last_trigger.realtime = ts;
|
||||
|
||||
log_unit_debug(u, "Time change, recalculating next elapse.");
|
||||
timer_enter_waiting(t, true);
|
||||
if (t->on_clock_change) {
|
||||
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) {
|
||||
@@ -827,8 +836,13 @@ static void timer_timezone_change(Unit *u) {
|
||||
if (t->state != TIMER_WAITING)
|
||||
return;
|
||||
|
||||
log_unit_debug(u, "Timezone change, recalculating next elapse.");
|
||||
timer_enter_waiting(t, false);
|
||||
if (t->on_timezone_change) {
|
||||
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] = {
|
||||
|
||||
@@ -57,6 +57,8 @@ struct Timer {
|
||||
bool persistent;
|
||||
bool wake_system;
|
||||
bool remain_after_elapse;
|
||||
bool on_clock_change;
|
||||
bool on_timezone_change;
|
||||
|
||||
char *stamp_path;
|
||||
};
|
||||
|
||||
+34
-12
@@ -60,7 +60,7 @@ static enum {
|
||||
static char **arg_path_property = NULL;
|
||||
static char **arg_socket_property = NULL;
|
||||
static char **arg_timer_property = NULL;
|
||||
static bool with_timer = false;
|
||||
static bool arg_with_timer = false;
|
||||
static bool arg_quiet = false;
|
||||
static bool arg_aggressive_gc = false;
|
||||
static char *arg_working_directory = NULL;
|
||||
@@ -124,6 +124,8 @@ static int help(void) {
|
||||
" --on-unit-active=SECONDS Run SECONDS after the last activation\n"
|
||||
" --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\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"
|
||||
"\nSee the %s for details.\n"
|
||||
, program_invocation_short_name
|
||||
@@ -170,6 +172,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_ON_UNIT_ACTIVE,
|
||||
ARG_ON_UNIT_INACTIVE,
|
||||
ARG_ON_CALENDAR,
|
||||
ARG_ON_TIMEZONE_CHANGE,
|
||||
ARG_ON_CLOCK_CHANGE,
|
||||
ARG_TIMER_PROPERTY,
|
||||
ARG_PATH_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-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
|
||||
{ "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 },
|
||||
{ "path-property", required_argument, NULL, ARG_PATH_PROPERTY },
|
||||
{ "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY },
|
||||
@@ -339,7 +345,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
with_timer = true;
|
||||
arg_with_timer = true;
|
||||
break;
|
||||
|
||||
case ARG_ON_BOOT:
|
||||
@@ -347,7 +353,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
with_timer = true;
|
||||
arg_with_timer = true;
|
||||
break;
|
||||
|
||||
case ARG_ON_STARTUP:
|
||||
@@ -355,7 +361,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
with_timer = true;
|
||||
arg_with_timer = true;
|
||||
break;
|
||||
|
||||
case ARG_ON_UNIT_ACTIVE:
|
||||
@@ -363,7 +369,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
with_timer = true;
|
||||
arg_with_timer = true;
|
||||
break;
|
||||
|
||||
case ARG_ON_UNIT_INACTIVE:
|
||||
@@ -371,7 +377,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
with_timer = true;
|
||||
arg_with_timer = true;
|
||||
break;
|
||||
|
||||
case ARG_ON_CALENDAR:
|
||||
@@ -379,7 +385,23 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
with_timer = true;
|
||||
arg_with_timer = true;
|
||||
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:
|
||||
@@ -387,7 +409,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (strv_extend(&arg_timer_property, optarg) < 0)
|
||||
return log_oom();
|
||||
|
||||
with_timer = with_timer ||
|
||||
arg_with_timer = arg_with_timer ||
|
||||
STARTSWITH_SET(optarg,
|
||||
"OnActiveSec=",
|
||||
"OnBootSec=",
|
||||
@@ -455,10 +477,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
assert_not_reached("Unhandled option");
|
||||
}
|
||||
|
||||
with_trigger = !!arg_path_property || !!arg_socket_property || with_timer;
|
||||
with_trigger = !!arg_path_property || !!arg_socket_property || arg_with_timer;
|
||||
|
||||
/* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
|
||||
if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) with_timer > 1)
|
||||
if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) arg_with_timer > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Only single trigger (path, socket, timer) unit can be created.");
|
||||
|
||||
@@ -554,7 +576,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Path, socket or timer options are not supported in --scope mode.");
|
||||
|
||||
if (arg_timer_property && !with_timer)
|
||||
if (arg_timer_property && !arg_with_timer)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--timer-property= has no effect without any other timer options.");
|
||||
|
||||
@@ -1646,7 +1668,7 @@ static int run(int argc, char* argv[]) {
|
||||
r = start_transient_trigger(bus, ".path");
|
||||
else if (arg_socket_property)
|
||||
r = start_transient_trigger(bus, ".socket");
|
||||
else if (with_timer)
|
||||
else if (arg_with_timer)
|
||||
r = start_transient_trigger(bus, ".timer");
|
||||
else
|
||||
r = start_transient_service(bus, &retval);
|
||||
|
||||
@@ -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) {
|
||||
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);
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
../TEST-01-BASIC/Makefile
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
|
||||
# ex: ts=8 sw=4 sts=4 et filetype=sh
|
||||
set -e
|
||||
TEST_DESCRIPTION="test OnClockChange= + OnTimezoneChange="
|
||||
TEST_NO_NSPAWN=1
|
||||
|
||||
. $TEST_BASE_DIR/test-functions
|
||||
|
||||
test_setup() {
|
||||
create_empty_image
|
||||
mkdir -p $TESTDIR/root
|
||||
mount ${LOOPDEV}p1 $TESTDIR/root
|
||||
|
||||
(
|
||||
LOG_LEVEL=5
|
||||
eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
|
||||
|
||||
inst_any /usr/share/zoneinfo/Europe/Kiev
|
||||
inst_any /usr/share/zoneinfo/Europe/Berlin
|
||||
|
||||
setup_basic_environment
|
||||
|
||||
# mask some services that we do not want to run in these tests
|
||||
ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
|
||||
ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
|
||||
ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
|
||||
ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
|
||||
ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
|
||||
ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
|
||||
|
||||
# setup the testsuite service
|
||||
cat >$initdir/etc/systemd/system/testsuite.service <<EOF
|
||||
[Unit]
|
||||
Description=Testsuite service
|
||||
|
||||
[Service]
|
||||
ExecStart=/testsuite.sh
|
||||
Type=oneshot
|
||||
StandardOutput=tty
|
||||
StandardError=tty
|
||||
NotifyAccess=all
|
||||
EOF
|
||||
cp testsuite.sh $initdir/
|
||||
|
||||
setup_testsuite
|
||||
) || return 1
|
||||
|
||||
ddebug "umount $TESTDIR/root"
|
||||
umount $TESTDIR/root
|
||||
}
|
||||
|
||||
do_test "$@"
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
|
||||
# ex: ts=8 sw=4 sts=4 et filetype=sh
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
systemd-analyze set-log-level debug
|
||||
systemd-analyze set-log-target console
|
||||
|
||||
systemctl disable --now systemd-timesyncd.service
|
||||
|
||||
timedatectl set-timezone Europe/Berlin
|
||||
timedatectl set-time 1980-10-15
|
||||
|
||||
systemd-run --on-timezone-change touch /tmp/timezone-changed
|
||||
systemd-run --on-clock-change touch /tmp/clock-changed
|
||||
|
||||
! test -f /tmp/timezone-changed
|
||||
! test -f /tmp/clock-changed
|
||||
|
||||
timedatectl set-timezone Europe/Kiev
|
||||
|
||||
while ! test -f /tmp/timezone-changed ; do sleep .5 ; done
|
||||
|
||||
timedatectl set-time 2018-1-1
|
||||
|
||||
while ! test -f /tmp/clock-changed ; do sleep .5 ; done
|
||||
|
||||
systemd-analyze set-log-level info
|
||||
|
||||
echo OK > /testok
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user