From ca1c38417c7ecebcbb50b826d7b7c70c90f29554 Mon Sep 17 00:00:00 2001 From: beyondx123 <109916089+beyondx123@users.noreply.github.com> Date: Fri, 15 May 2026 17:42:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E6=AC=A1=E4=BF=AE=E6=94=B9=E4=BA=86?= =?UTF-8?q?=E4=B8=89=E4=B8=AA=E5=9C=B0=E6=96=B9=EF=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ① set_boot_kernel(去掉确认,新增禁止自动选最新内核) 移除 read -p 确认,直接写入 /etc/default/grub 同时将 GRUB_SAVEDEFAULT 强制写为 false,防止 GRUB 记住上次选择 干扰指定内核 新增 UUID 有效性检查,获取失败时报错退出而非写入空值 ② hold_default_boot_kernel(新增锁定元包) 原来只锁定具体版本的 linux-image-6.8.0-52-generic 新增锁定 linux-image-generic 和 linux-headers-generic 两个元包——这才是 apt 升级时切换内核的根本原因 ③ 主流程(去掉两个交互确认) 安装完成后自动调用 set_default_boot_kernel + hold_default_boot_kernel,无需用户输入 --- README.md | 75 ++++++++++++++++++++++++++++-------------------- switch_kernel.sh | 52 +++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index be2ec0c..f9c3ee2 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,18 @@ ## 版本:V1.3(支持离线安装 + DKMS 故障处理 + 自动日志记录) ---- +*** ## 功能特性 -✅ **在线/离线双模式**:自动检测网络,无网时切换离线模式 -✅ **DKMS 智能处理**:自动检测问题驱动,提供交互式修复 -✅ **预下载支持**:在有网机器上打包,传到离线机器安装 -✅ **驱动自动编译**:网卡、显卡驱动随内核自动重编译 -✅ **版本锁定**:防止系统自动更新覆盖指定内核 -✅ **自动日志记录**:所有操作追加写入 `log-日期-dacs.log` +✅ **在线/离线双模式**:自动检测网络,无网时切换离线模式\ +✅ **DKMS 智能处理**:自动检测问题驱动,提供交互式修复\ +✅ **预下载支持**:在有网机器上打包,传到离线机器安装\ +✅ **驱动自动编译**:网卡、显卡驱动随内核自动重编译\ +✅ **版本锁定**:防止系统自动更新覆盖指定内核\ +✅ **自动日志记录**:所有操作追加写入 `log-日期-dacs.log` ---- +*** ## 日志功能 @@ -22,6 +22,7 @@ **日志文件命名:** `log-YYYYMMDD-dacs.log`(例如:`log-20240514-dacs.log`) **日志内容包括:** + - 脚本启动/完成时间 - 执行的命令和参数 - 所有关键操作的输出(apt-get、dpkg、dkms 等) @@ -29,6 +30,7 @@ - 系统信息(主机名、当前内核等) **查看日志:** + ```bash # 实时查看日志 tail -f log-$(date +%Y%m%d)-dacs.log @@ -40,7 +42,7 @@ less log-$(date +%Y%m%d)-dacs.log grep -i error log-*.log ``` ---- +*** ## 使用场景 @@ -49,19 +51,20 @@ grep -i error log-*.log **适用:** 目标机器有网络连接 ```bash -sudo ./switch_kernel_V1.2.sh +sudo ./switch_kernel.sh # 或指定版本 -sudo ./switch_kernel_V1.2.sh --version 6.8.0-52-generic +sudo ./switch_kernel.sh --version 6.8.0-52-generic ``` **流程:** + 1. 自动检测网络 ✓ 2. 检查 DKMS 驱动兼容性 3. 在线下载并安装内核 4. 自动编译驱动(DKMS) 5. 配置 GRUB 引导 ---- +*** ### 场景 2:离线安装(两步法) @@ -70,10 +73,11 @@ sudo ./switch_kernel_V1.2.sh --version 6.8.0-52-generic #### 步骤 1:在有网机器上下载包 ```bash -sudo ./switch_kernel_V1.2.sh --download /tmp/kernel-debs --version 6.8.0-52-generic +sudo ./switch_kernel.sh --download ./dacs --version 6.8.0-52-generic ``` **输出:** + ``` [OK] 下载完成,包列表: -rw-r--r-- 1 root root 14M linux-image-6.8.0-52-generic_6.8.0-52.53_amd64.deb @@ -82,7 +86,7 @@ sudo ./switch_kernel_V1.2.sh --download /tmp/kernel-debs --version 6.8.0-52-gene -rw-r--r-- 1 root root 108M linux-modules-extra-6.8.0-52-generic_6.8.0-52.53_amd64.deb 将 /tmp/kernel-debs 目录复制到目标机器后,运行: - sudo ./switch_kernel_V1.2.sh --offline /tmp/kernel-debs --version 6.8.0-52-generic + sudo ./switch_kernel.sh --offline ./dacs --version 6.8.0-52-generic ``` #### 步骤 2:在目标机器上安装 @@ -92,37 +96,38 @@ sudo ./switch_kernel_V1.2.sh --download /tmp/kernel-debs --version 6.8.0-52-gene scp -r /tmp/kernel-debs user@target-machine:/tmp/ # 在目标机器上运行 -sudo ./switch_kernel_V1.2.sh --offline /tmp/kernel-debs --version 6.8.0-52-generic +sudo ./switch_kernel.sh --offline ./dacs --version 6.8.0-52-generic ``` ---- +*** ### 场景 3:跳过 DKMS 编译(解决驱动兼容问题) **适用:** 已知某些驱动与新内核不兼容,想先安装内核 ```bash -sudo ./switch_kernel_V1.2.sh --skip-dkms +sudo ./switch_kernel.sh --skip-dkms ``` **效果:** + - 临时禁用 DKMS 自动编译钩子 - 内核安装完成后自动恢复钩子 - 可重启后手动编译驱动:`sudo dkms autoinstall -k 6.8.0-52-generic` ---- +*** ## 参数说明 -| 参数 | 说明 | 示例 | -|------|------|------| -| `--version <版本>` | 指定内核版本 | `--version 6.8.0-52-generic` | -| `--download <目录>` | 仅下载包到目录(需要网络) | `--download /tmp/debs` | -| `--offline <目录>` | 强制离线模式,从目录安装 | `--offline /tmp/debs` | -| `--skip-dkms` | 跳过 DKMS 自动编译 | `--skip-dkms` | -| `-h, --help` | 显示帮助信息 | `-h` | +| 参数 | 说明 | 示例 | +| ----------------- | ------------- | ---------------------------- | +| `--version <版本>` | 指定内核版本 | `--version 6.8.0-52-generic` | +| `--download <目录>` | 仅下载包到目录(需要网络) | `--download /tmp/debs` | +| `--offline <目录>` | 强制离线模式,从目录安装 | `--offline /tmp/debs` | +| `--skip-dkms` | 跳过 DKMS 自动编译 | `--skip-dkms` | +| `-h, --help` | 显示帮助信息 | `-h` | ---- +*** ## DKMS 故障处理 @@ -162,7 +167,7 @@ sudo ./switch_kernel_V1.2.sh --skip-dkms - **B**:强制完成内核安装,忽略驱动编译错误(驱动可能不可用) - **C**:退出脚本,查看 `TROUBLESHOOTING.md` 手动排查 ---- +*** ## 常见问题 @@ -201,12 +206,14 @@ uname -r ### Q5: elkeid-driver 编译失败怎么办? **临时移除(推荐):** + ```bash sudo dkms remove elkeid-driver/1.7.0.22 --all sudo ./switch_kernel_V1.2.sh ``` **安装完成后恢复:** + ```bash sudo apt-get install --reinstall elkeid-driver # 或手动编译 @@ -216,6 +223,7 @@ sudo dkms install elkeid-driver/1.7.0.22 -k 6.8.0-52-generic ### Q6: 显卡驱动失效怎么办? **NVIDIA 显卡:** + ```bash # 检查驱动状态 nvidia-smi @@ -228,7 +236,7 @@ sudo dkms install nvidia/xxx -k 6.8.0-52-generic **注意:** 如果启用了 Secure Boot,需要关闭或签名驱动模块。 ---- +*** ## 完整示例 @@ -266,7 +274,7 @@ sudo ./switch_kernel_V1.2.sh --skip-dkms --version 6.8.0-52-generic sudo dkms autoinstall -k 6.8.0-52-generic ``` ---- +*** ## 日志与调试 @@ -302,11 +310,12 @@ dmesg | tail -100 参见 `TROUBLESHOOTING.md` 文档。 ---- +*** ## 安全提示 ⚠️ **Secure Boot**:如果启用了 Secure Boot,第三方驱动(NVIDIA、VirtualBox 等)可能无法加载。建议: + - 关闭 Secure Boot(BIOS 设置) - 或为驱动模块签名(高级) @@ -314,11 +323,12 @@ dmesg | tail -100 ⚠️ **生产环境**:建议先在测试环境验证,确认无问题后再部署到生产。 ---- +*** ## 更新日志 ### V1.3 (2024-05-14) + - ✨ 新增 DKMS 兼容性预检查 - ✨ 新增 DKMS 编译失败自动修复 - ✨ 新增 `--skip-dkms` 参数 @@ -327,13 +337,16 @@ dmesg | tail -100 - 📝 添加详细的故障排查文档 ### V1.2 (2024-05-14) + - ✨ 新增离线安装支持 - ✨ 新增 `--download` 模式 - ✨ 新增网络自动检测 - 🐛 修复依赖安装顺序问题 ### V1.0 + - 🎉 初始版本 - ✅ 在线安装内核 - ✅ DKMS 驱动自动编译 - ✅ GRUB 引导配置 + diff --git a/switch_kernel.sh b/switch_kernel.sh index 8ec1e7a..10a661c 100644 --- a/switch_kernel.sh +++ b/switch_kernel.sh @@ -444,28 +444,34 @@ get_kernel_uuid() { set_boot_kernel() { local grub_path="/etc/default/grub" - local default="GRUB_DEFAULT=" local newlines="" local uuid_list uuid_list=$(get_kernel_uuid) + if [[ -z "$uuid_list" || "$uuid_list" == ">" ]]; then + log_err "无法从 grub.cfg 中获取内核 UUID,请确认内核已安装并运行过 update-grub。" + return 1 + fi + + # 重写 GRUB_DEFAULT,同时确保 GRUB_SAVEDEFAULT 不干扰 while read -r l; do - if [[ $l == $default* ]]; then - newlines+="$default\"$uuid_list\"\n" + if [[ $l == GRUB_DEFAULT=* ]]; then + newlines+="GRUB_DEFAULT=\"$uuid_list\"\n" + elif [[ $l == GRUB_SAVEDEFAULT=* ]]; then + newlines+="GRUB_SAVEDEFAULT=false\n" else newlines+="$l\n" fi done < "$grub_path" - echo -e "\n${YELLOW}新的 /etc/default/grub 配置预览:${NC}" - echo -e "$newlines" - - read -p "请确认配置是否正确,输入Y确认回写文件,按任意键跳过: " answer - if [[ "$answer" == "Y" || "$answer" == "y" ]]; then - echo -e "$newlines" > "$grub_path" - return 0 + # 如果文件里没有 GRUB_SAVEDEFAULT 这行,追加一条 + if ! grep -q "^GRUB_SAVEDEFAULT=" "$grub_path"; then + newlines+="GRUB_SAVEDEFAULT=false\n" fi - return 1 + + log_info "写入 GRUB_DEFAULT: $uuid_list" + echo -e "$newlines" > "$grub_path" + return 0 } set_default_boot_kernel() { @@ -482,7 +488,6 @@ set_default_boot_kernel() { log_info "正在更新 GRUB 引导程序..." update-grub 2>&1 | tee -a "$LOG_FILE" - # 如果没有跳过 DKMS,尝试为新内核编译驱动 if [[ "$SKIP_DKMS" == false ]]; then log_info "正在为新内核 ($KERNEL_VERSION) 构建驱动程序 (DKMS)..." if dkms autoinstall -k "$KERNEL_VERSION" 2>&1 | tee -a "$LOG_FILE"; then @@ -494,14 +499,22 @@ set_default_boot_kernel() { else log_info "已跳过 DKMS 自动编译(可重启后手动运行: sudo dkms autoinstall -k $KERNEL_VERSION)。" fi + else + log_err "GRUB 配置写入失败,请手动检查 /etc/default/grub。" + exit 1 fi } hold_default_boot_kernel() { log_info "正在锁定内核版本,防止被系统更新替换..." + # 锁定具体版本包 apt-mark hold linux-image-"$KERNEL_VERSION" apt-mark hold linux-headers-"$KERNEL_VERSION" apt-mark hold linux-modules-extra-"$KERNEL_VERSION" + # 锁定元包,防止 apt 升级时将默认内核切换到新版本 + apt-mark hold linux-image-generic + apt-mark hold linux-headers-generic + log_ok "内核版本已锁定。" } # --- 主程序 --- @@ -607,17 +620,12 @@ else fi fi -# 设置默认启动内核 -read -p "是否设置 $KERNEL_VERSION 为默认启动内核?(Y/N): " answer -if [[ "$answer" == "Y" || "$answer" == "y" ]]; then - set_default_boot_kernel -fi +# 安装成功后:自动设置默认启动内核 + 锁定版本(无需用户确认) +log_step "设置 $KERNEL_VERSION 为默认启动内核..." +set_default_boot_kernel -# 锁定内核版本 -read -p "是否锁定该内核版本(防止系统自动更新内核)?(Y/N): " answer -if [[ "$answer" == "Y" || "$answer" == "y" ]]; then - hold_default_boot_kernel -fi +log_step "锁定内核版本,防止 apt 自动升级切换..." +hold_default_boot_kernel log_ok "操作完成!" echo -e "${YELLOW}注意:如果重启后显卡驱动不正常,请检查 Secure Boot 是否已关闭。${NC}"