Discussion:
Bug#882851: live-config: Wrong time when RTC is set to local time
Add Reply
Santiago García Mantiñán
2017-11-27 14:00:01 UTC
Reply
Permalink
Package: live-config
Version: 5.20170112
Severity: normal

Hi!

This may be a follow up of #824197, I believe that the patches that were
introduced then don't fix the problem, at least not now.

I'm testing this on a live network image which was built using stretch and
has as boot parameters:
boot=live components config hostname=coru username=debian locales=es_ES.UTF-8,gl_ES.UTF-8 keyboard-layouts=es timezone=Europe/Madrid utc=no netboot=cifs nfsroot=//10.10.50.10/debian-live-amd64 noroot quiet

The important part here is that the clock is supposed to be in local time
(we have the utc=no to signal this and indeed the /etc/adjtime on the live
system file says LOCAL) and we are on CET (timezone=Europe/Madrid).

However, the system adds 1 hour to the rtc even though we are saying that it
is on local time anyway.

I believe that systemd is reading /etc/adjtime before live systems adds the
LOCAL label to it, or something similar (this is just my thought, no
evicence pointing at this yet). This is what timedatectl says after booting:

Local time: jue 2017-11-23 09:25:36 CET
Universal time: jue 2017-11-23 08:25:36 UTC
RTC time: jue 2017-11-23 08:25:35
Time zone: Europe/Madrid (CET, +0100)
Network time on: yes
NTP synchronized: no
RTC in local TZ: yes

As you can see it detects that we have the rtc on local time however the
info is incoherent, it is showing that the rtc has 8:25 and utc is is 8:25
with a TZ of +1 and the RTC in local TZ :-(

I did contact Raphael Hertzog about this and he was so kind to produce a
patch on which we changed live-config to use timedatectl instead of just
changing /etc/adjtime, but this didn't help either. Here is Raphael's patch
with a little typo fixed:

diff --git a/components/1120-util-linux b/components/1120-util-linux
index 8bb45e5..b078df5 100755
--- a/components/1120-util-linux
+++ b/components/1120-util-linux
@@ -43,25 +43,24 @@ Config ()
then
case "${LIVE_UTC}" in
yes)
-
-cat > /etc/adjtime << EOF
-0.0 0 0.0
-0
-UTC
-EOF
-
+ set_local_rtc=0
+ adjtime=UTC
;;

no)
-
-cat > /etc/adjtime << EOF
-0.0 0 0.0
-0
-LOCAL
-EOF
-
+ set_local_rtc=1
+ adjtime=LOCAL
;;
esac
+ if which timedatectl >/dev/null 2>&1; then
+ timedatectl set-local-rtc $set_local_rtc --adjust-system-clock
+ else
+ cat > /etc/adjtime <<-EOF
+ 0.0 0 0.0
+ 0
+ $adjtime
+ EOF
+ fi
fi

# Creating state file

The problem seems to be that when this script is run timedatectl doesn't
have enough services to be able to do anything, so it doesn't do a thing.

I have done some tests and at the time 1120-util-linux just a few systemd
services are running:
root 441 0.6 0.4 39176 4400 ? Ss 15:04 0:00 /lib/systemd/systemd-journald
systemd+ 492 0.4 0.4 129344 4192 ? Ssl 15:04 0:00 /lib/systemd/systemd-timesyncd
in fact, no other service is running except for init, lvmetad, the kernel
processes and live-config itself.

So... the question here is... how to we tell systemd at this time of the
boot process that we have the RTC in LOCAL time if setting LOCAL on third
line of /etc/adjtime at this time doesn't work and we cannot use timedatectl?

I have tested this both with live-config from stable and unstable.

If you want me to do any tests or need any other info just let me know.

Regards.


Kernel: Linux 4.9.0-4-amd64 (SMP w/4 CPU cores)
Locale: LANG=gl_ES.UTF-8, LC_CTYPE=gl_ES.UTF-8 (charmap=UTF-8), LANGUAGE=gl_ES.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages live-config depends on:
ii live-config-systemd [live-config-backend] 5.20170112+nmu1

Versions of packages live-config recommends:
ii iproute2 4.9.0-1
ii keyboard-configuration 1.164
ii live-config-doc 5.20170112
pn live-tools <none>
ii locales 2.24-11+deb9u1
ii locales-all 2.24-11+deb9u1
ii sudo 1.8.19p1-2.1
pn user-setup <none>

Versions of packages live-config suggests:
ii pciutils 1:3.5.2-1
ii wget 1.18-5+deb9u1

-- no debconf information
intrigeri
2018-11-18 11:30:02 UTC
Reply
Permalink
Hi Santiago and others,
Post by Santiago García Mantiñán
I believe that systemd is reading /etc/adjtime before live systems adds the
LOCAL label to it, or something similar (this is just my thought, no
evicence pointing at this yet).
Right, systemd starts before live-config (well, it starts live-config)
so live-config's 1120-util-linux is simply late at the party.

FWIW the relevant systemd code lives in the initialize_clock function
(which calls clock_is_localtime, that parses /etc/adjtime).
Post by Santiago García Mantiñán
I have done some tests and at the time 1120-util-linux just a few systemd
root 441 0.6 0.4 39176 4400 ? Ss 15:04 0:00 /lib/systemd/systemd-journald
systemd+ 492 0.4 0.4 129344 4192 ? Ssl 15:04 0:00 /lib/systemd/systemd-timesyncd
in fact, no other service is running except for init, lvmetad, the kernel
processes and live-config itself.
I think timedatectl talks to systemd-timedated.service which is
activated on request over D-Bus. D-Bus typically starts after
live-config but systemd sets up its listening socket early, so I'm not
sure what's going on. I'm not sure that we can expect timedatectl to
work during this stage of the boot process but if you want to go
further down this path, I would suggest trying to do that in a new
live-config-hwclock.service that starts after dbus.service, at least
to better understand what's going on; and if despaired, add some
debugging to method_set_local_rtc in timedated.c.
Post by Santiago García Mantiñán
So... the question here is... how to we tell systemd at this time of the
boot process that we have the RTC in LOCAL time if setting LOCAL on third
line of /etc/adjtime at this time doesn't work and we cannot use timedatectl?
I think there are three main options:

1. Have live-config use hwclock to apply the updated /etc/adjtime

I guess calling "hwclock --systz" when utc=no should do
the trick: that's what dracut does in the initrd it generates,
whenever /etc/adjtime says "LOCAL". But beware:

- Reading the systemd source code and hwclock manpage, it seems
that some of the operations we want to perform only work the very
first time. So once systemd has done them once, it may be too
late, so I'm not sure if this can possibly work. But I think it's
cheap enough to be worth trying.

- Brutally applying a N hours offset to the system time while other
services have already started has potential to break all kinds of
things. Thankfully we have DefaultDependencies=no and
Before=basic.target so the risk is somewhat limited. It might be
worth checking if there's anything else we can do to start
live-config even earlier, before other important services that
have DefaultDependencies=no and might dislike time travel.

2. Move this to live-boot

There, mimic what dracut does and call "hwclock --systz" when
utc=no. I don't know if we also need to write /etc/adjtime there
and I don't know if there's a hook point for initramfs-tools
scripts to run after the root FS has been mounted read-write but
before init is started.

If that works and option #1 doesn't, it can be the cheapest
short-term solution. Long-term, given the move to dracut seems
unavoidable, it adds code that will need to be ported, which might
be problematic (although I expect that teaching dracut to honor
utc= would be easy).

3. Move this to systemd

i.e. add the equivalent of the live-config.utc= option there and
make sure clock_is_localtime honors it. At first glance it looks
like the best option: every systemd-based OS benefits from it, this
works with dracut too, and we can remove code from live-config.

Assuming that would be accepted upstream, the only major downside
I see is that it makes it harder to implement automatic discovery
of "is RTC in UTC?", which I'm very interested in: that's why
I landed here in the first place, will file a wishlist bug blocked
by this one shortly.

So I would recommend trying (1) and if that fails, trying (2).

Meta: is this something you're interested in working on
further yourself?

Cheers,
--
intrigeri
intrigeri
2019-10-09 06:20:01 UTC
Reply
Permalink
Hi Marcel,
has anything changed about this situation since a year ago?
I'm not aware of any change in this respect and I'm confident that
live-config contributors would have updated this bug report
if there had been changes.
I think you have described the options very well and I also liked
your proposal on 914001.. I have one day to get it implemented 😅 ..
Mind assisting me a bit? 🤓
I'm afraid I can make time for this under such a tight timeline :/
But if you come back to it later, I'll be there :)

Cheers,
--
intrigeri
Marcel Partap
2019-12-02 21:50:01 UTC
Reply
Permalink
... with os-prober, if that is available
---
components/1120-util-linux | 48 +++++++++++++++++++++++++++++++-------
1 file changed, 39 insertions(+), 9 deletions(-)

diff --git a/components/1120-util-linux b/components/1120-util-linux
index 8bb45e5..65aa1be 100755
--- a/components/1120-util-linux
+++ b/components/1120-util-linux
@@ -21,13 +21,21 @@ Cmdline ()
;;
esac
done
+
+ # If not explicitly given, auto-detect
+ if [ -n "${LIVE_UTC}" ]
+ then
+ LIVE_UTC="auto"
+ fi
+
}

Init ()
{
# Checking if package is installed
if [ ! -e /var/lib/dpkg/info/util-linux.list ] || \
- [ -e /var/lib/live/config/util-linux ]
+ # and wether previously configured or auto-detect mode active
+ [ -e /var/lib/live/config/util-linux -a "${LIVE_UTC}" != "auto" ]
then
exit 0
fi
@@ -39,10 +47,20 @@ Config ()
{
rm -f /etc/rc?.d/*hwclock*

- if [ -n "${LIVE_UTC}" ]
+ # if os-prober is installed, use it to detect windows installations
+ if [ "${LIVE_UTC}" = "auto" ] && [ -x /usr/bin/os-prober ]
then
- case "${LIVE_UTC}" in
- yes)
+ if os-prober | grep -qsi windows
+ then
+ LIVE_UTC=no
+ else
+ LIVE_UTC=yes
+ fi
+
+ fi
+
+ case "${LIVE_UTC}" in
+ yes)

cat > /etc/adjtime << EOF
0.0 0 0.0
@@ -50,19 +68,31 @@ cat > /etc/adjtime << EOF
UTC
EOF

- ;;
+ ;;

- no)
+ no)

cat > /etc/adjtime << EOF
0.0 0 0.0
0
LOCAL
EOF
+ # prevent "System clock time unset or jumped
+ # backwards, restoring from recorded timestamp"
+ # oh Lennart
+ pgrep systemd-timesyncd && SYSD=1
+ TIMEFILE=/var/lib/systemd/timesync/clock

- ;;
- esac
- fi
+ [ -e $TIMEFILE ] && rm -v $TIMEFILE
+ [ "$SYSD" = "1" ] && systemctl stop systemd-timesyncd
+
+ # tell kernel to set the timezone and
+ # reset the system clock to local time
+ hwclock --systz --localtime
+
+ [ "$SYSD" = "1" ] && systemctl start systemd-timesyncd
+ ;;
+ esac

# Creating state file
touch /var/lib/live/config/util-linux
--
2.24.0

Loading...