Package: util-linux Version: 2.19.1-5 Severity: important Tags: patch Back in 2011, hwclock-set was amended to bail out if systemd is present. According to #629811 the rationale was that "systemd > 25 sets the hwclock itself, based on the contents of /etc/adjtime, so /lib/udev/hwclock-set should not do anything if running under systemd."
More accurately however, systemd only determines if the RTC runs at UTC or local time, and warps the system clock accordingly. It does *not* set the system clock from the RTC: An examination of the systemd git repo shows that clock_get_hwclock() is only called from src/timedate/timedated.c in the D-Bus methods SetLocalRTC and RTCTimeUSec. The latter, which reads the RTC, is only called from src/timedate/timedatectl.c when the user invokes "timedatectl status": https://github.com/systemd/systemd/blob/master/src/core/main.c#L1457 https://github.com/systemd/systemd/blob/master/src/basic/clock-util.c#L36 https://github.com/systemd/systemd/blob/master/src/timedate/timedated.c https://github.com/systemd/systemd/blob/master/src/timedate/timedatectl.c In most cases, the kernel itself initializes the system clock from the RTC with the late_initcall rtc_hctosys(): http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/rtc/hctosys.c But this doesn't work if the driver for the RTC is compiled as a module or if the kernel was compiled with CONFIG_RTC_HCTOSYS disabled. One use case where both of these prerequisites are not met is the Raspberry Pi: Raspbian ships with a kernel which disables CONFIG_RTC_HCTOSYS and also compiles all RTC drivers as a module. This makes sense because the Raspberry Pi does not possess an RTC. Instead, people use add-on boards with various types of clocks and it wouldn't be reasonable to link all of their drivers into the kernel. The Internet is full of recipes where /lib/udev/hwclock-set is edited to remove the lines which cause it to bail out when detecting presence of systemd, as otherwise the system clock is never initialized from the RTC. But this approach has the disadvantage that the change will get overwritten whenever the util-linux package is updated. Examples: https://learn.adafruit.com/adding-a-real-time-clock-to-raspberry-pi/set-rtc-time https://afterthoughtsoftware.com/products/rasclock http://spellfoundry.com/sleepy-pi/setting-up-the-real-time-clock-on-raspbian-jessie/ Constrain the check for systemd presence in hwclock-set to the invocation of "hwclock --systz", and do set the system clock from the RTC unless the kernel has already done that (in which case /sys/class/rtc/rtc0/hctosys contains "1".) This patch was developed for and tested successfully on a Revolution Pi by Kunbus GmbH. Cc: Mathias Duckeck <m.duck...@kunbus.de> Cc: Phil Elwell <p...@raspberrypi.org> Signed-off-by: Lukas Wunner <lu...@wunner.de> --- debian/hwclock-set | 18 +++++++++--------- debian/hwclock.rules | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-)
>From 48207793e5131b7fdb8ccd039a20d54db3ce9cc2 Mon Sep 17 00:00:00 2001 From: Lukas Wunner <lu...@wunner.de> Date: Tue, 14 Feb 2017 13:51:38 +0100 Subject: [PATCH] hwclock-set: Synchronize from hwclock despite systemd presence Back in 2011, hwclock-set was amended to bail out if systemd is present. According to #629811 the rationale was that "systemd > 25 sets the hwclock itself, based on the contents of /etc/adjtime, so /lib/udev/hwclock-set should not do anything if running under systemd." More accurately however, systemd only determines if the RTC runs at UTC or local time, and warps the system clock accordingly. It does *not* set the system clock from the RTC: An examination of the systemd git repo shows that clock_get_hwclock() is only called from src/timedate/timedated.c in the D-Bus methods SetLocalRTC and RTCTimeUSec. The latter, which reads the RTC, is only called from src/timedate/timedatectl.c when the user invokes "timedatectl status": https://github.com/systemd/systemd/blob/master/src/core/main.c#L1457 https://github.com/systemd/systemd/blob/master/src/basic/clock-util.c#L36 https://github.com/systemd/systemd/blob/master/src/timedate/timedated.c https://github.com/systemd/systemd/blob/master/src/timedate/timedatectl.c In most cases, the kernel itself initializes the system clock from the RTC with the late_initcall rtc_hctosys(): http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/rtc/hctosys.c But this doesn't work if the driver for the RTC is compiled as a module or if the kernel was compiled with CONFIG_RTC_HCTOSYS disabled. One use case where both of these prerequisites are not met is the Raspberry Pi: Raspbian ships with a kernel which disables CONFIG_RTC_HCTOSYS and also compiles all RTC drivers as a module. This makes sense because the Raspberry Pi does not possess an RTC. Instead, people use add-on boards with various types of clocks and it wouldn't be reasonable to link all of their drivers into the kernel. The Internet is full of recipes where /lib/udev/hwclock-set is edited to remove the lines which cause it to bail out when detecting presence of systemd, as otherwise the system clock is never initialized from the RTC. But this approach has the disadvantage that the change will get overwritten whenever the util-linux package is updated. Examples: https://learn.adafruit.com/adding-a-real-time-clock-to-raspberry-pi/set-rtc-time https://afterthoughtsoftware.com/products/rasclock http://spellfoundry.com/sleepy-pi/setting-up-the-real-time-clock-on-raspbian-jessie/ Constrain the check for systemd presence in hwclock-set to the invocation of "hwclock --systz", and do set the system clock from the RTC unless the kernel has already done that (in which case /sys/class/rtc/rtc0/hctosys contains "1".) This patch was developed for and tested successfully on a Revolution Pi by Kunbus GmbH. Cc: Mathias Duckeck <m.duck...@kunbus.de> Cc: Phil Elwell <p...@raspberrypi.org> Signed-off-by: Lukas Wunner <lu...@wunner.de> --- debian/hwclock-set | 18 +++++++++--------- debian/hwclock.rules | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/debian/hwclock-set b/debian/hwclock-set index eacf948df..ad2575a7d 100755 --- a/debian/hwclock-set +++ b/debian/hwclock-set @@ -3,10 +3,7 @@ # was copied by the kernel was in localtime. dev=$1 - -if [ -e /run/systemd/system ] ; then - exit 0 -fi +kernel_hctosys=/sys/class/rtc/$2/hctosys if [ -e /run/udev/hwclock-set ]; then exit 0 @@ -26,11 +23,14 @@ if [ -f /etc/default/hwclock ] ; then fi if [ yes = "$BADYEAR" ] ; then - /sbin/hwclock --rtc=$dev --systz --badyear - /sbin/hwclock --rtc=$dev --hctosys --badyear -else - /sbin/hwclock --rtc=$dev --systz - /sbin/hwclock --rtc=$dev --hctosys + badyear="--badyear" +fi + +if [ ! -e /run/systemd/system ] ; then + /sbin/hwclock --rtc=$dev --systz $badyear +fi +if [ ! -e $kernel_hctosys -o "$(cat $kernel_hctosys)" != 1 ] ; then + /sbin/hwclock --rtc=$dev --hctosys $badyear fi # Note 'touch' may not be available in initramfs diff --git a/debian/hwclock.rules b/debian/hwclock.rules index 972e4aab3..3c42069ac 100644 --- a/debian/hwclock.rules +++ b/debian/hwclock.rules @@ -1,4 +1,4 @@ # Set the System Time from the Hardware Clock and set the kernel's timezone # value to the local timezone when the kernel clock module is loaded. -KERNEL=="rtc0", RUN+="/lib/udev/hwclock-set $root/$name" +KERNEL=="rtc0", RUN+="/lib/udev/hwclock-set $root/$name $kernel" -- 2.11.0