#!/bin/bash DEV_PATH="$1" LOG_FILE="/var/log/usb_disk_fix.log" # 用于调试和记录所有输出 # 确保日志文件存在且可写 touch "$LOG_FILE" chmod 644 "$LOG_FILE" # 确保普通用户可读,方便查看 # --- 辅助函数:同时输出到终端和日志文件 --- # 所有重要的信息都通过这个函数输出 log_and_print() { local message="$1" echo "$(date): $message" | tee -a "$LOG_FILE" } # --- 辅助函数:执行命令并将其输出同时记录到终端和日志文件 --- execute_and_log_output() { local description="$1" local command_to_run="$2" log_and_print "Initiating command: $description" log_and_print "Executing: $command_to_run" # 执行命令,将其标准输出和标准错误都通过 tee 同时发送到终端和日志文件 # 注意:这里移除了后台运行的 '&' 符号,使命令同步执行 eval "$command_to_run" 2>&1 | tee -a "$LOG_FILE" log_and_print "Command for '$description' finished." } # --- 主要逻辑 --- log_and_print "Script started for $DEV_PATH" # 1. 验证输入设备路径 if ! [ -b "$DEV_PATH" ]; then log_and_print "$DEV_PATH 不是一个块设备。退出。" exit 0 fi # 2. 检查文件系统类型是否为 ext2 或 ext3 FS_TYPE=$(blkid -s TYPE -o value "$DEV_PATH" 2>/dev/null) if [[ "$FS_TYPE" != "ext2" && "$FS_TYPE" != "ext3" ]]; then log_and_print "$DEV_PATH 不是EXT2或EXT3文件系统 (类型: $FS_TYPE)。退出。" exit 0 fi # 3. 检查是否已经挂载 if findmnt -M "$DEV_PATH" &>/dev/null; then log_and_print "$DEV_PATH 已经挂载。GVfs 或其他已处理。退出。" exit 0 fi # 4. 尝试临时挂载以检测是否能正常挂载 TEMP_MOUNT_DIR=$(mktemp -d) log_and_print "Attempting temporary mount of $DEV_PATH to $TEMP_MOUNT_DIR" MOUNT_OUTPUT=$(mount "$DEV_PATH" "$TEMP_MOUNT_DIR" 2>&1) MOUNT_STATUS=$? if [ "$MOUNT_STATUS" -eq 0 ]; then # 挂载成功,说明没有问题,GVfs 应该能处理 umount "$TEMP_MOUNT_DIR" rmdir "$TEMP_MOUNT_DIR" log_and_print "$DEV_PATH 成功临时挂载。GVfs 将处理。退出。" exit 0 else # 挂载失败,尝试进行修复 log_and_print "$DEV_PATH 无法挂载。尝试进行修复 (fsck 和 resize2fs -f)。" # 构建修复命令字符串 REPAIR_COMMAND=" echo \"$(date): 检测到USB磁盘 ($DEV_PATH) 无法挂载。尝试进行文件系统修复。\" # 第一次文件系统检查 echo \"$(date): 正在进行文件系统检查 (fsck -fy) 第一次尝试...\" # 使用 yes | 确保所有交互式提示都回答 'yes' FSCK_OUTPUT_1=\$(yes | fsck -fy '$DEV_PATH' 2>&1) FS_CHECK_STATUS_1=\$? echo \"$(date): 第一次 fsck 输出 (状态码: \$FS_CHECK_STATUS_1):\" echo \"\$FSCK_OUTPUT_1\" local initial_fsck_had_errors=false if [ \$FS_CHECK_STATUS_1 -ne 0 ]; then echo \"$(date): WARNING: 第一次文件系统检查 (fsck) 发现错误。继续尝试 resize2fs。\" initial_fsck_had_errors=true else echo \"$(date): 第一次文件系统检查 (fsck) 成功完成。\" fi # 强制调整文件系统大小 echo \"$(date): 正在强制调整文件系统大小 (resize2fs -f)...这可能需要一些时间。\" RESIZE_OUTPUT=\$(resize2fs -f '$DEV_PATH' 2>&1) RESIZE_STATUS=\$? echo \"$(date): resize2fs 输出 (状态码: \$RESIZE_STATUS):\" echo \"\$RESIZE_OUTPUT\" if [ \$RESIZE_STATUS -ne 0 ]; then echo \"$(date): ERROR: 文件系统修复 (resize2fs -f) 失败。请手动检查。\" exit 1 else echo \"$(date): 文件系统修复 (resize2fs -f) 完成!\" fi # *** 关键修改:修复后不再自己挂载,而是通过 udisksctl 触发桌面环境挂载 *** echo \"$(date): 尝试通过 udisksctl 挂载磁盘,让桌面环境接管...\" # 注意:udisksctl 必须以原始用户身份运行,而不是 root if [ -n \"\$SUDO_USER\" ]; then UDISKS_MOUNT_OUTPUT=\$(sudo -u \"\$SUDO_USER\" udisksctl mount -b \"\$DEV_PATH\" 2>&1) UDISKS_MOUNT_STATUS=\$? else # 如果没有 SUDO_USER (例如直接以 root 运行),则尝试直接 udisksctl mount # 这在桌面环境下可能不理想,但作为备用方案 echo \"$(date): 警告:未检测到 SUDO_USER 变量,尝试直接以当前用户身份运行 udisksctl。\" UDISKS_MOUNT_OUTPUT=\$(udisksctl mount -b \"\$DEV_PATH\" 2>&1) UDISKS_MOUNT_STATUS=\$? fi if [ \$UDISKS_MOUNT_STATUS -eq 0 ]; then echo \"$(date): USB磁盘 (\$DEV_PATH) 修复后成功通过 udisksctl 挂载!桌面环境将接管。\" # 由于 udisksctl 会挂载到它自己的位置,我们不需要卸载 TEMP_MOUNT_DIR # TEMP_MOUNT_DIR 应该保持为空,并在脚本结束时被 rmdir 清理 else echo \"$(date): ERROR: USB磁盘 (\$DEV_PATH) 修复后通过 udisksctl 挂载失败。请手动检查。\" echo \"udisksctl mount output: \$UDISKS_MOUNT_OUTPUT\" exit 1 fi echo \"$(date): 修复流程结束。\" " # 执行修复命令,所有输出都将记录到 LOG_FILE 并打印到终端 execute_and_log_output "USB磁盘修复 - $DEV_PATH" "$REPAIR_COMMAND" # 清理临时挂载点(无论修复成功与否,只要它存在且为空) # 在修复成功的情况下,TEMP_MOUNT_DIR 应该没有被实际使用,所以是空的 if [ -d "$TEMP_MOUNT_DIR" ]; then rmdir "$TEMP_MOUNT_DIR" 2>/dev/null fi exit 0 fi