by Frank Tegtmeyer <fte@fte.to>
Daniel J. Bernsteins clockspeed package provides a good way to synchronize the system clock of one or a group of computers. It lacks a way do do the necessary measurements in an automated way. This article describes an automated setup using daemontools from the same author.
The clockspeed package by
Daniel J. Bernstein works by adjusting the systems clock to a
reference clock. The adjustments are done using measurements against
the reference clock in increasing intervals.
The precondition for this is that the reference clock and the local
system clock have to run persistently fast or slow.
The solution is usable for a host synchronizing against a NTP reference source and for stations in a LAN environment synchronizing against a master server running Bernsteins taiclockd server. The daemontools setup for the taicklockd server is not described here because it is simple and very similar to the one for the clockspeed daemon.
Wayne Marshall built a very well done package based on this article. I recommend to check it out (after reading this page) at his clocksd page.
To have the clockspeed daemon running all the time a daemontools setup is used which creates a clockspeed service. Should the daemon crash for any reason (I doubt it ever will) the supervise process will restart it within a few seconds.
For the measurements there is a second service defined that starts a long running shell script. After doing a measurement the shell script sleeps a given time before doing the next measurement. The sleep time is doubled for every loop until a defined maximum time is reached. After that the script sleeps always for that maximum time between measurements.
The installation of clockspeed is done using the installation instructions inside the package. All files are installed under /usr/local/clockspeed.
Several scripts use the configuration file that is created as /etc/clockspeed.conf:
# `uname -n` for a single host MASTER='myhost' # not used for a single host MASTER_IP='213.61.218.4' # Your NTP-source (IP address) SNTP_IP=`dnsip ntp2.ptb.de | sed 's/ .*//'` # the installation directory CLOCK_DIR='/usr/local/clockspeed'
Please note that the first two entries are used for taiclock clients in a local area network - they are not used in a single host setup. At the opposite the SNTP_IP entry is not used for taiclock clients.
SNTP_IP has to be an IP address in dotted format. I use ntp2.ptb.de as source, that's one of the two NTP servers of the Physikalisch Technische Bundesanstalt in Germany. They changed the IP addresses of their servers a while ago and I found several of my servers unsynchronized some day because of that. So I use the output of the dnsip program from now on. This will fail also under some circumstances but that's not the topic here. Feel free to set a fixed IP address.
Someclock
is the script that differentiates between the NTP-client setup and the
taicklock-client setup. It is used in the clockspeed and in the
measurement service.
The script is stored as /usr/local/clockspeed/bin/someclock:
#! /bin/sh
. /etc/clockspeed.conf
PATH="$CLOCK_DIR/bin":/usr/bin:/bin
export PATH
case `uname -n` in
$MASTER)
sntpclock $SNTP_IP
;;
*)
taiclock $MASTER_IP
;;
esac
As you can see the output of uname -n is used to decide if the system is using NTP or taiclock. Possibly there would be a semantically better way to do this. The setup of /etc/clockspeed.conf and this script has to be seen with a local area network in mind where the one server that synchronizes against the NTP source acts as master for all the taiclock clients.
#!/bin/sh . /etc/clockspeed.conf $CLOCK_DIR/bin/someclock | $CLOCK_DIR/bin/clockadd exec /usr/local/clockspeed/bin/clockspeed
The script first set's the systems clock with the time it gets from the reference clock and then executes the clockspeed daemon. Because there is no logging output by the clockspeed daemon itself the log service isn't necessary.
The service is started by linking it into the /service directory:
ln -s /usr/local/clockspeed/service_clockspeed /service/clockspeed
The adjustment input for the clockspeed daemon is provided by writing the time measurements into the pipe /usr/local/clockspeed/adjust that is created (and read) by the clockspeed deamon.
To improve security the measurements are done under the account sntp and group sntp. On a SuSE-Linux system these are added with the commands:
groupadd sntp useradd -g sntp -d /var/lib -s /bin/false sntp; passwd -l sntp
For users of other distributions or systems: The user gets a home directory where he cannot write and a shell that instantly terminates (/bin/true is also a candidate for that). Additionally the account is locked after creation so that nobody can use this account for interactive sessions.
The measurement pipe is made writeble for the sntp group (after the clockspeed daemon was started):
chgrp sntp /usr/local/clockspeed/adjust chmod 620 /usr/local/clockspeed/adjust
The real measurement script is /usr/local/clockspeed/service_adjust/clockadjust which is divided from the run script to enable an easy way to switch the uid for it. It runs under user sntp:
#!/bin/sh
#
# script to do the time measurements for clockspeed
# automatically - it runs forever
# Frank Tegtmeyer <fte@fte.to>, based on an idea
# of Tim Goodwin
exec 2>&1
. /etc/clockspeed.conf
PATH="$CLOCK_DIR/bin":/usr/bin:/bin export PATH
maximum_wait=7884000
sleep=600
while true
do
. /etc/clockspeed.conf
# wait a while
echo Sleeping $sleep seconds ...
sleep $sleep
# get new measurement
someclock | tee $CLOCK_DIR/adjust | clockview
clockview < $CLOCK_DIR/etc/atto
echo '----------------------'
# double the time
sleep=`expr $sleep + $sleep`
# cut the value
if [ $sleep -gt $maximum_wait ]
then
sleep=$maximum_wait
fi
done
The logging output of this service is caught by the matching log/run file which logs under /var/log/clockadjust. here is an example using a special log user (file /usr/local/clockspeed/service_adjust/log/run):
#!/bin/sh exec setuidgid sntplog /command/multilog t /var/log/clockadjust
The adjustment service is controlled by it's run script /usr/local/clockspeed/service_adjust/run. It first drops it's privileges by changing it's UID to the sntp user and then executes the measurement script:
#!/bin/sh # exec /command/setuidgid sntp \ /usr/local/clockspeed/service_adjust/clockadjust
Because clockspeed uses TAI as it's time base, the time zone file has to be one from the "right" subdirectory. Under Linux and for Germany you have to do the following:
rm /etc/localtime ln -s /usr/share/zoneinfo/right/Europe/Berlin /etc/localtime
Of course you have to pick the right zone matching your location.
Don't forget to make the run files and other scripts executable :)
Don't forget to create the log directory /var/log/clockadjust and make it writeable for the user used for logging.
qmail has a leapseconds bug, that creates a time offset in Received headers.
Thanks to Tim Goodwin for the idea and initial version. Thanks to
Gerrit Pape for putting some pressure on me to make this
public. I always wanted to do it but never managed to steal the
necessary time.
If you have
improvements (marginal or substantial) please tell me and I will include
you in this section.