一般Openwrt系統較多用于網絡方面的産品,比如路由器,但路由器幾乎都沒有硬體RTC,是以系統初始時間不準.
在Openwrt系統中,初始時間可以認為有2個, 固件編譯時間和檔案系統加載後的初始時間
關于固件編譯時間,即為Linux kernel 編譯時間, 即是/proc/version内容,比如:
[email protected]:~# cat /proc/version
Linux version 4.14.221 (xxxx) (gcc version 7.5.0 (OpenWrt GCC 7.5.0 r11063-85e04e9f46)) #0 Tue Aug 31 06:45:02 2021
kernel 編譯時間通過宏KBUILD_BUILD_TIMESTAMP來傳入
宏初始化, 從SOURCE_DATE_EPOCH擷取時間
SOURCE_DATE_EPOCH 由腳本生成
腳本get_source_date_epoch.sh如下:
分别從version.date檔案,git,hg來進行初始化
version.date檔案存儲的即為編譯時的UTC時間
# cat version.date
1630392302
#!/usr/bin/env bash
export LANG=C
export LC_ALL=C
[ -n "$TOPDIR" ] && cd $TOPDIR
try_version() {
[ -f version.date ] || return 1
SOURCE_DATE_EPOCH="$(cat version.date)"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_git() {
[ -e .git ] || return 1
SOURCE_DATE_EPOCH="$(git log -1 --format=format:%ct)"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_hg() {
[ -d .hg ] || return 1
SOURCE_DATE_EPOCH="$(hg log --template '{date}' -l 1 | cut -d. -f1)"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_mtime() {
perl -e 'print((stat $ARGV[0])[9])' "$0"
[ -n "$SOURCE_DATE_EPOCH" ]
}
try_version || try_git || try_hg || try_mtime || SOURCE_DATE_EPOCH=""
echo "$SOURCE_DATE_EPOCH"
宏傳入:
宏使用 scripts/mkcompile_h 腳本:
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
TARGET=$1
ARCH=$2
SMP=$3
PREEMPT=$4
CC=$5
vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; }
# If compile.h exists already and we don't own autoconf.h
# (i.e. we're not the same user who did make *config), don't
# modify compile.h
# So "sudo make install" won't change the "compiled by <user>"
# do "compiled by root"
if [ -r $TARGET -a ! -O include/generated/autoconf.h ]; then
vecho " SKIPPED $TARGET"
exit 0
fi
# Do not expand names
set -f
# Fix the language to get consistent output
LC_ALL=C
export LC_ALL
if [ -z "$KBUILD_BUILD_VERSION" ]; then
if [ -r .version ]; then
VERSION=`cat .version`
else
VERSION=0
echo 0 > .version
fi
else
VERSION=$KBUILD_BUILD_VERSION
fi
#### 擷取外部定義,沒有則自動生成,以目前時間為主
if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
TIMESTAMP=`date`
else
TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
fi
if test -z "$KBUILD_BUILD_USER"; then
LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/')
else
LINUX_COMPILE_BY=$KBUILD_BUILD_USER
fi
if test -z "$KBUILD_BUILD_HOST"; then
LINUX_COMPILE_HOST=`hostname`
else
LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
fi
UTS_VERSION="#$VERSION"
CONFIG_FLAGS=""
if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP"
# Truncate to maximum length
UTS_LEN=64
UTS_TRUNCATE="cut -b -$UTS_LEN"
# Generate a temporary compile.h
( echo /\* This file is auto generated, version $VERSION \*/
if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi
echo \#define UTS_MACHINE \"$ARCH\"
echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\"
echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\"
echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | grep ' version ' | sed 's/[[:space:]]*$//'`\"
) > .tmpcompile
# Only replace the real compile.h if the new one is different,
# in order to preserve the timestamp and avoid unnecessary
# recompilations.
# We don't consider the file changed if only the date/time changed.
# A kernel config change will increase the generation number, thus
# causing compile.h to be updated (including date/time) due to the
# changed comment in the
# first line.
if [ -r $TARGET ] && \
grep -v 'UTS_VERSION' $TARGET > .tmpver.1 && \
grep -v 'UTS_VERSION' .tmpcompile > .tmpver.2 && \
cmp -s .tmpver.1 .tmpver.2; then
rm -f .tmpcompile
else
vecho " UPD $TARGET"
mv -f .tmpcompile $TARGET
fi
rm -f .tmpver.1 .tmpver.2
最終生成在檔案include/generated/compile.h
#define UTS_MACHINE "mips"
#define UTS_VERSION "#0 Tue Aug 31 06:45:02 2021"
#define LINUX_COMPILE_BY "gwind"
#define LINUX_COMPILE_HOST "gwind-XX"
#define LINUX_COMPILER "gcc version 7.5.0 (OpenWrt GCC 7.5.0 r11063-85e04e9f46)"
關于 檔案系統加載後的初始時間, 可以了解為使用者應用起來後的系統時間
Openwrt系統啟動過程中會進行系統檔案更新時間判斷,以最新的檔案更新時間設定為目前系統時間
實作在腳本package/base-files/files/etc/init.d/sysfixtime
#!/bin/sh /etc/rc.common
# Copyright (C) 2013-2014 OpenWrt.org
### 00,最先運作
START=00
STOP=90
RTC_DEV=/dev/rtc0
HWCLOCK=/sbin/hwclock
boot() {
start && exit 0
local maxtime="$(maxtime)"
local curtime="$(date +%s)"
[ $curtime -lt $maxtime ] && date -s @$maxtime
}
start() {
[ -e "$RTC_DEV" ] && [ -e "$HWCLOCK" ] && $HWCLOCK -s -u -f $RTC_DEV
}
stop() {
[ -e "$RTC_DEV" ] && [ -e "$HWCLOCK" ] && $HWCLOCK -w -u -f $RTC_DEV && \
logger -t sysfixtime "saved '$(date)' to $RTC_DEV"
}
maxtime() {
local file newest
#### 搜尋/etc下最新的檔案
for file in $( find /etc -type f ) ; do
[ -z "$newest" -o "$newest" -ot "$file" ] && newest=$file
done
### 以最新的檔案時間設定為系統時間
[ "$newest" ] && date -r "$newest" +%s
}
最終系統運作日志:
[email protected]:~# logread |head
Tue Aug 31 14:45:10 2021 kern.notice kernel: [ 0.000000] Linux version 4.14.221 (gcc version 7.5.0 (OpenWrt GCC 7.5.0 r11063-85e04e9f46)) #0 Tue Aug 31 06:45:02 2021
====Kernel時間為6:45編譯時間, 标準UTC時間
=== 系統時間為14:45, 因為目前時區是CST-8
Tue Aug 31 14:45:10 2021 kern.info kernel: [ 0.000000] Board has DDR2
Tue Aug 31 14:45:10 2021 kern.info kernel: [ 0.000000] Analog PMU set to hw control
Tue Aug 31 14:45:10 2021 kern.info kernel: [ 0.000000] Digital PMU set to hw control
Tue Aug 31 14:45:10 2021 kern.info kernel: [ 0.000000] SoC Type: MediaTek MT7688 ver:1 eco:2
Tue Aug 31 14:45:10 2021 kern.info kernel: [ 0.000000] bootconsole [early0] enabled
Tue Aug 31 14:45:10 2021 kern.info kernel: [ 0.000000] CPU0 revision is: 00019655 (MIPS 24KEc)