the djb way

clockspeed service daemons


We began on the djb way with the clockspeed package. That got us started with downloading, building, installing and running a representative piece of djb software. Coincidentally, perhaps, our clocks may even be running a little more accurately now.

But the original operating instructions left a lot to be desired. Sure, we may have started the clockspeed background daemon at one time, but we didn't make any special arrangments to be sure it started again with each system reboot. And the periodic calibration procedure required us to remember to do something from the command line every so often, after a few hours, then days, then weeks, then months apart. Hah! Not likely!

Now that we have the daemontools utilities at our disposal, though, we can make better use of the clockspeed package as a serious network time server. This section will describe clockspeed service daemons as an example of running clockspeed under daemontools the djb way.


Recall that the clockspeed package includes the following components:

Our goal is to use daemontools for creating a set of clockspeed services that:

In addition, it would be nice to log the activities of these services, so we can monitor what clockspeed is doing behind the scenes.


The clockspeed services of course require the clockspeed package. The scripts described here also make use of our clockctl interface to the clockspeed functions.

The clockspeed services will then consist of a set of daemontools run scripts and supporting utilities that will be defined within the /var/svc.d directory. To prepare the framework, make these directories now:

# mkdir -p /var/svc.d
# cd /var/svc.d
# mkdir -p clockspeed/log
# mkdir -p clockspeed_adjust/log
# mkdir -p taiclockd/log

We will also be introducing the setuidgid utility of daemontools, to run our services at reduced privelege levels whenever possible. To prepare for this, add the group nofiles, and two users named clocksd and multilog--both members of group nofiles--to your system, in accordance with the conventions for your particular platform. The clocksd user will be used to run some of the clockspeed service daemons, while the multilog user will be used to run the logging services. As a security measure, these users will have non-root priveleges.

The group nofiles will be a constant companion along the djb way. Most of the unpriveleged users we meet will be members of this group.

clockspeed service

The daemontools run script for clockspeed is simple:

# clockspeed/run
# "run" script for a clockspeed daemon
exec 2>&1
echo "*** Starting clockspeed..."
exec /usr/local/clockspeed/bin/clockspeed
# that's all, folks!

Save this to /var/svc.d/clockspeed/run and make it executable, chmod 755.

Note that in this run script, the clockspeed executable is run in the foreground. That is, no ampersand (&) follows the command as when we ran it from the command line. This is a crucial aspect of services run under daemontools: they must run in the foreground. The daemontools supervise process will take care of running the command as a background daemon for us.

Next is a logger for the clockspeed service. Although the clockspeed utility itself doesn't generate any output, the echo line in the run script above will make multilog generate a timestamp for logging the start-up.

# clockspeed/log/run
# "run" script for clockspeed multilog
exec setuidgid multilog multilog t /var/multilog/clockspeed
# that's all, folks!

Save to /var/svc.d/clockspeed/log/run, make it executable, chmod 755.

The new daemontools twist to notice here is the setuidgid utility as the command that is exec'd. This has the effect of running multilog as an unpriveleged user; here we specify the username multilog, the user we created specifically for logging when we set up the framework earlier.

There's one more step now for the logging service. Since multilog will be run as an unprivleged user, the log directory needs to be owned by that user:

# mkdir -p /var/multilog/clockspeed
# chown multilog:nofiles /var/multilog/clockspeed

This pair of scripts will now run clockspeed under control of daemontools with logging. Activate the service by linking it into the /service directory:

# ln -s /var/svc.d/clockspeed  /service/clockspeed

After the service starts, set ownership on the special named pipe created by clockspeed:

# chown clocksd /usr/local/clockspeed/adjust

The clockspeed_adjust service set up below will then be able to run as this non-priveleged user.

clockspeed_adjust service

Now we want a background service that periodically remembers to get a new timing mark from an external timeserver. The main job is done by a simple script:

# periodically get timing mark for clockspeed service
# initialize WAIT, WAIT_MAX:

# loop indefinitely
while :
    echo "Waiting ${WAIT} seconds until next adjustment..."
    sleep ${WAIT}
    # obtain timing mark for calibrating clockspeed adjust:
    clockctl mark
    # log current "attoseconds":
    clockctl atto
    echo "==="
    # increment $WAIT:
    WAIT=`expr ${WAIT} + ${WAIT} + ${WAIT}`
    if [ ${WAIT} -gt ${WAIT_MAX} ] ; then
# that's all, folks!

Save this script to /var/svc.d/clockspeed_adjust/, chmod 755.

(Note: OpenBSD users may have problems with the use of sleep in this shell script. Please refer to the notes regarding the OpenBSD /bin/sh shell anomaly, and possible work-arounds.)

This script is designed for a continuously running, network connected host. It uses a single loop to periodically get a new timing mark from an external timeserver, with an ever-lengthening interval between each loop, up to a maximum interval defined by $WAIT_MAX.

Notice that this script calls the clockctl interface we previously installed for operating clockspeed.

The daemontools run script for the clockspeed_adjust service then looks like this:

# clockspeed_adjust/run
# "run" script for a clockspeed_adjust daemon
exec 2>&1
echo "*** Starting clockspeed_adjust..."
exec setuidgid clocksd ./
# that's all, folks!

Save this script to /var/svc.d/clockspeed_adjust/run, chmod 755.

Here again we use the daemontools setuidgid utility. Only in this case, the script is now set up to run with reduced priveleges as user clocksd.

The logging service for clockspeed_adjust should be getting familiar by now:

# clockspeed_adjust/log/run
# "run" script for clockspeed_adjust logger
exec setuidgid multilog multilog t /var/multilog/clockspeed_adjust
# that's all, folks!

Save this script to /var/svc.d/clockspeed_adjust/log/run, chmod 755. (Hello? Is there an echo in here?)

Again we use setuidgid on the logging service, to run the service as the unpriveleged multilog user. Configure the log directory for the service:

# mkdir -p /var/multilog/clockspeed_adjust
# chown multilog:nofiles /var/multilog/clockspeed_adjust

This set of scripts will now run a clockspeed_adjust service under control of daemontools with logging.

Activate the service by linking it into the /service directory:

# ln -s /var/svc.d/clockspeed_adjust /service/clockspeed_adjust

taiclockd service

Optionally you may want to set up a host on a network to serve time, using Bernstein's taiclockd server. This server should itself be calibrated to an external time server as described above.

Setting up a taiclockd service then involves a familiar pair of simple daemontools run scripts. The main run script for the service looks like this:

# taiclockd/run
# "run" script for a taiclockd daemon
exec 2>&1
echo "*** Starting taiclockd..."
exec setuidgid clocksd /usr/local/clockspeed/bin/taiclockd
# that's all, folks!

As usual, install the script in /var/svc.d/taiclockd/run, chmod 755.

Notice again that taiclockd is run with the reduced priveleges of user clocksd.

Here now is the logging service:

# taiclockd/log/run
# "run" script for taiclockd multilog
exec setuidgid multilog multilog t /var/multilog/taiclockd
# that's all, folks!

Familiar stuff, right? Install in /var/svc.d/taiclockd/log/run, chmod 755.

Set up the directory for multilog:

# mkdir -p /var/multilog/taiclockd
# chown multilog:nofiles /var/multilog/taiclockd

Everything should be good to go. Activate the service by linking into /service:

# ln -s /var/svc.d/taiclockd /service/taiclockd

Clients of this time server should be set up according to the operating instructions of clockspeed, along with clockspeed and clockspeed_adjust services as described above. Just edit the clients' clockspeed.conf file in /usr/local/etc, setting CLOCK_TYPE="tai", and CLOCK_IP to the IP address of this local time server.

Copyright © 2002, 2003, 2004, Wayne Marshall.
All rights reserved.

Last edit 2004.10.04, wcm.