Skip to content
January 12, 2015 / gus3

Getting a Time Without NTP

One of the drawbacks of a Raspberry Pi is its lack of an on-board clock. After a reboot, its clock is set to midnight, New Year’s Day, 1970 UTC, the beginning of the Unix epoch, and then the kernel boots. However, it is possible to get the current time early in the boot process, with one condition: an NFS root filesystem.

What’s my motivation?

One thing I’ve noticed with my Raspberry Pi, is that its clock runs a little bit slow (losing seconds over weeks). However, the clock on my file server runs more than a little fast (gaining seconds over days). The clash appears when using “make” to build something. After a long enough uptime, editing a file can cause that file to have a modification time “in the future,” as the RPi sees it. The “make” program then issues a warning: “Clock skew detected. Your build may be incomplete.” I used a lame command involving SSH and “date” to set the clock on the RPi to agree with the server, but it became a nuisance to do this every time I saw the “make” warning.

Setting up an NTP service wasn’t an onerous task, but I never really wanted to do that. My file server isn’t connected to the Internet, so its time can’t be considered a stable time source. I just wanted to stop the warning messages. Mostly, I wanted a way to keep the clocks in sync, even if that meant they had the same, incorrect time.

NTP isn’t the only network time

Then the proverbial light came on. There are other ways to get another computer’s time, especially if another computer is a file server. In this case, having the root filesystem on an NFS server was a stupendous asset. Unix files have timestamps, and the “date” command can access the modification time of a particular file. Why not create a file, then immediately set the system time from that file? The local system may have a wildly incorrect time, but the time on the NFS server is really the one we care about, correct or not. Even with delays from shell script interpretation, we can probably get the time from the NFS server, with tenth-of-a-second resolution.

So how do we do it?

It’s very simple, actually. The lower task is to create a file; the middle task is to get that file’s timestamp (and then remove it, as a good user); and the higher task is to set the system time to that timestamp. Setting the system time requires root privileges; the command isn’t really effective otherwise.

So, as root, the following command will do the trick:


/bin/date -s "$(touch /.z ; sync ; /bin/date --rfc-3339=ns -r /.z ; rm /.z)"

This shell command accomplishes a few tricks. First, it creates a hidden file in the root filesystem, /.z. (The dot-zed filename isn’t fixed. It’s just what I came up with for my system.) The “sync” command makes sure the NFS server and client agree on, well, whatever. That is to say: It Works For Me. Then, the second “date” command gets the nanosecond-timestamp of the /.z file that we just created.

Once we have that timestamp, the first “date” command sets the system time to that timestamp. There may be some elapsed time between the “date” commands, but it can be ignored safely. The main intention is to get the client’s time close enough to the server’s time, to avoid any “clock skew” warnings.

At boot?

Yes, this command works at boot, with an NFS root filesystem. I have the following in my ArmedSlack /etc/rc.d/rc.S script:


# Try to mount /proc:
/sbin/mount -v proc /proc -n -t proc 2> /dev/null

# On an NFS root, try to set time from NFS server
if grep -q nfsroot /proc/cmdline ; then
/usr/bin/date -s "$(touch /.z ; sync ; /usr/bin/date --rfc-3339=ns -r /.z ; rm -f /.z)"
fi

The first two lines give a hint where to insert the following “if…fi” clause. The same could be done on any Linux system with an NFS root; finding the proper location in the boot scripts is left as an exercise for the reader.

What about after boot?

I also have the following line in the system crontab:


*/5 * * * * /usr/bin/date -s "$(/bin/touch /.z ; sync ; /usr/bin/date --rfc-3339=ns -r /.z ; rm /.z)" 1> /dev/null

This does the same thing, every five minutes. During a heavy build, like the kernel or glibc, the client-server time difference tends to become more pronounced. A small interruption every five minutes is a small price to pay for shutting off a nuisance warning.

What about other network filesystems?

I haven’t tested this method on them. I don’t know if it would work with CIFS (Samba), AndrewFS, Coda, or NCP (NetWare), and I’m not sure any of these can be used as a root filesystem in Linux. If you are using any of these as a root filesystem, and you try the above code on your Raspberry Pi, please report your results in the comments section below.

5 Comments

Leave a Comment
  1. Mike Lothian / Jan 13 2015 6:48 am

    If you switch to using systemd it has an inbuilt ntp client which will keep your clock in sync

    • gus3 / Jan 13 2015 7:20 am

      And here come the systemd fanbois.

      First, Slackware doesn’t use systemd, and won’t be using it any time in the near future. Second, an NTP client needs an NTP server, which itself needs a stable external time source. I don’t have an outside Internet connection at home, and I don’t feel like setting up a service that practically demands Internet access to work properly. I just want to keep the clocks in sync.

      • Mike / Jan 13 2015 3:49 pm

        Forget systemd.

        Use whatever works for you, but you can set your server up as an ntp server with “undisciplined local clock”.

        Just put this in your /etc/ntpd.conf:
        server 127.127.1.0 # local clock
        fudge 127.127.1.0 stratum 10

        No internet access is needed. The ntpd server will happily serve your local time to clients. The stratum value ensures that if the clients find a better source, they will use it instead.

        • gus3 / Jan 13 2015 6:41 pm

          That takes care of the fully-booted case, but it still ignores the boot to single-user mode. Single-user may also lose the cron method, but at least it’ll have a “reasonable” time at login time.

Trackbacks

  1. Time without NTP (Raspberry Pi) | 0ddn1x: tricks with *nix

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.