1. 系统启动概述
Linux 系统启动是一个复杂而精密的过程,涉及多个阶段的协同工作。了解整个启动流程对于系统管理员和开发者来说至关重要,能够帮助诊断启动问题、优化启动速度以及深入理解操作系统工作原理。
graph TD
A[按下电源按钮] --> B[BIOS/UEFI 固件初始化]
B --> C[POST 上电自检]
C --> D[引导加载程序]
D --> E[Linux 内核加载]
E --> F[initramfs 初始化]
F --> G[systemd 初始化]
G --> H[系统服务启动]
H --> I[显示管理器启动]
I --> J[登录界面显示]
style A fill:#2c3e50,color:#ffffff
style B fill:#3498db,color:#ffffff
style C fill:#3498db,color:#ffffff
style D fill:#9b59b6,color:#ffffff
style E fill:#e74c3c,color:#ffffff
style F fill:#e67e22,color:#ffffff
style G fill:#1abc9c,color:#ffffff
style H fill:#16a085,color:#ffffff
style I fill:#27ae60,color:#ffffff
style J fill:#2ecc71,color:#ffffff
2. 硬件初始化阶段
2.1 BIOS/UEFI 初始化
当按下电源按钮时,计算机首先执行固件代码:
创建测试脚本:bios_test.sh
#!/bin/bash
# BIOS/UEFI 信息检测脚本
echo "=== BIOS/UEFI 信息检测 ==="
# 检查系统是使用 BIOS 还是 UEFI
if [ -d /sys/firmware/efi ]; then
echo "启动模式: UEFI"
echo "EFI 变量目录: /sys/firmware/efi"
# 显示 EFI 变量(需要 root 权限)
if [ "$(id -u)" -eq 0 ]; then
echo "EFI 变量列表:"
ls -la /sys/firmware/efi/efivars/ 2>/dev/null | head -10
fi
else
echo "启动模式: Legacy BIOS"
fi
# 显示固件信息
echo -e "\n=== 固件信息 ==="
if command -v dmidecode &> /dev/null && [ "$(id -u)" -eq 0 ]; then
echo "BIOS 信息:"
dmidecode -t bios | grep -E "Vendor|Version|Release Date" | head -5
fi
# 检查启动设备顺序
echo -e "\n=== 启动设备信息 ==="
if [ -d /sys/firmware/efi ]; then
efibootmgr 2>/dev/null || echo "需要安装 efibootmgr 工具"
else
echo "BIOS 启动顺序需要通过 BIOS 设置界面查看"
fi
2.2 POST(上电自检)过程
POST 过程由硬件固件自动执行,主要完成以下检测:
- 内存检测
- CPU 检测
- 存储设备检测
- 外设初始化
3. 引导加载程序阶段
3.1 GRUB2 引导加载程序
创建 GRUB 配置文件:/etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# 自定义 GRUB 配置
menuentry 'Linux 深度调试模式' {
load_video
insmod gzio
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
linux /vmlinuz-linux root=/dev/sda2 ro systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M earlyprintk=vga,keep
initrd /initramfs-linux.img
}
menuentry 'Linux 单用户模式' {
load_video
insmod gzio
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
linux /vmlinuz-linux root=/dev/sda2 ro single
initrd /initramfs-linux.img
}
创建 GRUB 设置脚本:grub_setup.sh
#!/bin/bash
# GRUB2 配置和管理脚本
echo "=== GRUB2 配置和管理 ==="
# 备份原有配置
echo "备份 GRUB 配置..."
sudo cp /etc/default/grub /etc/default/grub.backup.$(date +%Y%m%d)
sudo cp -r /etc/grub.d /etc/grub.d.backup.$(date +%Y%m%d)
# 显示当前 GRUB 配置
echo -e "\n=== 当前 GRUB 配置 ==="
cat /etc/default/grub
# 生成 GRUB 配置文件
echo -e "\n=== 生成 GRUB 配置 ==="
sudo grub-mkconfig -o /boot/grub/grub.cfg
# 显示生成的菜单条目
echo -e "\n=== GRUB 菜单条目 ==="
grep -A 10 "menuentry" /boot/grub/grub.cfg | head -20
# 安装 GRUB 到引导设备(如果需要重新安装)
echo -e "\n=== GRUB 安装信息 ==="
if [ -d /sys/firmware/efi ]; then
echo "UEFI 系统安装 GRUB:"
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
else
echo "BIOS 系统安装 GRUB:"
sudo grub-install /dev/sda
fi
# 验证安装
echo -e "\n=== GRUB 安装验证 ==="
sudo grub-install --verify /dev/sda
3.2 引导参数详解
创建引导参数分析脚本:boot_params_analysis.sh
#!/bin/bash
# Linux 内核引导参数分析
echo "=== 当前内核引导参数分析 ==="
# 获取当前内核引导参数
BOOT_PARAMS=$(cat /proc/cmdline)
echo "当前引导参数: $BOOT_PARAMS"
echo -e "\n=== 引导参数解析 ==="
IFS=' ' read -ra PARAMS <<< "$BOOT_PARAMS"
for param in "${PARAMS[@]}"; do
case $param in
root=*)
echo "根文件系统: ${param#root=}"
;;
ro|rw)
echo "挂载模式: $param"
;;
init=*)
echo "初始化进程: ${param#init=}"
;;
systemd.unit=*)
echo "systemd 目标单元: ${param#systemd.unit=}"
;;
debug)
echo "调试模式: 启用"
;;
quiet)
echo "安静模式: 启用"
;;
splash)
echo "启动画面: 启用"
;;
resume=*)
echo "休眠恢复设备: ${param#resume=}"
;;
esac
done
echo -e "\n=== 常用引导参数说明 ==="
cat << 'EOF'
常用引导参数:
- root=DEVICE 指定根文件系统设备
- ro 以只读方式挂载根文件系统
- rw 以读写方式挂载根文件系统
- init=PATH 指定初始化程序路径
- systemd.unit=UNIT 指定 systemd 启动目标
- debug 启用调试输出
- quiet 减少启动信息输出
- splash 显示启动画面
- single 单用户模式
- emergency 紧急模式
- rescue 救援模式
EOF
4. Linux 内核初始化阶段
4.1 内核解压和初始化
创建内核信息检查脚本:kernel_info.sh
#!/bin/bash
# Linux 内核信息检查脚本
echo "=== 内核基本信息 ==="
uname -a
echo -e "\n=== 内核版本详细信息 ==="
cat /proc/version
echo -e "\n=== 内核编译配置 ==="
if [ -f /proc/config.gz ]; then
zcat /proc/config.gz | grep -E "^(CONFIG_DEBUG|CONFIG_MODULES|CONFIG_BLK_DEV)" | head -20
else
echo "内核配置不可用,需要启用 CONFIG_IKCONFIG_PROC"
fi
echo -e "\n=== 内核模块信息 ==="
lsmod | head -10
echo -e "\n=== 内核启动消息 ==="
dmesg | head -30
echo -e "\n=== 内核参数 ==="
sysctl -a 2>/dev/null | grep -E "^(kernel|vm|net)" | head -20
4.2 设备驱动初始化
创建设备驱动分析脚本:driver_analysis.sh
#!/bin/bash
# 设备驱动初始化分析
echo "=== 设备树信息 (如果可用) ==="
if [ -d /proc/device-tree ]; then
find /proc/device-tree -type f | head -10
else
echo "设备树不可用 (非 ARM 系统)"
fi
echo -e "\n=== PCI 设备信息 ==="
lspci | head -10
echo -e "\n=== USB 设备信息 ==="
lsusb | head -10
echo -e "\n=== 块设备信息 ==="
lsblk
echo -e "\n=== 内核探测到的硬件 ==="
dmesg | grep -E "(probing|initializing|found)" | head -15
echo -e "\n=== 加载的驱动模块 ==="
find /sys/module -name "version" -exec sh -c 'echo "{}: $(cat {})"' \; 2>/dev/null | head -15
5. initramfs 阶段
5.1 initramfs 结构和功能
创建 initramfs 分析脚本:initramfs_analysis.sh
#!/bin/bash
# initramfs 文件系统分析脚本
echo "=== initramfs 信息 ==="
# 查找当前使用的 initramfs
INITRAMFS_FILE=$(ls /boot/initramfs-*.img 2>/dev/null | head -1)
if [ -z "$INITRAMFS_FILE" ]; then
INITRAMFS_FILE=$(ls /boot/initrd.img-* 2>/dev/null | head -1)
fi
if [ -n "$INITRAMFS_FILE" ]; then
echo "当前 initramfs 文件: $INITRAMFS_FILE"
# 创建临时目录用于解压分析
TEMP_DIR=$(mktemp -d)
echo "临时分析目录: $TEMP_DIR"
# 解压 initramfs
echo -e "\n=== 解压 initramfs 进行分析 ==="
cd "$TEMP_DIR"
# 检测 initramfs 格式并解压
if file "$INITRAMFS_FILE" | grep -q "cpio archive"; then
zcat "$INITRAMFS_FILE" | cpio -idmv 2>/dev/null
else
# 尝试其他格式
cp "$INITRAMFS_FILE" initramfs.gz
gunzip -c initramfs.gz | cpio -idmv 2>/dev/null
fi
echo -e "\n=== initramfs 目录结构 ==="
find . -type f -name "init" -o -name "*init*" | head -10
ls -la
echo -e "\n=== initramfs 中的关键文件 ==="
if [ -f init ]; then
echo "init 脚本内容 (前50行):"
head -50 init
fi
# 清理
cd /
rm -rf "$TEMP_DIR"
else
echo "未找到 initramfs 文件"
fi
echo -e "\n=== 查看 initramfs 生成配置 ==="
if [ -f /etc/mkinitcpio.conf ]; then
echo "mkinitcpio 配置:"
grep -v "^#" /etc/mkinitcpio.conf | grep -v "^$"
elif [ -f /etc/dracut.conf ]; then
echo "dracut 配置:"
grep -v "^#" /etc/dracut.conf | grep -v "^$" | head -20
fi
5.2 自定义 initramfs
创建自定义 initramfs 脚本:custom_initramfs.sh
#!/bin/bash
# 自定义 initramfs 创建脚本
echo "=== 创建自定义 initramfs ==="
BACKUP_DIR="/boot/backup_$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# 备份原有 initramfs
echo "备份原有 initramfs..."
cp /boot/initramfs-*.img "$BACKUP_DIR/" 2>/dev/null || true
# 获取当前内核版本
KERNEL_VERSION=$(uname -r)
echo "当前内核版本: $KERNEL_VERSION"
# 创建自定义 hooks 目录
HOOKS_DIR="/etc/initramfs-tools/hooks"
SCRIPTS_DIR="/etc/initramfs-tools/scripts"
mkdir -p "$HOOKS_DIR"
mkdir -p "$SCRIPTS_DIR/local-premount"
# 创建自定义 hook
echo "创建自定义 hook..."
cat > "$HOOKS_DIR/custom_debug" << 'EOF'
#!/bin/sh
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
# 添加调试工具
copy_exec /bin/bash /bin
copy_exec /usr/bin/strace /bin
copy_exec /bin/grep /bin
copy_exec /bin/sed /bin
# 添加额外的模块
# manual_add_modules debug_module
echo "自定义 debug hook 执行完成"
EOF
chmod +x "$HOOKS_DIR/custom_debug"
# 创建自定义初始化脚本
echo "创建自定义初始化脚本..."
cat > "$SCRIPTS_DIR/local-premount/debug_setup" << 'EOF'
#!/bin/sh
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
echo "=== 自定义初始化调试 ==="
echo "当前根设备: $ROOT"
echo "根文件系统类型: $ROOTFSTYPE"
echo "初始化参数: $@"
# 调试信息
mount -t proc proc /proc
echo "挂载点信息:"
cat /proc/mounts
umount /proc
# 创建调试文件
echo "初始化阶段完成" > /run/initramfs/debug.log
EOF
chmod +x "$SCRIPTS_DIR/local-premount/debug_setup"
# 更新 initramfs
echo "更新 initramfs..."
update-initramfs -u -k "$KERNEL_VERSION"
echo "自定义 initramfs 创建完成"
6. systemd 初始化阶段
6.1 systemd 启动流程分析
创建 systemd 启动分析脚本:systemd_analysis.sh
#!/bin/bash
# systemd 系统启动分析脚本
echo "=== systemd 系统信息 ==="
systemd-analyze
echo -e "\n=== 启动时间详细分析 ==="
systemd-analyze blame | head -15
echo -e "\n=== 关键启动路径分析 ==="
systemd-analyze critical-chain
echo -e "\n=== systemd 版本信息 ==="
systemd --version
echo -e "\n=== 系统状态 ==="
systemctl status --no-pager -l
echo -e "\n=== 失败的单元 ==="
systemctl --failed --no-pager
echo -e "\n=== 启动目标 ==="
systemctl get-default
echo -e "\n=== 当前运行级别/目标 ==="
runlevel
systemctl list-units --type=target --state=active
6.2 systemd 单元文件分析
创建 systemd 单元分析脚本:unit_analysis.sh
#!/bin/bash
# systemd 单元文件分析
echo "=== 关键系统单元状态 ==="
CRITICAL_UNITS=(
"systemd-journald.service"
"systemd-udevd.service"
"dbus.service"
"network.service"
"NetworkManager.service"
"systemd-logind.service"
"getty.target"
"multi-user.target"
"graphical.target"
)
for unit in "${CRITICAL_UNITS[@]}"; do
if systemctl is-enabled "$unit" &>/dev/null; then
status=$(systemctl is-active "$unit")
enabled=$(systemctl is-enabled "$unit")
echo "单元: $unit | 状态: $status | 启用: $enabled"
fi
done
echo -e "\n=== 单元依赖关系分析 ==="
# 分析关键单元的依赖
for unit in "${CRITICAL_UNITS[@]:0:3}"; do
if systemctl cat "$unit" &>/dev/null; then
echo -e "\n--- $unit 依赖关系 ---"
systemctl list-dependencies "$unit" --no-pager | head -10
fi
done
echo -e "\n=== 单元文件位置 ==="
systemctl cat getty@.service | head -20
7. 服务启动阶段
7.1 系统服务启动顺序
创建服务启动分析脚本:service_analysis.sh
#!/bin/bash
# 系统服务启动顺序分析
echo "=== 服务启动顺序和时间 ==="
# 使用 systemd-analyze 获取详细的时间信息
systemd-analyze plot > /tmp/boot-analysis.svg
echo "启动时间图表已保存到: /tmp/boot-analysis.svg"
echo -e "\n=== 按启动时间排序的服务 ==="
systemd-analyze blame --no-pager | while read line; do
time=$(echo $line | cut -d' ' -f1)
service=$(echo $line | cut -d' ' -f2)
if [[ $time == *"ms" ]] || [[ $time == *"s" ]]; then
echo "服务: $service | 时间: $time"
fi
done | head -20
echo -e "\n=== 关键服务状态检查 ==="
KEY_SERVICES=(
"acpid"
"cron"
"ssh"
"rsyslog"
"systemd-journald"
"dbus"
"NetworkManager"
"gdm"
"lightdm"
"sddm"
)
for service in "${KEY_SERVICES[@]}"; do
if systemctl is-active "$service" &>/dev/null || \
systemctl is-active "${service}.service" &>/dev/null; then
service_name="$service"
if ! systemctl is-active "$service" &>/dev/null; then
service_name="${service}.service"
fi
status=$(systemctl is-active "$service_name")
echo "服务: $service | 状态: $status"
fi
done
7.2 自定义系统服务
创建自定义服务示例:custom_service.sh
#!/bin/bash
# 创建自定义系统服务示例
echo "=== 创建自定义系统服务示例 ==="
SERVICE_DIR="/etc/systemd/system"
SERVICE_NAME="boot-analyzer"
# 创建自定义服务文件
cat > "$SERVICE_DIR/${SERVICE_NAME}.service" << EOF
[Unit]
Description=Boot Process Analyzer Service
After=network.target
Wants=network.target
Documentation=https://example.com/docs
[Service]
Type=simple
ExecStart=/usr/local/bin/boot-analyzer.sh
ExecStartPost=/bin/bash -c 'echo "服务启动时间: \$(date)" > /var/log/boot-analyzer.log'
ExecStop=/bin/bash -c 'echo "服务停止时间: \$(date)" >> /var/log/boot-analyzer.log'
Restart=on-failure
RestartSec=5s
TimeoutStartSec=30s
TimeoutStopSec=10s
StandardOutput=journal
StandardError=journal
# 安全设置
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=read-only
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
EOF
# 创建服务执行脚本
cat > "/usr/local/bin/boot-analyzer.sh" << 'EOF'
#!/bin/bash
# Boot Analyzer Service Script
echo "启动分析服务开始运行..."
# 创建日志目录
mkdir -p /var/log/boot-analyzer
# 收集系统信息
{
echo "=== 系统启动分析报告 ==="
echo "生成时间: $(date)"
echo "系统运行时间: $(uptime)"
echo "当前用户: $(whoami)"
echo "=== 内存信息 ==="
free -h
echo "=== 磁盘使用情况 ==="
df -h
echo "=== 系统服务状态 ==="
systemctl list-units --state=running --no-pager | head -20
} > /var/log/boot-analyzer/system-report.log
# 持续监控(示例)
while true; do
echo "分析服务运行中... $(date)" >> /var/log/boot-analyzer/service.log
sleep 60
done
EOF
chmod +x "/usr/local/bin/boot-analyzer.sh"
# 重新加载 systemd 配置
systemctl daemon-reload
# 启用并启动服务
systemctl enable "$SERVICE_NAME.service"
systemctl start "$SERVICE_NAME.service"
echo "自定义服务创建完成"
echo "服务状态: $(systemctl is-active $SERVICE_NAME.service)"
echo "查看日志: journalctl -u $SERVICE_NAME.service -f"
8. 显示管理器和登录界面
8.1 显示管理器配置
创建显示管理器分析脚本:display_manager_analysis.sh
#!/bin/bash
# 显示管理器分析脚本
echo "=== 显示管理器检测 ==="
# 检测当前使用的显示管理器
if systemctl is-active gdm &>/dev/null; then
DM="gdm"
DM_CONFIG="/etc/gdm3/custom.conf"
elif systemctl is-active lightdm &>/dev/null; then
DM="lightdm"
DM_CONFIG="/etc/lightdm/lightdm.conf"
elif systemctl is-active sddm &>/dev/null; then
DM="sddm"
DM_CONFIG="/etc/sddm.conf"
else
DM="未知"
DM_CONFIG=""
fi
echo "当前显示管理器: $DM"
echo "配置文件: $DM_CONFIG"
if [ -n "$DM_CONFIG" ] && [ -f "$DM_CONFIG" ]; then
echo -e "\n=== 显示管理器配置 ==="
grep -v "^#" "$DM_CONFIG" | grep -v "^$" | head -20
fi
echo -e "\n=== X11/Wayland 信息 ==="
if command -v Xorg &>/dev/null; then
echo "Xorg 版本: $(Xorg -version 2>&1 | head -1)"
fi
if command -v weston &>/dev/null; then
echo "Weston (Wayland) 可用"
fi
echo -e "\n=== 当前显示会话 ==="
echo "DISPLAY 环境变量: $DISPLAY"
echo "XDG_SESSION_TYPE: $XDG_SESSION_TYPE"
echo "XDG_CURRENT_DESKTOP: $XDG_CURRENT_DESKTOP"
echo -e "\n=== 登录管理器服务状态 ==="
systemctl status display-manager --no-pager -l
8.2 登录过程分析
创建登录过程分析脚本:login_analysis.sh
#!/bin/bash
# 用户登录过程分析脚本
echo "=== PAM (Pluggable Authentication Modules) 配置 ==="
PAM_CONFIGS=(
"/etc/pam.d/login"
"/etc/pam.d/sshd"
"/etc/pam.d/sudo"
"/etc/pam.d/system-auth"
)
for config in "${PAM_CONFIGS[@]}"; do
if [ -f "$config" ]; then
echo -e "\n--- $config ---"
grep -v "^#" "$config" | grep -v "^$" | head -10
fi
done
echo -e "\n=== 用户认证信息 ==="
# 检查 nsswitch 配置
echo -e "\n--- NSSwitch 配置 ---"
grep -v "^#" /etc/nsswitch.conf | grep -v "^$"
# 检查用户和组配置
echo -e "\n--- 用户数据库配置 ---"
getent passwd | head -5
echo "..."
getent group | head -5
echo -e "\n=== SSH 配置 (如果启用) ===""
if [ -f /etc/ssh/sshd_config ]; then
grep -v "^#" /etc/ssh/sshd_config | grep -v "^$" | head -15
fi
echo -e "\n=== 当前登录用户 ==="
who -a
9. 完整的启动流程监控
9.1 启动时间线监控
创建完整启动监控脚本:boot_timeline.sh
#!/bin/bash
# 完整的启动时间线监控脚本
echo "=== 系统启动时间线分析 ==="
# 创建时间线文件
TIMELINE_FILE="/tmp/boot_timeline_$(date +%Y%m%d_%H%M%S).log"
{
echo "系统启动时间线分析 - $(date)"
echo "=========================================="
echo -e "\n1. 固件和引导加载程序时间线"
echo "------------------------------------------"
# 检查上次关机时间
if [ -f /var/log/wtmp ]; then
echo "最后关机时间:"
last -x | grep shutdown | head -1
fi
echo -e "\n2. 内核初始化时间线"
echo "------------------------------------------"
dmesg | grep -E "(\[.*\]|Linux version|Command line|Memory|CPU)" | head -20
echo -e "\n3. 系统服务启动时间线"
echo "------------------------------------------"
journalctl --since="1 hour ago" | grep -E "(Starting|Started|Reached target)" | head -30
echo -e "\n4. 用户会话启动时间线"
echo "------------------------------------------"
if [ -f /var/log/auth.log ]; then
grep -E "(session opened|login)" /var/log/auth.log | tail -10
elif [ -f /var/log/secure ]; then
grep -E "(session opened|login)" /var/log/secure | tail -10
fi
echo -e "\n5. 当前系统状态"
echo "------------------------------------------"
echo "系统运行时间: $(uptime)"
echo "当前时间: $(date)"
echo "负载平均值: $(cat /proc/loadavg)"
echo "内存使用:"
free -h
echo "挂载的文件系统:"
df -h | grep -E "^(/dev|Filesystem)"
} > "$TIMELINE_FILE"
echo "详细启动时间线已保存到: $TIMELINE_FILE"
cat "$TIMELINE_FILE"
9.2 实时启动监控
创建实时启动监控脚本:realtime_boot_monitor.sh
#!/bin/bash
# 实时启动监控脚本
echo "=== 实时启动监控 ==="
echo "按 Ctrl+C 停止监控"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 监控函数
monitor_boot_process() {
while true; do
clear
echo -e "${BLUE}=== 实时启动监控 - $(date) ===${NC}"
# 系统运行时间
UPTIME=$(uptime)
echo -e "${GREEN}系统运行时间:${NC} $UPTIME"
# 系统负载
LOAD=$(cat /proc/loadavg)
echo -e "${GREEN}系统负载:${NC} $LOAD"
# 内存使用
echo -e "\n${YELLOW}=== 内存使用情况 ===${NC}"
free -h
# 服务状态
echo -e "\n${YELLOW}=== 关键服务状态 ===${NC}"
SERVICES=("systemd-journald" "dbus" "NetworkManager" "display-manager")
for service in "${SERVICES[@]}"; do
if systemctl is-active "$service" &>/dev/null; then
echo -e "${GREEN}✓${NC} $service: 运行中"
else
echo -e "${RED}✗${NC} $service: 未运行"
fi
done
# 用户会话
echo -e "\n${YELLOW}=== 用户会话 ===${NC}"
who
# 最近日志
echo -e "\n${YELLOW}=== 最近系统日志 ===${NC}"
journalctl --since="1 minute ago" --no-pager | tail -5
sleep 5
done
}
# 启动监控
monitor_boot_process
10. 故障排除和调试
10.1 启动问题诊断
创建启动问题诊断脚本:boot_troubleshoot.sh
#!/bin/bash
# 启动问题诊断脚本
echo "=== Linux 启动问题诊断工具 ==="
# 检查系统日志
echo -e "\n1. 检查系统日志..."
journalctl --list-boots | head -5
echo "最近启动日志:"
journalctl -b -1 --no-pager | tail -10
# 检查文件系统
echo -e "\n2. 检查文件系统..."
df -h
echo -e "\n挂载选项:"
mount | grep -E "^(/dev|tmpfs)" | head -10
# 检查内核参数
echo -e "\n3. 检查内核参数..."
cat /proc/cmdline
# 检查硬件错误
echo -e "\n4. 检查硬件错误..."
dmesg | grep -i "error\|warning\|failed" | tail -10
# 检查服务状态
echo -e "\n5. 检查失败的服务..."
systemctl --failed --no-pager
# 检查磁盘健康
echo -e "\n6. 检查磁盘健康状态..."
if command -v smartctl &>/dev/null; then
for disk in /dev/sd?; do
echo "检查 $disk ..."
smartctl -H "$disk" 2>/dev/null | grep -E "(SMART|test)" | head -2
done
fi
# 生成诊断报告
echo -e "\n7. 生成诊断报告..."
REPORT_FILE="/tmp/boot_diagnosis_$(date +%Y%m%d_%H%M%S).txt"
{
echo "Linux 启动诊断报告"
echo "生成时间: $(date)"
echo "========================================"
uname -a
echo "----------------------------------------"
systemd-analyze
echo "----------------------------------------"
systemctl --failed
echo "----------------------------------------"
dmesg | tail -20
} > "$REPORT_FILE"
echo "诊断报告已保存到: $REPORT_FILE"
10.2 紧急恢复模式
创建紧急恢复脚本:emergency_recovery.sh
#!/bin/bash
# 紧急恢复模式工具
echo "=== 紧急恢复模式工具 ==="
if [ "$(id -u)" -ne 0 ]; then
echo "请使用 root 权限运行此脚本"
exit 1
fi
# 检查当前运行级别
CURRENT_TARGET=$(systemctl get-default)
echo "当前默认目标: $CURRENT_TARGET"
echo -e "\n可用的恢复选项:"
echo "1) 重启显示管理器"
echo "2) 检查磁盘空间"
echo "3) 检查文件系统完整性"
echo "4) 重置 systemd 用户会话"
echo "5) 检查网络连接"
echo "6) 进入单用户模式"
echo "7) 重新生成 initramfs"
echo "8) 修复 GRUB 引导"
read -p "请选择恢复选项 (1-8): " choice
case $choice in
1)
echo "重启显示管理器..."
systemctl restart display-manager
;;
2)
echo "检查磁盘空间..."
df -h
echo "检查 inode 使用情况:"
df -i
;;
3)
echo "检查文件系统完整性..."
for fs in /dev/sd*; do
if mount | grep -q "$fs"; then
echo "检查 $fs ..."
fsck -n "$fs"
fi
done
;;
4)
echo "重置 systemd 用户会话..."
systemctl --user daemon-reload
loginctl list-sessions
read -p "输入要重置的会话ID: " session
loginctl terminate-session "$session"
;;
5)
echo "检查网络连接..."
ping -c 3 8.8.8.8
ip addr show
;;
6)
echo "进入单用户模式..."
systemctl rescue
;;
7)
echo "重新生成 initramfs..."
kernel_version=$(uname -r)
mkinitcpio -p "$kernel_version"
;;
8)
echo "修复 GRUB 引导..."
grub-install /dev/sda
update-grub
;;
*)
echo "无效选项"
;;
esac
echo "恢复操作完成"
总结
通过以上详细的步骤和脚本,我们完整地剖析了 Linux 系统从按下电源到出现登录界面的整个启动流程。这个过程涉及多个层次的协作:
- 硬件初始化:BIOS/UEFI 固件初始化和 POST 自检
- 引导加载程序:GRUB2 加载内核和 initramfs
- 内核初始化:硬件检测、驱动加载、根文件系统挂载
- initramfs 阶段:临时根文件系统,为真正的根文件系统挂载做准备
- systemd 初始化:PID 1 进程,管理系统服务和启动目标
- 服务启动:系统服务、网络服务、显示管理器依次启动
- 登录界面:用户认证和桌面环境启动
每个阶段都有相应的监控和调试工具,这些脚本可以帮助系统管理员深入理解启动过程,诊断启动问题,并优化启动性能。掌握这些知识对于 Linux 系统管理和故障排除至关重要。