天天看点

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)

继续阅读