I would like to thank Pat for reviewing and accepting Part I.
As I said in
Part I, most of the date-time problems were in hwclock, not
Slackware. However, there are some needed changes and this is Part II.
To frame this discussion in the Slackware philosophy of 'if it ain't
broke don't fix it':
What's Broke:
1) /etc/hardwareclock and /etc/adjtime easily go out of sync, causing
the Hardware Clock's time scale to be set differently by the init
scripts then when hwclock is called from anywhere else. This has been
the source of, or a complication in, many date-time complaints here
at LQ.
2) without ntpd, or a similar outside correction, it has not been
possible to configure Slackware to keep reasonably good date-time.
What's needed: both the Hardware Clock and System Clock need to be
configurable for 'drift' correction.
The lack of Hardware Clock drift correction is fixed in
util-linux
v2.26 released today.
Slackware needs to be configurable for the System Clock rate, and it
needs to be done *before* calling hwclock during boot. This is required
because all of hwclock's precision is dependent upon the System Clock's
rate being correct. Equally important, the System Clock rate needs to be
configurable to keep good date-time without an outside helper like ntpd.
We could simply add adjtimex calls to rc.S, but I want to suggest that
the date-time configuration be moved into its own rc script for several
reasons:
* It allows System Administrators to customize their date-time
handling in a portable way that can easily be moved between upgrades.
* It allows the System Clock configurations to be set in its rc script
without hacking rc.S. (the rc.clocks script below also allows them to
be set in /etc/default/adjtimex)
* The kernel now sets the System Clock from the Hardware Clock during
boot. Machines that keep their Hardware Clock in UTC and run ntpd may
wish to not run any clock commands from init for faster boot time.
Having the clock related commands in a separate rc script allows the
traditional Slackware method of controlling their use by setting the
executable permissions.
Does it work? Here are the results for an off-line box that is up for 14
and shutdown for about 10 hours per day. It normally loses ~3 seconds
per day, which for a one month period like this would have been around a 90
second loss:
Code:
/usr/sbin/ntpdate -q ntp.lan
19 Jan 22:39:25 ntpdate[2113]: adjust time server ntp.lan offset -0.006518 sec
/usr/sbin/ntpdate -q ntp.lan
19 Feb 06:32:45 ntpdate[2113]: adjust time server ntp.lan offset -0.105969 sec
The problem of /etc/hardwareclock and /etc/adjtime going out of sync is
handled in the new rc.clocks by only using /etc/hardwareclock if its
modification time is newer than /etc/adjtime. This allows setting the
Hardware Clock's time scale with either timeconfig or hwclock without
breaking anything.
THE NEW rc.clocks
Code:
#!/bin/sh
#
# /etc/rc.d/rc.clocks
#
# Init handler for date-time Clocks.
#
# start/stop conventions are followed, but equate to
# boot/shutdown as there are no daemons to run here.
#
# The System Clock drift is compensated by setting
# its tick and frequency. Those work together, the
# first being a course adjustment, the later fine.
# They can be set here or in /etc/default/adjtimex.
# See adjtimex(8)
#
# Drift factor for the Hardware Clock is set in
# /etc/adjtime, see hwclock(8).
# FHS future path will be /var/lib/hwclock/adjtime.
#
# Written for Slackware Linux by J William Piggott <slackware64 gmx com>
# Sat Dec 13 19:00:52 EST 2014
# When the adjtime and hardwareclock files get out of sync it causes the
# init scripts to set the Hardware Clock in a different scale than when
# hwclock is called from anywhere else. To prevent this, only use
# hardwareclock if it is newer than adjtime.
#
HWLOCAL=""
if [ /etc/hardwareclock -nt /etc/adjtime ]; then
if grep -q "^localtime" /etc/hardwareclock 2> /dev/null ; then
HWLOCAL=" --localtime"
else
HWLOCAL=" --utc"
fi
fi
# Default: tick=10000 frequency=0
TICK=10000
FREQ=0
# Set tick and frequency for System Clock.
time_adjtimex() {
if [ -x /sbin/adjtimex ]; then
# The traditional location for system tick and frequency configurations
[ ! -r /etc/default/adjtimex ] || . /etc/default/adjtimex
if /sbin/adjtimex --tick $TICK --frequency $FREQ; then
echo "Set the System Clock rate: tick = $TICK frequency = $FREQ"
else
echo "Unable to set the System Clock rate"
fi
fi
}
# System and Hardware Clock exchanges at boot and shutdown.
time_hwclock() {
if [ -x /sbin/hwclock ]; then
# Verify rtc ioports to prevent system hangs.
if ! grep -q rtc /proc/ioports ; then
CLOCK_OPT=" --directisa"
fi
if [ $1 = "BOOT" ]; then
if /sbin/hwclock${CLOCK_OPT} --hctosys; then
echo "Set the System Clock from the Hardware Clock${CLOCK_OPT}: `date`"
else
echo "Unable to set the System Clock from the Hardware Clock${CLOCK_OPT}"
fi
else
if /sbin/hwclock${HWLOCAL}${CLOCK_OPT} --systohc; then
echo "Set the Hardware Clock${HWLOCAL}${CLOCK_OPT} from the System Clock"
else
echo "Unable to set the Hardware Clock${CLOCK_OPT} from the System Clock"
fi
fi
fi
}
case "$1" in
'start')
time_adjtimex # Must be called before hwclock!
time_hwclock BOOT
;;
'stop')
time_hwclock SHUTDOWN
;;
*)
echo "Usage: $0 is not intended to be called directly"
esac
PATCH rc.S
Code:
diff --git a/rc.S b/rc.S
index 061545b..ee011a4 100644
--- a/rc.S
+++ b/rc.S
@@ -146,21 +146,9 @@ if [ -x /etc/rc.d/rc.fuse ]; then
sh /etc/rc.d/rc.fuse start
fi
-# Set the system time from the hardware clock using hwclock --hctosys.
-if [ -x /sbin/hwclock ]; then
- # Check for a broken motherboard RTC clock (where ioports for rtc are
- # unknown) to prevent hwclock causing a hang:
- if ! grep -q -w rtc /proc/ioports ; then
- CLOCK_OPT="--directisa"
- fi
- if grep -wq "^UTC" /etc/hardwareclock ; then
- echo -n "Setting system time from the hardware clock (UTC): "
- /sbin/hwclock $CLOCK_OPT --utc --hctosys
- else
- echo -n "Setting system time from the hardware clock (localtime): "
- /sbin/hwclock $CLOCK_OPT --localtime --hctosys
- fi
- date
+# Set and Correct date-time, if requested:
+if [ -x /etc/rc.d/rc.clocks ]; then
+ /etc/rc.d/rc.clocks start
fi
# Test to see if the root partition is read-only, like it ought to be.
PATCH rc.6
Code:
diff --git a/rc.6 b/rc.6
index 58234d2..0dc6c89 100644
--- a/rc.6
+++ b/rc.6
@@ -37,20 +37,9 @@ case "$0" in
;;
esac
-# Save the system time to the hardware clock using hwclock --systohc.
-if [ -x /sbin/hwclock ]; then
- # Check for a broken motherboard RTC clock (where ioports for rtc are
- # unknown) to prevent hwclock causing a hang:
- if ! grep -q -w rtc /proc/ioports ; then
- CLOCK_OPT="--directisa"
- fi
- if grep -q "^UTC" /etc/hardwareclock 2> /dev/null ; then
- echo "Saving system time to the hardware clock (UTC)."
- /sbin/hwclock $CLOCK_OPT --utc --systohc
- else
- echo "Saving system time to the hardware clock (localtime)."
- /sbin/hwclock $CLOCK_OPT --localtime --systohc
- fi
+# Save the System Time to the Hardware Clock, if requested:
+if [ -x /etc/rc.d/rc.clocks ]; then
+ /etc/rc.d/rc.clocks stop
fi
# Run any local shutdown scripts: