天天看點

Openwrt系統初始時間

一般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擷取時間

Openwrt系統初始時間

SOURCE_DATE_EPOCH 由腳本生成

Openwrt系統初始時間

腳本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"
           

宏傳入:

Openwrt系統初始時間

宏使用 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)

繼續閱讀