#!/bin/bash
set -Eeuo pipefail

# ==================== 配置 ====================
BASE_URL="https://bash.niteng.net/R730"
TARGET_IDRAC="2.86.86.86"
TARGET_BIOS="2.19.0"

# 阵列卡目标固件版本：当前版本与目标不一致就执行 DUP，一致则跳过
TARGET_RAID_FW_H730="25.5.9.0001"
TARGET_RAID_FW_H330="25.5.9.0001"

TOOLS_FILE="DellEMC-iDRACTools-Web-LX-9.5.0-4111_A00.tar.gz"
RACADM_BIN="/opt/dell/srvadmin/sbin/racadm"

# ==================== 日志工具 ====================
log() { echo "[$(date '+%F %T')] $*"; }
die() { echo "[$(date '+%F %T')] ERROR: $*" >&2; exit 1; }

WORKDIR="$(mktemp -d /tmp/r730-fw.XXXXXX)"
# 退出时统一清理：工作目录 + 下载到 /tmp 的 DUP。
# 失败/兜底路径也要清，否则最多会有 130MB 留在 /tmp。
trap 'rm -rf "$WORKDIR" /tmp/idrac.bin /tmp/bios.bin /tmp/h330.bin /tmp/h730.bin /tmp/dup_payload_check' EXIT

# ==================== 基础检查 ====================
[[ $EUID -eq 0 ]] || die "请以 root 运行"

# ==================== 机型校验 ====================
# 本脚本的固件包是 13G 专用（iDRAC8 2.86.86.86 / BIOS 2.19.0 / PERC H730、H330 25.5.9.0001），
# 同代的 R730 / R730xd / R630 通用。
# 刷到 R720（12G，iDRAC7）等其它代际上会被 DUP 判为"与系统配置不兼容"，
# 且报出来的是 "disneyinstall.sh: No such file or directory" 这种看不出真实原因的错，
# 所以这里提前拦下，避免下完 110MB 才失败。
SUPPORTED_MODELS="R730 / R730xd / R630"
get_model() {
  if [[ -r /sys/class/dmi/id/product_name ]]; then
    cat /sys/class/dmi/id/product_name 2>/dev/null
  elif command -v dmidecode >/dev/null 2>&1; then
    dmidecode -s system-product-name 2>/dev/null
  fi
}

check_model() {
  local m
  # || true：万一大机型文件在 -r 判断与 cat 之间消失，别让 set -e 直接终止脚本
  m="$(get_model || true)"
  if [[ -z "$m" ]]; then
    log "警告：无法读取机型，跳过机型校验"
    return 0
  fi
  log "服务器机型: $m"
  case "$m" in
    *R730*|*R630*) return 0 ;;
  esac
  die "机型不匹配：本脚本的固件包 (iDRAC $TARGET_IDRAC / BIOS $TARGET_BIOS / PERC $TARGET_RAID_FW_H330)
       只适用于 $SUPPORTED_MODELS（13G），当前机型是「$m」。
       不同代际的固件不能互刷，请改用对应机型自己的固件包。"
}

check_model

# ==================== yum 源（CentOS 7 已 EOL，直接用华为云） ====================
# 官方 mirrorlist.centos.org 已下线、EPEL 7 已归档，不再做可用性探测，
# 直接写成华为云 centos-vault / epel-archive 源（与线上已配置好的机器逐字节一致）
HUAWEI_VAULT="http://mirrors.huaweicloud.com/centos-vault/7.9.2009"
HUAWEI_EPEL="http://mirrors.huaweicloud.com/epel-archive/7"
CENTOS_BASE_REPO="/etc/yum.repos.d/CentOS-Base.repo"
EPEL_REPO="/etc/yum.repos.d/epel.repo"

is_centos7() {
  grep -qiE 'centos( linux)? release 7' /etc/redhat-release 2>/dev/null
}

repo_is_huawei() {
  [[ -f "$1" ]] && grep -q 'mirrors\.huaweicloud\.com' "$1"
}

backup_repo() {
  [[ -f "$1" ]] || return 0
  local stamp backup
  stamp="$(date +%Y%m%d%H%M%S)"
  backup="$1.bak.$stamp"
  cp -a "$1" "$backup"
  log "  已备份: $backup"
}

write_centos_base_repo() {
  cat > "$CENTOS_BASE_REPO" <<EOF
[base]
name=CentOS-7.9.2009 - Base
#mirrorlist=http://mirrorlist.centos.org/?release=7.9.2009&arch=\$basearch&repo=os&infra=\$infra
baseurl=${HUAWEI_VAULT}/os/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[updates]
name=CentOS-7.9.2009 - Updates
#mirrorlist=http://mirrorlist.centos.org/?release=7.9.2009&arch=\$basearch&repo=updates&infra=\$infra
baseurl=${HUAWEI_VAULT}/updates/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[extras]
name=CentOS-7.9.2009 - Extras
#mirrorlist=http://mirrorlist.centos.org/?release=7.9.2009&arch=\$basearch&repo=extras&infra=\$infra
baseurl=${HUAWEI_VAULT}/extras/\$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

[centosplus]
name=CentOS-7.9.2009 - Plus
#mirrorlist=http://mirrorlist.centos.org/?release=7.9.2009&arch=\$basearch&repo=centosplus&infra=\$infra
baseurl=${HUAWEI_VAULT}/centosplus/\$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
EOF
}

write_epel_repo() {
  cat > "$EPEL_REPO" <<EOF
[epel]
name=Extra Packages for Enterprise Linux 7 - \$basearch
baseurl=${HUAWEI_EPEL}/\$basearch
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=\$basearch&infra=\$infra&content=\$contentdir
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7

[epel-debuginfo]
name=Extra Packages for Enterprise Linux 7 - \$basearch - Debug
baseurl=${HUAWEI_EPEL}/\$basearch/debug
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=\$basearch&infra=\$infra&content=\$contentdir
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1

[epel-source]
name=Extra Packages for Enterprise Linux 7 - \$basearch - Source
baseurl=${HUAWEI_EPEL}/source/tree/
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=\$basearch&infra=\$infra&content=\$contentdir
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1
EOF
}

# 已是华为源则跳过，避免每次运行都重复备份/改写/清缓存
# 配置失败不阻塞固件升级，只有真需要装 curl/tar 时才强制要求 yum 可用
setup_yum_repo() {
  YUM_OK=0
  if ! is_centos7; then
    log "非 CentOS 7 系统，跳过 yum 源配置"
    return 0
  fi
  if ! command -v yum >/dev/null 2>&1; then
    log "未找到 yum，跳过 yum 源配置"
    return 0
  fi

  log "===== 配置 yum 源（CentOS 7 已 EOL，使用华为云源）====="

  local changed=0
  if repo_is_huawei "$CENTOS_BASE_REPO"; then
    log "  CentOS-Base 已是华为云源，跳过"
  else
    backup_repo "$CENTOS_BASE_REPO"
    write_centos_base_repo
    changed=1
    log "  CentOS-Base 已写为华为云 centos-vault 源"
  fi

  # EPEL 仅在已安装（epel.repo 存在）时处理，
  # 避免在没装 EPEL 的机器上凭空造出引用了不存在 GPG key 的源
  if [[ -f "$EPEL_REPO" ]]; then
    if repo_is_huawei "$EPEL_REPO"; then
      log "  EPEL 已是华为云源，跳过"
    else
      backup_repo "$EPEL_REPO"
      write_epel_repo
      changed=1
      log "  EPEL 已写为华为云 epel-archive 源"
    fi
  fi

  [[ $changed -eq 1 ]] && yum -q clean all >/dev/null 2>&1

  if timeout 90 yum -q -y makecache >/dev/null 2>&1; then
    log "  yum 源就绪"
    YUM_OK=1
  else
    log "  警告：yum 源不可用，请检查网络/代理（不影响本次固件升级）"
  fi
}

setup_yum_repo

for cmd in curl tar; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    [[ $YUM_OK -eq 1 ]] || die "缺少 $cmd 且 yum 不可用，请先修复 yum 源或网络"
    log "安装 $cmd"
    yum install -y "$cmd" || die "安装 $cmd 失败"
  fi
done

download() {
  local url="$1" out="$2" hdr want got
  log "下载 $url"
  hdr="$WORKDIR/.hdr.$$"
  curl -fL --retry 3 --retry-delay 5 --connect-timeout 15 -D "$hdr" -o "$out" "$url" \
    || { rm -f "$hdr"; die "下载失败: $url"; }
  # 用响应头里的 Content-Length 校验完整性（代理/缓存偶尔会返回截断内容）。
  # -D 会记录所有跳转的响应头，取最后一个 Content-Length；分块传输没有该头则跳过校验。
  want="$(tr -d '\r' < "$hdr" | awk 'tolower($1)=="content-length:"{n=$2} END{print n}')"
  rm -f "$hdr"
  got="$(stat -c%s "$out" 2>/dev/null || echo 0)"
  if [[ "$want" =~ ^[0-9]+$ ]] && (( got != want )); then
    die "下载不完整: $url 期望 ${want} 字节，实际 ${got} 字节"
  fi
}

# ==================== iDRAC Tools（按需安装） ====================
if [[ ! -x "$RACADM_BIN" ]] && ! command -v racadm >/dev/null 2>&1; then
  log "安装 iDRAC Tools"
  download "${BASE_URL}/${TOOLS_FILE}" "$WORKDIR/$TOOLS_FILE"
  tar -zxf "$WORKDIR/$TOOLS_FILE" -C "$WORKDIR"

  # 包内安装脚本是 racadm/install_racadm.sh（包里没有 install.sh），
  # 且该脚本内部用相对路径引用 RHEL7/x86_64/*.rpm，必须在 racadm/ 目录下执行
  RACADM_INSTALLER="$(find "$WORKDIR" -maxdepth 4 -type f -name 'install_racadm.sh' -print -quit)"
  [[ -n "$RACADM_INSTALLER" ]] || die "未找到 racadm 安装脚本 install_racadm.sh"
  log "执行 racadm 安装脚本: $RACADM_INSTALLER"
  (cd "$(dirname "$RACADM_INSTALLER")" && bash ./install_racadm.sh) \
    || log "install_racadm.sh 返回非 0，继续检查 racadm 是否可用"
fi

[[ -x "$RACADM_BIN" ]] || RACADM_BIN="$(command -v racadm || true)"
[[ -x "$RACADM_BIN" ]] || die "racadm 未找到"
log "使用 racadm: $RACADM_BIN"

# ==================== 取值工具 ====================
# 从 racadm 输出里抽出 "Key=Value" 的 Value（去掉 Key 和首尾空白）
# 允许 key 前后有空白：get 的输出是紧凑的 "Version=x"，放开更稳；
# getversion 那种 "Bios Version = x"（key 内含空格）依然不会误匹配。
# 这是过滤器语义：永远返回 0，由调用方判断输出是否为空。
# （否则 head 提前关闭会让 grep 收到 SIGPIPE，在 pipefail 下成功也返回非 0）
parse_kv() {
  grep -E '^[[:space:]]*[A-Za-z][A-Za-z0-9._]*[[:space:]]*=' 2>/dev/null \
    | head -n1 \
    | sed 's/^[^=]*=//' \
    | tr -d '\r' \
    | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' || true
}

get_value() {
  "$RACADM_BIN" get "$1" 2>/dev/null | parse_kv
}

get_bios_version() {
  local v
  v="$(get_value 'BIOS.SysInformation.SystemBiosVersion' || true)"
  [[ -n "$v" ]] && { printf '%s\n' "$v"; return 0; }
  v="$("$RACADM_BIN" getversion -b 2>/dev/null \
       | grep -iE 'Bios Version' | sed 's/.*=//;s/^[[:space:]]*//;s/[[:space:]]*$//' \
       | tr -d '\r' | head -n1 || true)"
  [[ -n "$v" ]] && { printf '%s\n' "$v"; return 0; }
  return 1
}

get_idrac_version() {
  local v
  v="$(get_value 'iDRAC.Info.Version' || true)"
  [[ -n "$v" ]] && { printf '%s\n' "$v"; return 0; }
  v="$("$RACADM_BIN" getversion 2>/dev/null \
       | grep -iE '^ *iDRAC Version' | sed 's/.*=//;s/^[[:space:]]*//;s/[[:space:]]*$//' \
       | tr -d '\r' | head -n1 || true)"
  [[ -n "$v" ]] && { printf '%s\n' "$v"; return 0; }
  return 1
}

# 阵列卡检测：返回 "型号|固件版本"
detect_raid_card() {
  local raw
  raw="$("$RACADM_BIN" storage get controllers -o 2>/dev/null)" || return 1

  local name="" fw="" line
  while IFS= read -r line; do
    if [[ "$line" =~ ^[A-Za-z] ]]; then
      if [[ "$name" == *H730* ]]; then printf 'H730|%s\n' "$fw"; return 0; fi
      if [[ "$name" == *H330* ]]; then printf 'H330|%s\n' "$fw"; return 0; fi
      name=""; fw=""
    elif [[ "$line" =~ ^[[:space:]]+Name[[:space:]]*=[[:space:]]*(.*)$ ]]; then
      name="${BASH_REMATCH[1]}"
      name="${name%"${name##*[![:space:]]}"}"
    elif [[ "$line" =~ ^[[:space:]]+FirmwareVersion[[:space:]]*=[[:space:]]*(.*)$ ]]; then
      fw="${BASH_REMATCH[1]}"
      fw="${fw%"${fw##*[![:space:]]}"}"
    fi
  done <<<"$raw"

  if [[ "$name" == *H730* ]]; then printf 'H730|%s\n' "$fw"; return 0; fi
  if [[ "$name" == *H330* ]]; then printf 'H330|%s\n' "$fw"; return 0; fi
  return 1
}

# ==================== 阶段 1: 探测 ====================
probe() {
  log "===== 阶段 1: 获取当前固件/硬件信息 ====="

  # iDRAC 版本只查一次：既当连通性检查，也当取值来源。
  # （racadm 每次要 2~3 秒，之前这里查了两遍，白扔一次）
  local idrac_raw
  idrac_raw="$("$RACADM_BIN" get iDRAC.Info.Version 2>/dev/null)" \
    || die "racadm 无法访问 iDRAC，请检查 iDRAC 网络/USB 通道"

  CURRENT_IDRAC="$(printf '%s\n' "$idrac_raw" | parse_kv || true)"
  # 万一这次输出格式异常，再用原有路径兜一次
  [[ -n "$CURRENT_IDRAC" ]] || CURRENT_IDRAC="$(get_idrac_version || true)"
  [[ -n "$CURRENT_IDRAC" ]] || die "无法读取 iDRAC 版本"

  CURRENT_BIOS="$(get_bios_version  || true)"
  [[ -n "$CURRENT_BIOS" ]] || die "无法读取 BIOS 版本"

  local raid_info
  raid_info="$(detect_raid_card || true)"
  RAID_CARD="${raid_info%%|*}"
  RAID_FW="${raid_info##*|}"

  log "  当前 iDRAC : $CURRENT_IDRAC  (目标 $TARGET_IDRAC)"
  log "  当前 BIOS  : $CURRENT_BIOS   (目标 $TARGET_BIOS)"
  if [[ -n "$RAID_CARD" ]]; then
    log "  阵列卡     : $RAID_CARD  (当前固件 ${RAID_FW:-未知})"
  else
    log "  阵列卡     : 未识别"
  fi
}

# ==================== 阶段 2: 决策 ====================
# 规则只有一条：版本不一致就执行，一致就跳过
decide() {
  log "===== 阶段 2: 判断是否需要升级 ====="

  DO_IDRAC=0; DO_BIOS=0; DO_RAID=""; NEED_REBOOT=0

  [[ "$CURRENT_IDRAC" != "$TARGET_IDRAC" ]] && DO_IDRAC=1
  [[ "$CURRENT_BIOS"  != "$TARGET_BIOS"  ]] && DO_BIOS=1

  case "$RAID_CARD" in
    H730) if [[ "$RAID_FW" != "$TARGET_RAID_FW_H730" ]]; then DO_RAID="h730"; fi ;;
    H330) if [[ "$RAID_FW" != "$TARGET_RAID_FW_H330" ]]; then DO_RAID="h330"; fi ;;
  esac
  # 版本读不到时不能当成"已是最新"，会执行 DUP 交给它自己判断；但要明确告知
  if [[ -n "$RAID_CARD" && -z "$RAID_FW" ]]; then
    log "  警告：读不到阵列卡固件版本，将执行 DUP 由包自己判断"
  fi

  tag() { [[ "$1" -eq 1 ]] && echo "[需升级]" || echo "[已最新]"; }

  log "  iDRAC : $CURRENT_IDRAC -> $TARGET_IDRAC   $(tag $DO_IDRAC)"
  log "  BIOS  : $CURRENT_BIOS  -> $TARGET_BIOS    $(tag $DO_BIOS)"
  if [[ -z "$RAID_CARD" ]]; then
    log "  阵列卡: 未识别，跳过"
  elif [[ -n "$DO_RAID" ]]; then
    log "  阵列卡: $RAID_CARD (当前 ${RAID_FW:-未知}) -> 需升级"
  else
    log "  阵列卡: $RAID_CARD (当前 ${RAID_FW:-未知}) 已是目标版本，跳过"
  fi

  if [[ $DO_IDRAC -eq 0 && $DO_BIOS -eq 0 && -z "$DO_RAID" ]]; then
    log "全部已是目标版本，无需升级。"
    exit 0
  fi
}

# ==================== 阶段 3: 执行升级 ====================
wait_for_idrac() {
  local target="$1" timeout="${2:-1800}" interval=15 elapsed=0
  log "等待 iDRAC 恢复并确认版本 $target ..."
  while (( elapsed < timeout )); do
    local v
    if v="$(get_idrac_version || true)" && [[ -n "$v" ]]; then
      if [[ "$v" == "$target" ]]; then
        log "iDRAC 已恢复，版本: $v"
        return 0
      fi
      log "当前 iDRAC 版本: $v，继续等待..."
    else
      log "iDRAC 暂不可达，等待中..."
    fi
    sleep "$interval"; elapsed=$((elapsed+interval))
  done
  die "等待 iDRAC 升级超时"
}

# DUP 失败时打印关键信息
dup_diagnose() {
  local file="$1"
  local dlog="/var/log/dell/updatepackage/log/support/${file}.log"
  log "---- DUP 失败信息 ----"
  log "  包 md5: $(md5sum "/tmp/$file" 2>/dev/null | cut -d' ' -f1)"
  [[ -f "$dlog" ]] && { log "  DUP 日志尾部:"; tail -n 25 "$dlog" | sed 's/^/    /'; }
  # 自检：从 DUP 切出 payload，确认 disneyinstall.sh / firmimg.d7 在不在。
  # （--extract 不能与其它选项同用，且非 tty 下会去 exec xterm，所以自己按标记切）
  local marker payload=/tmp/dup_payload_check
  marker="$(grep -an '#####Startofarchive#####' "/tmp/${file}" 2>/dev/null | tail -n1 | cut -d: -f1 || true)"
  if [[ -n "$marker" ]]; then
    rm -rf "$payload"; mkdir -p "$payload"
    tail -n +$((marker + 1)) "/tmp/$file" | tar -xzf - -C "$payload" 2>/dev/null || true
    log "  payload 自检: disneyinstall.sh=$([[ -f $payload/disneyinstall.sh ]] && echo 有 || echo 无), firmimg.d7=$([[ -f $payload/payload/firmimg.d7 ]] && echo 有 || echo 无), 顶层条目=$(find "$payload" -maxdepth 1 -mindepth 1 2>/dev/null | wc -l)"
    rm -rf "$payload"
  else
    log "  payload 自检: 未找到 Startofarchive 标记"
  fi
}

# Dell Update Package 退出码：0=成功，2=更新已就绪但需重启后生效；其余按失败处理
run_dup() {
  local file="$1"
  local rc=0

  # 完全照手工步骤：下载到 /tmp/<名字>.bin，chmod +x，cd /tmp，./<名字>.bin -q -f
  download "${BASE_URL}/${file}" "/tmp/${file}"
  chmod +x "/tmp/${file}"

  log "cd /tmp && ./${file} -q -f"
  # cd 到 DUP 所在目录再用 ./ 相对路径执行：DUP 内部用 "$(pwd)/$(basename $0)" 拼
  # --packagepath 传给安装器，用绝对路径从别的目录调用会拼出无效路径。
  ( cd /tmp && "./${file}" -q -f ) || rc=$?

  case "$rc" in
    0) log "  -> ${file} 更新成功"; rm -f "/tmp/${file}"; return 0 ;;
    2) log "  -> ${file} 更新成功（退出码 2：重启后生效）"; NEED_REBOOT=1; rm -f "/tmp/${file}"; return 0 ;;
    *) dup_diagnose "$file"; return "$rc" ;;   # 文件留给诊断/兜底，EXIT trap 会清
  esac
}

# 备用通道：DUP 框架读不到 iDRAC 时会报"与系统配置不兼容"(退出码 5)，
# 此时从 DUP 里切出 iDRAC 固件本体 firmimg.d7，改走 racadm 原生升级通道。
# 这条路不依赖 DUP 框架的 hapi / inventory，只要能 racadm 通就能用。
idrac_via_racadm() {
  local file="idrac.bin" marker payload d7
  marker="$(grep -an '#####Startofarchive#####' "/tmp/${file}" 2>/dev/null | tail -n1 | cut -d: -f1 || true)"
  if [[ -z "$marker" ]]; then
    log "  未找到 DUP payload 标记，无法走 racadm 通道"
    return 1
  fi
  payload="$WORKDIR/idrac_payload"
  rm -rf "$payload"; mkdir -p "$payload"
  tail -n +$((marker + 1)) "/tmp/${file}" | tar -xzf - -C "$payload" 2>/dev/null || true
  d7="$(find "$payload" -name 'firmimg.d7' -print -quit)"
  if [[ -z "$d7" ]]; then
    log "  未从 DUP 中切出 firmimg.d7，无法走 racadm 通道"
    return 1
  fi
  log "  已切出固件: $d7 ($(stat -c%s "$d7") 字节)"
  # payload 已切出，110MB 的 DUP 本体不用再留着占 /tmp
  rm -f "/tmp/${file}"
  log "  执行 racadm update -f firmimg.d7（约 5-10 分钟，期间 iDRAC 会重启）"
  "$RACADM_BIN" update -f "$d7" || return 1
  return 0
}

upgrade() {
  log "===== 阶段 3: 执行升级 ====="

  if [[ $DO_IDRAC -eq 1 ]]; then
    log ">>> 升级 iDRAC"
    if run_dup "idrac.bin"; then
      wait_for_idrac "$TARGET_IDRAC"
    else
      log "  DUP 通道失败，改用 racadm 原生通道重试"
      if idrac_via_racadm; then
        wait_for_idrac "$TARGET_IDRAC"
      else
        die "iDRAC 升级失败：DUP 与 racadm 两条通道都未成功"
      fi
    fi
  fi

  if [[ -n "$DO_RAID" ]]; then
    log ">>> 升级阵列卡 $RAID_CARD"
    run_dup "${DO_RAID}.bin" || die "${RAID_CARD} 阵列卡升级失败"
  fi

  if [[ $DO_BIOS -eq 1 ]]; then
    log ">>> 升级 BIOS"
    # 绝不加 -r：不自动重启，重启由人工决定
    run_dup "bios.bin" || die "BIOS 升级失败"
  fi
}

# ==================== 主流程 ====================
probe
decide
upgrade

if [[ $NEED_REBOOT -eq 1 ]]; then
  log "全部任务完成。BIOS/阵列卡固件需手动重启服务器生效。"
else
  log "全部任务完成。"
fi
