HomeBanner

Clock adjusting in SuSE Linux micro-howto

Clocks in a Linux PC

Carlos Robinson

Abstract

How the clock works in a Linux PC, how SuSE treats it, and how it should be adjusted

Every PC has two clocks.

One is a software clock, that counts timer interrupts (19.2 per second); this is the only clock used by the operating system. The original PC had only this clock, so it had to ask the user for the current time and date on every boot to be set properly.

Then, somebody [1] designed an ISA card with a battery clock that the system could read on boot and initialize the software clock. The AT computer type had a chip with a clock, some memory and an external backup battery. It was a CMOS chip; sounds familiar? Yes, that is also where BIOS configuration is stored.

Therefore, all current PCs have also a hardware clock, with a battery, that runs even when the computer is unpowered, used to update the software (aka system) clock.

Universal versus localtime

The system clock is set internally to UTC[2]; when asked to display the time, it converts it to local time.

The CMOS on a Linux system should be UTC. However, we can set it also to localtime, specially if we double boot to some other OS. That is a special case that has to be considered on boot.

Accuracy and Precision.

A digital clock is always precise: there can be no doubt about the time it says it is. Being precise is not the same as being accurate, however: the time it says to be can be incorrect. Some definitions apply; I'll paste here what I found on The Free On-line Dictionary of Computing (27 SEP 03):

accuracy <mathematics>

How close to the real value a measurement is.

precision <mathematics>

The number of decimal places to which a number is computed.

The software clock might be inacurate, drift erratically, if the OS looses interrupts (note: I say might). However, every quartz based electronic clock may be inacurate, but it is always the same inacuracy: that is, it is always fast or slow by the same amount - or at least almost so. Therefore, if we know that amount by comparison to an external reference, we can make use of the fact that it is installed on a computer, and calculate and compensate for that constant drift.

That is what the program hwclock does, amongst other things, keeping the adjustment in /etc/adjtime.

Pity we can not do the same for our ordinary clock and watches.

Reading the clock

For the purpose of this writeup, use only the command date on a console or terminal. Don't even look at desktop gadgets, because sometimes they could be wrong (buggy) and confuse us.

For example:

nimrodel:˜ # hwclock --show ; date ; date -u 
	  Thu Dec 11 03:54:53 2003  -0.885510 seconds
	  Thu Dec 11 03:54:41 CET 2003
	  Thu Dec 11 02:54:41 UTC 2003
	

The commands above show, in succession, the CMOS time (localtime unless specified), the local system time, and UTC system time.

Setting up the clock

Don't.

On a Linux (or Unix) system the clock should not be touched lightly. Things can misbehave (cron, for one. X, for another). You may affect other users, etc. However, if you need to set up the clock, continue reading.

How SuSE scripts take care of the clock

This document is based on SuSE 8.2 - but the system has been basically the same for some years, and I assume it is the same as on SuSE 9.0.

Automatic setting up the clock during boot

The script /etc/init.d/boot.clock is responsible for setting up the clock during boot - read it for details. It takes some configuration from /etc/sysconfig/clock (or /etc/rc.config on older SuSE versions). I'll excerpt here the important parts.

If we have a s390 computer, and the CMOS clock is set to localtime, this is executed:

	if test "$HWCLOCK" != "-u"; then
	date $(date -u +'%m%d%H%M%Y')
	rc_status
	fi

Not too neat, perhaps a “hack”. After all, a Linux system should use UTC ;-)

Otherwise, for the rest of PCs, this is executed to set up the clock:

	echo -n Setting up the CMOS clock
	test -f /etc/adjtime || echo “0.0 0 0.0” > /etc/adjtime
	/sbin/hwclock --adjust $HWCLOCK
	rc_status
	/sbin/hwclock --hctosys $HWCLOCK

First, if the file /etc/adjtime does not exist, it is recreated with default valued (that's why if the adjust is going wrong, simply deleting that file works). Then, the hardware clock is adjusted (compensated) for its known constant drift. Finally, the system clock is set up from the hardware clock. Simple :-)

And during system close

The script /etc/init.d/halt does many things, and one of them is:

	echo "Sending all processes the KILL signal..."
	killall -9
	echo -e "$rc_done_up"

	if test "$HOSTTYPE" = "s390" ; then
	HWCLOCK_ACCESS=no
	fi

	if test "$HWCLOCK_ACCESS" != "no" ; then
	if rc_active xntpd ; then

	echo -n "Set Hardware Clock to the current System Time"
	# write back to hardware clock and calculate adjtime
	/sbin/hwclock --systohc $HWCLOCK

	rc_status -v -r
	fi
	fi
	

What is that? Well, it checks to see if xntpd daemon was defined to run, and if so it assumes the system clock is correct, and therefore finally copies it back to the hardware (CMOS) clock, and calculates the drift to consider.

How not to set up the clock

If we setup the system clock with date or a similar command we'll have problems, because the hardware clock is not synchronized. If we synchronize it incorrectly, the system is set up in such a way that it might think that is the constant drift it has to add on every boot, and the clock will be set up wrongly every boot up. There is a sequence of events that has to be respected.

Setting up the clock manually with an external reference.

This method can be used in cases where we don't have a permanent network connection, only a temporary one (or we don't want to run the daemon for whatever reasons). The sequence is:

  • call ntpdate or date

  • call hwclock --systohc

For example, it can be inserted in /etc/ppp/ip-up.local script and it will run automatically every time we connect using the modem:

	SERVICE_NAME=ip-up.local
	NTPDATEOUT=/etc/ppp/ntpdate.output    

	/etc/init.d/xntpd ntptimeset &/bin/logger -t $SERVICE_NAME
	-p user.info " --> Synchronizing time">
	$NTPDATEOUT
	. /etc/sysconfig/clock
	/sbin/hwclock --systohc $HWCLOCK

	/bin/logger -t $SERVICE_NAME -p user.info -f $NTPDATEOUT
      

For this to run, we have to previously edit the file /etc/ntp.conf, where we only need to insert the time servers we'll use as references:

	## Outside source of synchronized time 
	## 
	server ntp.host.domain    # address of server 1
	server ntp.host2.domain   # address of server 2
      

Explanation of the script

What we do is, first obtain the time form the best of external time servers taken form a list to update the system time. Secondly we update the hardware clock. The extra lines are “beautifiers”.

So, first we make a call to rcxntpd ntptimeset - this is equivalent to calling /usr/sbin/ntpdate -su server_list. The advantage is that

  1. The script is safer

  2. takes the list of servers from a general configuration file

  3. The program ntpdate is supposed to be deprecated some time in the future, and I assume SuSE will know about that and change the script as appropriate.

If we don't have a network connection, we'll have to make do with the command date and a radio for refence.

The second step is to synchronise the hardware clock, taking into account whether it uses local or UTC time[3].

Is using ntpdate appropriate - vs ntpd?

The ntpd daemon will adjust the clock slowly, so that the system is not altered. However, the ntpdate command will adjust time suddenly if the error is bigger than 128ms. If the clock jump some seconds strange, or even bad, things can occur. Therefore, ntpd is safer - but we may not have a permanent network connection, and synchronization can take hours. Setting the clock fast is something usually done during computer initialisation (booting up) so that the daemon has an easier job.

However, if we don't have a permanent network connection, using ntpdate is our only way - possibly using the -B parameter, which will force it to slew instead of step the clock. That is something I'm currently testing.

What to do if the clock is being set incorrectly on every boot?

Delete file /etc/adjtime after adjusting both system and hardware clock as explained above. Don't worry, it will be recreated on next boot.

Setting up the clock automatically with an external network reference.

Configure and start service rcxntpd - you can use Yast runlevel editor to enable this. I understand you can also use Yast to configure this service on SuSE 9.0, but certainly not on previous versions.

You will have to look elsewhere for information or details on configuring and running this service: a permanent network connection is needed, and I don't have one.

Where can we obtain external time references?

You can obtain the list of servers names from http://www.eecis.udel.edu/˜mills/ntp/servers.html - don't choose stratum 1 servers, unless you are going to set up a public NTP server - and in that case, this document shouldn't be your main source of information.

Also, we can obtain servers names from a pool of servers, using one or more lines like this one in the /etc/ntpd.conf file:

      server es.pool.ntp.org
      server europe.pool.ntp.org
    

I don't know how this pool works, I haven't found it documented in the ntpd docs yet. However, I have seen it on the SLE and the Spanish document mentioned in the further reading section below.

Further reading

Miscellaneaous

About the author

I can usually be found in the SuSE English and Spanish mail lists.

Disclaimer

All the information in this document is believed to be correct - however, there may be errors. If I'm told, I'll correct them in the next version of this document.


[1] Who he was I don't currently know

[2] The acronym UTC (Universal Coordinated Time) has that strange order on purpose, neither English or French (or Spanish) ordering. It is to preferred to the equivalent GMT (Greenwich Meridian Time), which is considered deprecated.

[3] Notice that ntp servers always give UTC time, not local time. The conversion to local time is the responsibility of your software or OS.


Updated: Mon, 16 Feb 2004
Valid CSS!Valid HTML 4.01!