Bug#66571: hwclock: [FIX] Here's a possible fix for #50572, #60734
Package: util-linux
Version: 2.10f-5.1
Severity: wishlist
Reported as a wishlist, because this needs some maintainer elbow-grease to
be applied :-)
Here's a strategy plan (plus patches) to address
#50572 (hwclock.sh runs too late), #60734 (hwclock starts too late). Someone
could merge these two bugs, BTW.
CCed to debian-devel because #60734 was considered RC by the submitter, and
downgraded without a fix because one is not exactly easy. I don't know if
this kind of change is a good idea during deep freeze, but here it is
anyway.
CCed to original bug submitters because I don't have an Alpha, and therefore
I may have misunderstood the problem.
This fix requires changes to the package, which I have not included because:
1. I'm not a developer, nor am I well versed in the packaging system
2. I didn't understand some suspicious stuff in debian/rules regarding
update-rc.d -f, the whole rm -f of /etc/rc?.d stuff and the lack of a
update-rc.d remove in postrm.
WARNING: I did some very, very light testing with this, but as my clock is a
reasonably well behaved RTC which I keep in UTC, I don't even need hwclock
to begin with... so you'd better have a look at the scripts and look for
anything I missed.
The Issues:
- Machines with the hardware clock set to local time or with weird
hardware clocks (some Alphas?) have problems with the current way things
are done (see #60734, #50572), so this bug must be addressed sooner or
later.
- modutils rc script causes problems if started before the system clock is
fixed (due to depmod -a) in certain configurations. This issue comes up
every once in a while in the mailinglists, so it should be fixed.
- modutils rc script must be started before mounting all filesystems,
as modules might be needed to do the mount.
- hwclock needs either read-only access to the timezone file or TZ set, if
it is to know what to do with a local-time hardware clock. If the timezone
file cannot be read before mounting all partitions, TZ is the only possible
workaround.
- hwclock needs read-write access to the /etc and /var filesystems if it
is to run without the --noadjfile (see included patch) or needs to update
the --badyear (/var/lib/lastdate) file.
The Fix Strategy:
- Proper documentation and warnings added everywhere in the hwclock
scripts and README.Debian.hwclock. I would suggest adding them to wherever
local-time hardware-clocks are discussed in the release notes and install
guides too. Patches attached.
- Patch to hwclock (--noadjfile option which works with /etc read-only
without causing errors) to guarantee it can operate early in the boot
process. This is also useful if you use ntp and don't want hwclock ever
creating /etc/adjtime file because it is useless. Patch attached, should
be forwarded upstream as well.
- New dual rc-file strategy to set the clock: do a preliminary set of the
system clock early in rcS.d (S19), do any optional fancy adjusts later at
rcS.d S50 (where hwclock.sh is right now). If your hardware clock is in
UTC, and your problem with the current method was the need for hwclock to
do strange corrections to whatever it reads from your hardware clock (some
Alphas? and PCs with broken RTCs/BIOS) then this solves your problem.
Patch attached.
- Even with the dual rc-file strategy, if you have your hardware clock in
local time, you either have to manually set TZ in the hwclockset.sh
script, or to insure that /etc/localtime is readable upon rc.S S19. The rc
script will detect if it cannot read /etc/localtime and TZ is not set, and
abort with an error.
Modifications needed in the util-linux package (NOT included):
- hwclock.sh (/etc/init.d script) must be "update-rc.d -f remove"'d
and removed from the package
- conffile hwclockset.sh (/etc/init.d script) must be added, and
installed with "update-rc.d hwclockset.sh start 19 S . stop 25 0 6 ."
Proper removal on package purge must be done as well, obviously.
- conffile hwclockadj.sh (/etc/init.d script) must be added, and
installed with "update-rc.d hwclockadj.sh start 50 S . stop 25 0 6 ."
Proper removal on package purge must be done as well, obviously.
Possible drawbacks:
- User has the RTC in UTC: none. There is no need to edit anything.
- User has the RTC in localtime: If the user has /usr as a separate
partition, he'll have to edit the hwclockset.sh script to correctly set
the TZ variable. This might cause problems with daylight saving time and
forgetful users.
- I didn't fix the problem for people needing --badyear at S19. I'm
not even sure someone would need it at S19, maybe S50 is good enough.
To fix, patch hwclock to read the year from somewhere in /etc instead
of /var.
-- System Information
Debian Release: 2.2
Architecture: i386
Kernel: Linux godzillah.rivendell.sol 2.2.17pre9 #1 Wed Jun 28 20:38:34 BRT 2000 i586
Versions of packages util-linux depends on:
ii libc6 2.1.3-10 GNU C Library: Shared libraries an
ii libncurses5 5.0-6 Shared libraries for terminal hand
ii slang1 1.3.9-1 The S-Lang programming library - r
-- Configuration Files:
/etc/fdprm [Errno 2] No such file or directory: '/etc/fdprm'
/etc/init.d/hwclock.sh [Errno 2] No such file or directory: '/etc/init.d/hwclock.sh'
--
"One disk to rule them all, One disk to find them. One disk to bring
them all and in the darkness grind them. In the Land of Redmond
where the shadows lie." -- The Silicon Valley Tarot
Henrique Holschuh
--- ../util-linux-2.10f/debian/README.Debian.hwclock Wed Jun 28 11:10:03 2000
+++ README.Debian.hwclock Fri Jun 30 23:59:28 2000
@@ -63,3 +63,27 @@
Don't use the hwclock --adjust facility, refer to alternate (and much safer)
programs such as ntp, chrony or adjtimex if you need precision timekeeping.
+
+Debian's /etc/init.d/hwclock* init scripts:
+
+There are two init scripts. The first one, /etc/init.d/hwclockset.sh, is
+run very early in the boot process, at a time where only /bin, /sbin and
+/etc are guaranteed to be available (and they will most likely be
+read-only). This script is used to guarantee that a reasonably sane
+system clock time is available to other early-starting scrits, such as
+the one for modutils.
+
+The second init script, hwclockadj.sh, runs after all filesystems were
+mounted. You are free to use hwclock options which do require write access
+(such as --adjust, --set).
+
+If you need any of the workaround options (--directisa, any of the
+Alpha-only options) you probably will need to edit and add them to *BOTH*
+init scripts.
+
+
+Hardware clocks in local (not UTC/GMT) time:
+
+If your hardware clock is in local time, you may need to manually set the
+timezone in /etc/init.d/hwclockset.sh. The script will print a warning
+message if such configuration is needed.
--- ../util-linux-2.10f/clock/hwclock.8 Wed Jun 28 11:10:03 2000
+++ hwclock.8 Fri Jun 30 23:47:20 2000
@@ -20,7 +20,7 @@
.PP
other options:
.PP
-.B "\-\-utc \-\-localtime \-\-directisa \-\-test \-\-debug"
+.B "\-\-utc \-\-localtime \-\-noadjfile \-\-directisa \-\-test \-\-debug"
.PP
and arcane options for DEC Alpha:
.PP
@@ -168,6 +168,17 @@
.B \-\-adjust
options), as recorded in the adjtime file. If the adjtime file doesn't
exist, the default is local time.
+
+.TP
+.B \-\-noadjfile
+disables the facilities provided by /etc/adjtime.
+.B hwclock
+will not read nor write to that file with this option, which is helpful
+if you have to start it early in the boot process. Either
+.B \-\-utc
+or
+.B \-\-localtime
+must be specified when using this option.
.TP
.B \-\-directisa
--- hwclock.c.orig Sun Jun 25 09:22:13 2000
+++ hwclock.c Sun Jun 25 13:37:52 2000
@@ -923,7 +923,8 @@
}
static void
-manipulate_clock(const bool show, const bool adjust,
+manipulate_clock(const bool show, const bool adjust,
+ const bool noadjfile,
const bool set, const time_t set_time,
const bool hctosys, const bool systohc,
const struct timeval startup_time,
@@ -945,7 +946,7 @@
if (no_auth) *retcode_p = 1;
else {
- if (adjust || set || systohc || (!utc && !local_opt))
+ if (!noadjfile && (adjust || set || systohc || (!utc && !local_opt)))
read_adjtime(&adjtime, &rc);
else {
/* A little trick to avoid reading the file if we don't have to */
@@ -1017,7 +1018,9 @@
*retcode_p = 1;
} else *retcode_p = 0;
}
- save_adjtime(adjtime, testing);
+ if (!noadjfile) {
+ save_adjtime(adjtime, testing);
+ }
}
}
}
@@ -1107,6 +1110,8 @@
" --date specifies the time to which to set the hardware clock\n"
" --epoch=year specifies the year which is the beginning of the \n"
" hardware clock's epoch value\n"
+ " --noadjfile do not access /etc/adjtime. Requires the use of\n"
+ " either --utc or --localtime\n"
));
#ifdef __alpha__
fprintf( usageto, _(
@@ -1146,7 +1151,7 @@
may be modified after parsing is complete to effect an implied option.
*/
bool help, show, set, systohc, hctosys, adjust, getepoch, setepoch, version;
- bool ARCconsole, utc, testing, directisa, Jensen, SRM, funky_toy;
+ bool ARCconsole, utc, testing, directisa, Jensen, SRM, funky_toy, noadjfile;
bool local_opt;
char *date_opt;
int epoch_opt;
@@ -1160,6 +1165,7 @@
{ 0, (char *) "getepoch", OPT_FLAG, &getepoch, 0 },
{ 0, (char *) "setepoch", OPT_FLAG, &setepoch, 0 },
{ 'a', (char *) "adjust", OPT_FLAG, &adjust, 0 },
+ { 0, (char *) "noadjfile", OPT_FLAG, &noadjfile, 0 },
{ 'v', (char *) "version", OPT_FLAG, &version, 0 },
{ 'V', (char *) "version", OPT_FLAG, &version, 0 },
{ 0, (char *) "date", OPT_STRING, &date_opt, 0 },
@@ -1188,8 +1194,8 @@
textdomain(PACKAGE);
/* set option defaults */
- help = show = set = systohc = hctosys = adjust = getepoch = setepoch =
- version = utc = local_opt = ARCconsole = SRM = funky_toy =
+ help = show = set = systohc = hctosys = adjust = noadjfile = getepoch =
+ setepoch = version = utc = local_opt = ARCconsole = SRM = funky_toy =
directisa = badyear = Jensen = testing = debug = FALSE;
date_opt = NULL;
epoch_opt = -1;
@@ -1198,8 +1204,8 @@
optParseOptions(&argc_parse, argv_parse, option_def, 0);
/* Uses and sets argc_parse, argv_parse.
Sets show, systohc, hctosys, adjust, utc, local_opt, version,
- testing, debug, set, date_opt, getepoch, setepoch, epoch_opt
- */
+ testing, debug, set, date_opt, getepoch, setepoch, epoch_opt,
+ noadjtime */
/* This is an ugly routine - for example, if I give an incorrect
option, it only says "unrecognized option" without telling
me what options are recognized. Rewrite with standard
@@ -1227,6 +1233,18 @@
exit(100);
}
+ if (adjust && noadjfile) {
+ fprintf(stderr, _("%s: The --adjust and --noadjfile options are mutually "
+ "exclusive. You specified both.\n"), MYNAME);
+ exit(100);
+ }
+
+ if (noadjfile && !(utc || local_opt)) {
+ fprintf(stderr, _("%s: With --noadjfile, you must specify either "
+ "--utc or --localtime\n"), MYNAME);
+ exit(100);
+ }
+
#ifdef __alpha__
set_cmos_epoch(ARCconsole, SRM);
set_cmos_access(Jensen, funky_toy);
@@ -1276,8 +1294,8 @@
"method. Use --debug option to see the details of our "
"search for an access method.\n"));
else
- manipulate_clock(show, adjust, set, set_time, hctosys, systohc,
- startup_time, utc, local_opt, testing, &rc);
+ manipulate_clock(show, adjust, noadjfile, set, set_time, hctosys,
+ systohc, startup_time, utc, local_opt, testing, &rc);
}
}
exit(retcode);
#!/bin/sh
# hwclockset.sh Set system clock to hardware clock, according to the UTC
# setting in /etc/default/rcS (see also rcS(5)).
#
# This script is intended to run very early in the boot
# process. If you want fancy clock adjustment, do that
# elsewhere.
#
# WARNING: Runs without write permission on /etc, and before
# mounting all filesystems! If you need write permission
# to do something, do it in hwclockadj.sh.
#
# WARNING: If your hardware clock is not in UTC/GMT, this script
# must know the local time zone. This information is
# stored in /etc/localtime. This might be a problem if
# your /etc/localtime is a symlink to something in
# /usr/share/zoneinfo AND /usr isn't in the root
# partition! The workaround is to define TZ either
# in /etc/default/rcS, or in the proper place below.
#
# REMEMBER TO EDIT hwclockadj.sh AS WELL!
# Set this to any options you might need to give to hwclock, such
# as machine hardware clock type for Alphas.
HWCLOCKPARS=
[ ! -x /sbin/hwclock ] && exit 0
. /etc/default/rcS
# Define TZ to the desired timezone here if you need it.
# You could also define it in /etc/default/rcS.
# see the manpage tzset(3) for how to define TZ.
# WARNING: TZ takes precedence over /etc/localtime !
# TZ=
[ "$GMT" = "-u" ] && UTC="yes"
case "$UTC" in
no|"") GMT="--localtime"
UTC=""
if [ ! -r /etc/localtime -a -z "$TZ" ]
then
echo
echo "$0: Hardware clock time zone could not be determined." >&2
echo "$0: WARNING: System clock was not updated at this time." >&2
echo
exit 1
fi
;;
yes) GMT="--utc"
UTC="--utc"
;;
*) echo "$0: Unknown UTC setting: \"$UTC\"" >&2
exit 1
;;
esac
case "$1" in
start)
if [ "$VERBOSE" != no ]
then
echo
echo "System time was `date --utc`."
echo "Setting the System Clock using the Hardware Clock as reference..."
fi
# Copies Hardware Clock time to System Clock using the correct
# timezone for hardware clocks in local time, and sets kernel
# timezone. DO NOT REMOVE.
TZ="${TZ}" hwclock --noadjfile --hctosys $GMT $HWCLOCKPARS
if [ "$VERBOSE" != no ]
then
echo "System Clock set. System local time is now `date $UTC`."
fi
;;
stop|restart|reload)
# Does nothing
exit 0
;;
*)
echo "Usage: hwclockset.sh {start|stop|reload}" >&2
echo " start sets kernel (system) clock from hardware (RTC) clock" >&2
echo " stop and reload do nothing." >&2
echo " Refer to hwclockadj.sh as well." >&2
exit 1
;;
esac
#!/bin/sh
# hwclockadj.sh Adjusts the system and hardware clocks, according to the
# UTC setting in /etc/default/rcS (see also rcS(5)).
#
# WARNING: Please read /usr/doc/util-linux/README.Debian.hwclock
# before changing this file. You risk serious clock
# misbehaviour otherwise.
# WARNING: hwclockset.sh runs before this one during startup,
# and might have adjusted the system time already.
#
# REMEMBER TO EDIT hwclockset.sh AS WELL!
# Uncomment the HWCLOCKADJ=yes line below if you want hwclock to try
# to correct systematic drift errors in the Hardware Clock.
#
# WARNING: If you uncomment this option, you must either make sure
# *nothing* changes the Hardware Clock other than hwclock --systohc,
# or you must delete /etc/adjtime every time someone else modifies
# the Hardware Clock.
#
# Common "vilains" are: ntp, MS Windows, the BIOS Setup program.
#
# WARNING: You must remember to invalidate (delete) /etc/adjtime if you
# ever need to set the system clock to a very different value and
# hwclock --adjust is being used.
#
# Please read /usr/doc/util-linux/README.Debian.hwclock before enabling
# this option.
#
# HWCLOCKADJ=yes
# Set this to any options you might need to give to hwclock, such
# as machine hardware clock type for Alphas.
HWCLOCKPARS=
[ ! -x /sbin/hwclock ] && exit 0
. /etc/default/rcS
[ "$GMT" = "-u" ] && UTC="yes"
case "$UTC" in
no|"") GMT="--localtime"
UTC=""
;;
yes) GMT="--utc"
UTC="--utc"
;;
*) echo "$0: unknown UTC setting: \"$UTC\"" >&2
exit 1
;;
esac
case "$1" in
start)
if [ ! -f /etc/adjtime ]
then
echo "0.0 0 0.0" > /etc/adjtime
fi
if [ "$HWCLOCKADJ" == "yes" ]
then
if [ "$VERBOSE" != no ]
then
echo "Compensating for Hardware Clock systematic drift..."
fi
hwclock --adjust $GMT $HWCLOCKPARS
hwclock --hctosys $GMT $HWCLOCKPARS
#
# Now that /usr/lib/zoneinfo should be available,
# announce the local time.
#
if [ "$VERBOSE" != no ]
then
echo "System Clock updated. Local time is now: `date`"
echo
fi
fi
;;
stop|restart|reload)
#
# Updates the Hardware Clock with the System Clock time.
# This will *override* any changes made to the Hardware Clock.
#
# WARNING: If you disable this, any changes to the system
# clock will not be carried across reboots.
#
if [ "$VERBOSE" != no ]
then
echo "Saving the System Clock time to the Hardware Clock..."
fi
hwclock --systohc $GMT
if [ "$VERBOSE" != no ]
then
echo "Hardware Clock updated to `date $UTC`."
fi
;;
show)
hwclock --show $GMT
;;
*)
echo "Usage: hwclockadj.sh {start|stop|reload|show}" >&2
echo " start sets kernel (system) clock from hardware (RTC) clock" >&2
echo " stop and reload set hardware (RTC) clock from kernel (system) clock" >&2
exit 1
;;
esac
Reply to: