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

Reply via email to