#!/bin/sh
#===============================================================================
# Hotplug 触发脚本：WAN 接口上线后自动运行软件包恢复
# 功能：当 OpenWrt 的 WAN 接口首次获取 IP 或状态变为 up 时，
#       等待网络真正连通，然后调用 restore-packages.sh 恢复用户软件包。
# 用法：放置于 /etc/hotplug.d/iface/ 目录下，由系统 hotplug 事件自动调用。
#       也可通过环境变量控制行为，例如：
#         PING_TARGET=114.114.114.114 \
#         RESTORE_SCRIPT=/usr/bin/restore-packages.sh /etc/hotplug.d/iface/99-restore-packages
#
# 配置参数（均可通过同名环境变量覆盖）：
#   LOGGER_TAG     syslog 标签 [默认: restore-packages-hotplug]
#   MAX_WAIT       最长等待网络就绪的时间（秒） [默认: 180]
#   CHECK_INTERVAL 网络检测间隔（秒） [默认: 10]
#   PING_TARGET    用于测试连通性的目标地址 [默认: 8.8.8.8]
#   RESTORE_SCRIPT 恢复脚本路径 [默认: /usr/bin/restore-packages.sh]
#   TRIGGER_LOG    触发过程与恢复脚本的输出日志文件 [默认: /var/log/restore-packages-trigger.log]
#
# 日志文件说明：
#   - 恢复脚本 (restore-packages.sh) 的详细日志默认存放在：
#     /var/log/package-restore-YYYYMMDDHHMMSS.log（若 /var/log 不可写则回退到 /tmp）
#   - 本触发脚本会将其标准输出/错误重定向到 TRIGGER_LOG 中（默认：
#     /var/log/restore-packages-trigger.log）
#   - 触发过程的关键信息（如启动、超时、退出）通过 logger 写入系统 syslog
#
# 说明：
#   - 仅在 ACTION=ifup 且 INTERFACE=wan 时触发，其他接口或事件被忽略。
#   - 网络检测采用循环 ping 目标地址，超时后放弃执行。
#   - 整个检测和执行过程在后台子 shell 中运行，不阻塞 hotplug 主进程。
#   - 可通过环境变量为恢复脚本传递额外配置，例如：
#       export LOG_LEVEL=1          # INFO 级别
#       export LOG_TO_CONSOLE=0     # 不输出到控制台
#     在调用前设置即可。
#
# 作者：Shuery-Shuai
# 日期：2026-07-24
# 版本：1.2.1
#===============================================================================

#===============================================================================
# 可配置参数（均可通过同名环境变量覆盖）
#===============================================================================
LOGGER_TAG="${LOGGER_TAG:-restore-packages-hotplug}"
MAX_WAIT="${MAX_WAIT:-180}"
CHECK_INTERVAL="${CHECK_INTERVAL:-10}"
PING_TARGET="${PING_TARGET:-8.8.8.8}"
RESTORE_SCRIPT="${RESTORE_SCRIPT:-/usr/bin/restore-packages.sh}"
TRIGGER_LOG="${TRIGGER_LOG:-/var/log/restore-packages-trigger.log}"

#===============================================================================
# 事件过滤：仅处理 WAN 接口的 ifup 事件
#===============================================================================
[ "$ACTION" = "ifup" ] && [ "$INTERFACE" = "wan" ] || exit 0

#===============================================================================
# 互斥锁：确保同一时间只有一个等待进程在运行
#===============================================================================
if ! exec 9>/var/run/restore-hotplug.lock 2>/dev/null; then
    logger -t "$LOGGER_TAG" "无法创建锁文件，放弃互斥保护"
else
    if ! flock -n 9; then
        logger -t "$LOGGER_TAG" "已有等待进程在运行，退出"
        exit 0
    fi
fi

#===============================================================================
# 参数验证：确保 MAX_WAIT 和 CHECK_INTERVAL 为正整数，否则使用默认值
#===============================================================================
case "$MAX_WAIT" in
'' | *[!0-9]*)
    logger -t "$LOGGER_TAG" "警告: MAX_WAIT 值无效，使用默认值 180 秒"
    MAX_WAIT=180
    ;;
esac
case "$CHECK_INTERVAL" in
'' | *[!0-9]* | 0)
    logger -t "$LOGGER_TAG" "警告: CHECK_INTERVAL 值无效，使用默认值 10 秒"
    CHECK_INTERVAL=10
    ;;
esac
if [ ! -x "$RESTORE_SCRIPT" ]; then
    logger -t "$LOGGER_TAG" "恢复脚本不可执行: $RESTORE_SCRIPT"
    exit 1
fi
LOG_DIR=$(dirname "$TRIGGER_LOG")
if ! mkdir -p "$LOG_DIR" 2>/dev/null || [ ! -d "$LOG_DIR" ]; then
    logger -t "$LOGGER_TAG" "无法创建日志目录 $LOG_DIR，回退到 /tmp"
    TRIGGER_LOG="/tmp/restore-packages-trigger.log"
fi

#===============================================================================
# 后台子进程：检测网络、调用恢复脚本
#===============================================================================
logger -t "$LOGGER_TAG" "WAN 接口上线，开始等待网络就绪..."

#-----------------------------------------------------------------------
# 循环检测网络连通性，每次间隔 CHECK_INTERVAL 秒，
# 若累计等待超过 MAX_WAIT 秒则超时退出。
#-----------------------------------------------------------------------
(
    waited=0
    while [ "$waited" -lt "$MAX_WAIT" ]; do
        if ping -c 1 -W 2 "$PING_TARGET" >/dev/null 2>&1; then
            logger -t "$LOGGER_TAG" "网络已就绪，启动恢复脚本: $RESTORE_SCRIPT"

            # 如需为恢复脚本传递特定日志级别，可在此处设置环境变量，例如：
            # export LOG_LEVEL=1
            # export LOG_TO_CONSOLE=0

            # 执行恢复脚本，标准输出和错误均追加到日志文件
            "$RESTORE_SCRIPT" >>"$TRIGGER_LOG" 2>&1
            exit_code=$?

            logger -t "$LOGGER_TAG" "恢复脚本结束，退出码: $exit_code"
            exit $exit_code
        fi

        sleep "$CHECK_INTERVAL"
        waited=$((waited + CHECK_INTERVAL))
    done

    # 超时未连通
    logger -t "$LOGGER_TAG" "等待网络就绪超时 (已等待 ${MAX_WAIT} 秒)，放弃执行恢复脚本"
    exit 1
) &
#===============================================================================
# 父进程立即返回，避免阻塞 hotplug 后续事件处理
#===============================================================================
exit 0
#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
