Files
H100PowerManger/scripts/sync-board-time.sh
T

177 lines
6.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
#=======================================================================
# FILE: scripts/sync-board-time.sh
# DESC: 校正 223 板卡(RK3588,默认 192.168.0.223)的系统时间:以
# 本机时间(或 --time 指定时间)为基准,经 SSH 设置板卡系统时
# 钟,并尽力写入硬件时钟 (RTC)。板卡网络隔离无 NTP,用本脚本对时。
#
# 用法:
# ./scripts/sync-board-time.sh # 用本机时间校正板卡
# ./scripts/sync-board-time.sh status # 只查看时间与偏差
# ./scripts/sync-board-time.sh --time "2026-09-01 12:00:00"
# # 用指定时间校正(本地时区)
#
# 参数:
# --host <ip> 目标主机(默认 192.168.0.223)
# --user <user> 登录用户(默认 root)
# --time <str> 手动指定基准时间(date 可解析的格式,按本地时区解释)
# --keep-ntp 不执行 timedatectl set-ntp false
# --no-rtc 不写硬件时钟(跳过 hwclock --systohc)
# -h, --help 显示帮助
#
# 说明:
# - 需要 root 登录与免密 SSH(ssh-copy-id root@<host>)。
# - 对时经 SSH 往返时延 (RTT) 折半补偿,精度约 ±0.1s(受网络抖动影响)。
# - 板卡若无可用 RTC,hwclock 失败仅告警;重启后时间可能回跳。
# - 对时会调整系统时钟,运行中的服务日志时间戳会跳变,属正常现象。
#=======================================================================
set -uo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HOST="192.168.0.223"
USER="root"
SET_TIME=""
KEEP_NTP=0
NO_RTC=0
info() { printf '\033[1;36m[time]\033[0m %s\n' "$*"; }
ok() { printf '\033[1;32m[time]\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m[time]\033[0m %s\n' "$*"; }
err() { printf '\033[1;31m[time]\033[0m %s\n' "$*"; }
usage() {
sed -n '2,26p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
exit 0
}
#-------------------------------------------------------------------
# 参数解析
#-------------------------------------------------------------------
ACTION=""
while [ $# -gt 0 ]; do
case "$1" in
--host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;;
--user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;;
--time) [ $# -ge 2 ] || { err "--time 需要参数"; exit 1; }; SET_TIME="$2"; shift 2 ;;
--keep-ntp) KEEP_NTP=1; shift ;;
--no-rtc) NO_RTC=1; shift ;;
status|help|-h|--help) ACTION="$1"; shift ;;
"") shift ;;
*) err "未知参数: $1(见 help)"; exit 1 ;;
esac
done
[ -n "${ACTION}" ] || ACTION="sync"
SSH_TARGET="${USER}@${HOST}"
SSH="ssh -o BatchMode=yes -o ConnectTimeout=5"
#-------------------------------------------------------------------
# 读取板卡时间并测 RTT
# 输出: "<epoch>|<板卡可读时间> <t0> <t1>"(t0/t1 为本机采样时刻)
#-------------------------------------------------------------------
read_board_time() {
local t0 t1 out
t0="$(date +%s.%N)"
out="$(${SSH} "${SSH_TARGET}" 'date "+%s.%N|%F %T %Z"' 2>/dev/null)" || {
err "无法免密 SSH 到 ${SSH_TARGET}(先配置免密: ssh-copy-id ${SSH_TARGET})" >&2
return 1
}
t1="$(date +%s.%N)"
printf '%s %.3f %.3f\n' "${out}" "${t0}" "${t1}"
}
# 从 read_board_time 输出解析: set -- <out> 后取 $1/$2/$3
parse_board_time() {
B_EPOCH="${1%%|*}"
B_DATE="${1#*|}"
T0="$2"
T1="$3"
MID="$(awk -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t0 + (t1-t0)/2}')"
DIFF="$(awk -v b="${B_EPOCH}" -v m="${MID}" 'BEGIN{printf "%+.3f", b - m}')"
}
#-------------------------------------------------------------------
# 命令: status
#-------------------------------------------------------------------
cmd_status() {
local out
out="$(read_board_time)" || return 1
parse_board_time ${out}
local rtt
rtt="$(awk -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t1-t0}')"
printf '本机时间: %s (RTT %.3fs)\n' "$(date -d "@${MID}" '+%F %T')" "${rtt}"
printf '板卡时间: %s\n' "${B_DATE}"
printf '偏差: 板卡比本机快 %s 秒\n' "${DIFF}"
}
#-------------------------------------------------------------------
# 命令: sync(默认)
#-------------------------------------------------------------------
cmd_sync() {
local out target board_reply
# 前置检查:SSH 连通 + 板卡 root 权限
out="$(read_board_time)" || return 1
parse_board_time ${out}
if ! ${SSH} "${SSH_TARGET}" '[ "$(id -u)" = 0 ]' 2>/dev/null; then
err "板卡登录用户需要 root 权限(当前 --user ${USER})"
return 1
fi
ok "SSH 连接正常: ${SSH_TARGET}"
info "当前偏差: 板卡比本机快 ${DIFF} 秒"
# 关闭 NTP 自动同步(板卡网络隔离本就无 NTP 源,防止干扰手动对时)
if [ "${KEEP_NTP}" = "0" ]; then
info "关闭板卡 NTP 自动同步 (timedatectl set-ntp false) ..."
${SSH} "${SSH_TARGET}" "command -v timedatectl >/dev/null 2>&1 && timedatectl set-ntp false || true"
fi
# 计算目标时间:手动指定值直接用;否则取本机时间 + RTT/2 补偿
if [ -n "${SET_TIME}" ]; then
target="$(date -d "${SET_TIME}" '+%s.%N' 2>/dev/null)" || {
err "无法解析时间: ${SET_TIME}"; return 1;
}
info "基准时间(手动): ${SET_TIME}"
else
local t2
t2="$(date +%s.%N)"
target="$(awk -v t2="${t2}" -v t0="${T0}" -v t1="${T1}" 'BEGIN{printf "%.3f", t2 + (t1-t0)/2}')"
info "基准时间(本机 + RTT/2 补偿)"
fi
info "设置板卡系统时间 -> $(date -d "@${target}" '+%F %T') ..."
board_reply="$(${SSH} "${SSH_TARGET}" "date -s @${target} 2>&1")" || {
err "date -s 失败: ${board_reply}"
return 1
}
ok "板卡返回: ${board_reply}"
# 写硬件时钟(无 RTC 时仅告警)
if [ "${NO_RTC}" = "0" ]; then
info "同步硬件时钟 (hwclock --systohc) ..."
if ${SSH} "${SSH_TARGET}" "hwclock --systohc" 2>/dev/null; then
ok "RTC 已同步"
else
warn "hwclock 失败(板卡可能无 RTC 或驱动未加载),重启后时间可能回跳"
fi
fi
# 校验
out="$(read_board_time)" || return 1
parse_board_time ${out}
info "校正后偏差: 板卡比本机快 ${DIFF} 秒"
ok "板卡时间: ${B_DATE}"
}
#-------------------------------------------------------------------
# 命令入口
#-------------------------------------------------------------------
case "${ACTION}" in
sync) cmd_sync ;;
status) cmd_status ;;
help|-h|--help) usage ;;
*) usage ;;
esac