RTC 芯片采用 PCF8563T,Linux 系统使用 date 设置时间后用 hwclock -w 同步到 RTC,一段时间后 Linux 系统时间与本地时间相差 8 个小时。
直觉告诉我们这是时区造成的,要么是系统的时区配置不对,要么是 RTC 时间的读写不对。
时区配置主要是两个文件:/etc/localtime 和 /etc/timezone,内容如下,看来是已经配置成 CST(中国标准时间)的了。
# ls -l /etc/localtime lrwxrwxrwx 1 root root 33 Jan 1 1970 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
# cat /etc/timezone Asia/Shanghai
设定了时区,还要确定 Linux 系统的时间方案。Linux 支持 UTC 时间,也就是本初子午线上的时间,它和以前的格林尼治时间(GMT)的区别似乎在于 UTC 是由多个原子钟平均出来的。
协调世界时,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT,Coordinated Universal Time)和法文(TUC)的缩写不同,作为妥协,后来都统一简称 UTC。
在文件 /etc/default/rcS 中,设定了系统是否使用 UTC,UTC=yes 则使用 UTC 时间,UTC=no 则使用本地时间。
# Assume that the BIOS clock is set to UTC time (recommended) UTC=yes
在读写 RTC 时,我们使用 hwclock 命令,其用法如下:
hwclock [-r|--show] [-s|--hctosys] [-w|--systohc] [-t|--systz] [-l|--localtime] [-u|--utc] [-f|--rtc FILE]
ARM Linux 有个时间戳文件 /etc/timestamp
# cat /etc/timestamp 201611171515
我们找一下,看看它是怎么产生的
# grep -rn "/etc/timestamp" /* /etc/init.d/bootmisc.sh:62:if test -e /etc/timestamp /etc/init.d/bootmisc.sh:65: read TIMESTAMP < /etc/timestamp /etc/init.d/save-rtc.sh:13:date -u +%4Y%2m%2d%2H%2M > /etc/timestamp
我们把目光定位在 /etc/init.d/save-rtc.sh,它的内容如下:
# cat /etc/init.d/save-rtc.sh #!/bin/sh ### BEGIN INIT INFO # Provides: save-rtc # Required-Start: # Required-Stop: $local_fs hwclock # Default-Start: S # Default-Stop: 0 6 # Short-Description: Store system clock into file # Description: ### END INIT INFO # Update the timestamp date -u +%4Y%2m%2d%2H%2M > /etc/timestamp
那到底是怎么调用的呢?我们找到端倪,/etc/rc0.d/S25save-rtc.sh 和 /etc/rc6.d/S25save-rtc.sh 都是 /etc/init.d/save-rtc.sh 的软链接。
再看看内核启动后的第一个用户进程 init,init 会调用脚本 /etc/inittab
# Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS
inittab 中启动的第一个脚本是 /etc/init.d/rcS,其内容如下:
# cat /etc/init.d/rcS #!/bin/sh # # rcS Call all S??* scripts in /etc/rcS.d in # numerical/alphabetical order. # # Version: @(#)/etc/init.d/rcS 2.76 19-Apr-1999 miquels@cistron.nl # PATH=/sbin:/bin:/usr/sbin:/usr/bin runlevel=S prevlevel=N umask 022 export PATH runlevel prevlevel # Make sure proc is mounted # [ -d "/proc/1" ] || mount /proc # # Source defaults. # . /etc/default/rcS # # Trap CTRL-C &c only in this shell so we can interrupt subprocesses. # trap ":" INT QUIT TSTP # # Call all parts in order. # exec /etc/init.d/rc S
该脚本会设置 /etc/default/rcS 中的环境变量,其中包括一个 UTC 变量:
# Assume that the BIOS clock is set to UTC time (recommended) UTC=yes
然后执行 /etc/init.d/rc S
,rc 中 循环调用 rcS.d 中的脚本
# Now run the START scripts for this runlevel. for i in /etc/rc$runlevel.d/S* do [ ! -f $i ] && continue if [ $previous != N ] && [ $previous != S ] then # # Find start script in previous runlevel and # stop script in this runlevel. # suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]} stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffix previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix # # If there is a start script in the previous level # and _no_ stop script in this level, we don't # have to re-start the service. # [ -f $previous_start ] && [ ! -f $stop ] && continue fi case "$runlevel" in 0|6) startup $i stop ;; *) startup $i start ;; esac done
# cat /etc/sysconfig/clock ZONE="Asia/Shanghai" UTC=false ARC=false
对时服务没有使用 NTP,而是公司内部的对时服务。