Linux 系统启动流程深度剖析:从按下电源到出现登录界面

68 阅读7分钟

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 系统从按下电源到出现登录界面的整个启动流程。这个过程涉及多个层次的协作:

  1. 硬件初始化:BIOS/UEFI 固件初始化和 POST 自检
  2. 引导加载程序:GRUB2 加载内核和 initramfs
  3. 内核初始化:硬件检测、驱动加载、根文件系统挂载
  4. initramfs 阶段:临时根文件系统,为真正的根文件系统挂载做准备
  5. systemd 初始化:PID 1 进程,管理系统服务和启动目标
  6. 服务启动:系统服务、网络服务、显示管理器依次启动
  7. 登录界面:用户认证和桌面环境启动

每个阶段都有相应的监控和调试工具,这些脚本可以帮助系统管理员深入理解启动过程,诊断启动问题,并优化启动性能。掌握这些知识对于 Linux 系统管理和故障排除至关重要。