Skip to content

Instantly share code, notes, and snippets.

@suntong
Last active May 9, 2026 15:35
Show Gist options
  • Select an option

  • Save suntong/85f04a59f4a047ea3cac9921785bbaee to your computer and use it in GitHub Desktop.

Select an option

Save suntong/85f04a59f4a047ea3cac9921785bbaee to your computer and use it in GitHub Desktop.

从 Live ISO 的 squashfs 中提取和安装完整 Linux 系统

以下是将 Live ISO 中的 squashfs 文件系统提取并部署为可独立启动的常规 Linux 系统的完整步骤:

1. 准备工作

1.1 所需工具和环境

# 在现有 Linux 系统中操作(Live USB 或已安装系统)
sudo apt-get update
sudo apt-get install -y squashfs-tools grub-pc grub-efi-amd64
# 或对应发行版的等价包

1.2 识别目标磁盘

# 查看可用磁盘
lsblk
sudo fdisk -l

# 假设目标磁盘为 /dev/sda
TARGET_DISK="/dev/sda"
BOOT_PART="${TARGET_DISK}1"    # EFI 分区 (建议 500MB-1GB)
ROOT_PART="${TARGET_DISK}2"    # 根分区
# 或使用单个分区方案

2. 提取 Live ISO 内容

2.1 挂载 ISO 文件

# 如果是从 ISO 文件开始
ISO_FILE="ubuntu-22.04-desktop-amd64.iso"
mkdir -p /mnt/iso
sudo mount -o loop "$ISO_FILE" /mnt/iso

# 如果从 Live USB 启动
# 通常已挂载在 /cdrom 或 /run/live/medium
LIVE_MEDIUM="/cdrom"

2.2 定位 squashfs 文件

# 常见位置
SQUASHFS_PATH="/mnt/iso/casper/filesystem.squashfs"
#
SQUASHFS_PATH="/run/live/medium/casper/filesystem.squashfs"
# 也可能是 /live/filesystem.squashfs

# 验证文件存在
ls -lh "$SQUASHFS_PATH"

3. 准备目标分区

3.1 分区(如果需要)

# 使用 fdisk 或 parted 创建分区
sudo fdisk "$TARGET_DISK"
# 创建 GPT 分区表(UEFI)或 MBR(传统 BIOS)
# 创建必要分区

3.2 格式化分区

# 假设根分区为 /dev/sda2
ROOT_PART="/dev/sda2"
BOOT_PART="/dev/sda1"  # 仅 UEFI 需要

# 格式化根分区为 ext4
sudo mkfs.ext4 -L "ROOT" "$ROOT_PART"

# 对于 UEFI 系统,格式化 EFI 分区
sudo mkfs.fat -F 32 -n "EFI" "$BOOT_PART"

3.3 挂载目标分区

# 创建挂载点
sudo mkdir -p /mnt/target

# 挂载根分区
sudo mount "$ROOT_PART" /mnt/target

# 对于 UEFI,创建并挂载 EFI 分区
sudo mkdir -p /mnt/target/boot/efi
sudo mount "$BOOT_PART" /mnt/target/boot/efi

4. 提取和解压 squashfs

4.1 直接提取到目标分区

# 使用 unsquashfs 直接解压到目标
sudo unsquashfs -f -d /mnt/target "$SQUASHFS_PATH"

# 或者使用 mount 和 rsync(更灵活)
mkdir /mnt/squash
sudo mount -t squashfs -o loop "$SQUASHFS_PATH" /mnt/squash
sudo rsync -a /mnt/squash/ /mnt/target/
sudo umount /mnt/squash

4.2 保留必要文件

# 某些 Live 系统文件需要保留
if [ -d "/mnt/iso" ]; then
    # 复制内核和 initramfs
    sudo cp /mnt/iso/casper/vmlinuz /mnt/target/boot/
    sudo cp /mnt/iso/casper/initrd /mnt/target/boot/
    
    # 复制 .disk 信息文件
    sudo cp -r /mnt/iso/.disk /mnt/target/
fi

5. 系统配置调整

5.1 创建必要的目录结构

# 在目标系统中创建缺失的标准目录
sudo mkdir -p /mnt/target/{proc,sys,dev,run,tmp}

5.2 更新 fstab

# 获取分区 UUID
ROOT_UUID=$(sudo blkid -s UUID -o value "$ROOT_PART")
BOOT_UUID=$(sudo blkid -s UUID -o value "$BOOT_PART")

# 创建 /etc/fstab
sudo tee /mnt/target/etc/fstab << EOF
# /etc/fstab: static file system information.
UUID=${ROOT_UUID} / ext4 defaults,errors=remount-ro 0 1
EOF

# 如果使用 EFI 分区
if [ -n "$BOOT_UUID" ]; then
    echo "UUID=${BOOT_UUID} /boot/efi vfat umask=0077 0 1" | sudo tee -a /mnt/target/etc/fstab
fi

5.3 更新 initramfs

# 使用 chroot 重新生成 initramfs
sudo mount --bind /proc /mnt/target/proc
sudo mount --bind /sys /mnt/target/sys
sudo mount --bind /dev /mnt/target/dev

# 切换到目标系统
sudo chroot /mnt/target /bin/bash << "EOF"
# 更新 initramfs(根据发行版选择命令)
update-initramfs -c -k all
# 或
mkinitcpio -P
# 或
dracut --force
EOF

6. 安装和配置引导加载程序

6.1 安装 GRUB(传统 BIOS)

# 安装到磁盘的 MBR
sudo grub-install --boot-directory=/mnt/target/boot --target=i386-pc "$TARGET_DISK"

6.2 安装 GRUB(UEFI)

# 挂载 EFI 分区后安装
sudo chroot /mnt/target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=LINUX
sudo chroot /mnt/target update-grub

6.3 生成 GRUB 配置

# 在 chroot 中生成配置
sudo chroot /mnt/target update-grub
# 或手动创建
sudo tee /mnt/target/boot/grub/grub.cfg << 'EOF'
set timeout=5
menuentry "Live System Install" {
    linux /boot/vmlinuz root=UUID=${ROOT_UUID} ro quiet splash
    initrd /boot/initrd.img
}
EOF

7. 清理和收尾工作

7.1 清理 Live 系统特定配置

# 删除 Live 特定服务
sudo chroot /mnt/target bash -c "systemctl disable casper-md5check || true"

# 清理网络配置(让 NetworkManager/DHCP 重新获取)
sudo rm -f /mnt/target/etc/resolv.conf
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /mnt/target/etc/resolv.conf

7.2 创建新用户(可选)

# 在 chroot 中创建用户
sudo chroot /mnt/target useradd -m -G sudo -s /bin/bash newuser
sudo chroot /mnt/target passwd newuser

7.3 清理和卸载

# 卸载绑定的文件系统
sudo umount /mnt/target/dev
sudo umount /mnt/target/sys
sudo umount /mnt/target/proc

# 卸载目标分区
sudo umount /mnt/target/boot/efi 2>/dev/null
sudo umount /mnt/target

8. 特殊发行版注意事项

Ubuntu/Debian Live

# 需要确保 casper 不会在启动时查找 CD
sudo chroot /mnt/target apt-get remove --purge ubiquity casper -y
sudo chroot /mnt/target apt-get install --reinstall linux-generic

Fedora Live

# 使用 dracut 重新生成 initramfs
sudo chroot /mnt/target dracut --force --regenerate-all

Arch Linux Live

# 重新安装内核和引导
sudo chroot /mnt/target pacman -Syu linux linux-firmware grub
sudo chroot /mnt/target grub-mkconfig -o /boot/grub/grub.cfg

9. 验证安装

9.1 使用虚拟机测试

# 使用 QEMU 测试
qemu-system-x86_64 -drive file="$TARGET_DISK",format=raw -m 2048

9.2 物理启动测试

# 重启并从目标磁盘启动
sudo reboot

10. 故障排除

常见问题

  1. 启动时卡住

    • 检查内核参数中的 root=UUID 是否正确
    • 验证 initramfs 是否包含必要的驱动程序
  2. 无法挂载根文件系统

    # 在 GRUB 启动时按 e 编辑,添加:
    root=/dev/sda2  # 或实际分区
    break=init
  3. 缺少驱动

    # 在 chroot 中安装额外内核模块
    sudo chroot /mnt/target apt-get install linux-modules-extra-$(uname -r)

11. 自动化脚本示例

#!/bin/bash
# auto-install-live.sh
set -e

ISO="$1"
TARGET_DISK="$2"

if [ $# -ne 2 ]; then
    echo "Usage: $0 <live-iso> <target-disk>"
    exit 1
fi

# 挂载 ISO
mkdir -p /mnt/iso
mount -o loop "$ISO" /mnt/iso

# 创建分区
parted "$TARGET_DISK" mklabel gpt
parted "$TARGET_DISK" mkpart primary 1MiB 513MiB
parted "$TARGET_DISK" set 1 esp on
parted "$TARGET_DISK" mkpart primary 513MiB 100%

# 格式化
mkfs.fat -F32 "${TARGET_DISK}1"
mkfs.ext4 "${TARGET_DISK}2"

# 挂载
mount "${TARGET_DISK}2" /mnt/target
mkdir -p /mnt/target/boot/efi
mount "${TARGET_DISK}1" /mnt/target/boot/efi

# 提取系统
unsquashfs -f -d /mnt/target /mnt/iso/casper/filesystem.squashfs

# 安装引导
chroot /mnt/target grub-install --target=x86_64-efi --efi-directory=/boot/efi
chroot /mnt/target update-grub

# 清理
umount -R /mnt/target
umount /mnt/iso

echo "安装完成!"

注意事项

  1. 数据安全:此过程会完全擦除目标磁盘,确保已备份重要数据
  2. 硬件兼容性:Live ISO 可能缺少专有驱动,可能需要额外安装
  3. 系统更新:安装后立即运行系统更新
  4. 许可证:确保遵守发行版的许可证条款
  5. UEFI/传统 BIOS:选择正确的引导安装方式

整个过程将 Live 系统的临时性 squashfs 转换为完整的、可独立启动的常规 Linux 安装。

QEMU 虚拟机测试

绝对不建议直接使用 /dev/sda, 绝对不建议这样做!这会损坏你的系统!

技术原因:

  • 当前Linux系统正在使用/dev/sda进行读写
  • QEMU试图获得对同一物理磁盘的独占访问
  • 这就像两个人同时修改同一份文档,结果必然混乱

安全的测试另一个启动分区, 可以,但有严格的限制和风险! 这比使用当前系统盘安全,但仍需谨慎。

可以安全测试的非系统分区场景

场景1:独立的测试/备用启动分区

假设你的磁盘布局:

/dev/sda1  # 当前Linux系统(正在使用)
/dev/sda2  # 另一个Linux安装(未使用)
/dev/sda3  # 数据分区

你可以相对安全地测试 /dev/sda2

场景2:USB/外部磁盘

# USB磁盘通常是安全的
qemu-system-x86_64 -drive file=/dev/sdb,format=raw -m 2048

安全测试的步骤

步骤1:确认分区未被使用

# 检查哪些分区被挂载
mount | grep sda
#
lsblk

步骤2:确保完全卸载

# 如果目标分区被挂载,先卸载
sudo umount /dev/sda2

步骤3:以只读模式启动(最安全)

# 添加 readonly=on
qemu-system-x86_64 -drive file=/dev/sda2,format=raw,readonly=on -m 2048

完整的安全检查脚本

#!/bin/bash
TARGET_PARTITION="/dev/sda2"

# 1. 检查是否是分区而非整个磁盘
if [[ ! $TARGET_PARTITION =~ ^/dev/[a-z]+[0-9]+$ ]]; then
    echo "错误:请指定分区(如/dev/sda2),不是整个磁盘!"
    exit 1
fi

# 2. 检查是否被挂载
if mount | grep -q "^$TARGET_PARTITION "; then
    echo "错误:分区 $TARGET_PARTITION 已被挂载!"
    echo "先卸载:sudo umount $TARGET_PARTITION"
    exit 1
fi

# 3. 检查当前系统是否在该磁盘上
CURRENT_ROOT=$(findmnt -n -o SOURCE /)
CURRENT_DISK=${CURRENT_ROOT%p[0-9]*}  # 去掉分区号
TARGET_DISK=${TARGET_PARTITION%[0-9]*}  # 去掉分区号

if [ "$CURRENT_DISK" = "$TARGET_DISK" ]; then
    echo "警告:目标分区与当前系统在同一物理磁盘!"
    read -p "继续?(y/N): " confirm
    if [ "$confirm" != "y" ]; then
        exit 1
    fi
fi

# 4. 启动测试
echo "以只读模式启动测试..."
qemu-system-x86_64 \
    -drive "file=$TARGET_PARTITION,format=raw,readonly=on" \
    -m 2048 \
    -snapshot  # 重要:使用快照模式

关键安全参数

1. readonly=on

-drive "file=/dev/sda2,format=raw,readonly=on"

防止QEMU写入分区,保护数据。

2. -snapshot 参数

qemu-system-x86_64 -drive file=/dev/sda2,format=raw -snapshot -m 2048
  • 所有写入都存储在临时文件
  • 退出QEMU时丢弃所有更改
  • 原始磁盘保持不变

3. 使用缓存模式

-drive "file=/dev/sda2,format=raw,cache=none"

避免缓存问题,立即看到磁盘状态。

完整的安全命令示例

# 最安全的测试命令
qemu-system-x86_64 \
    -drive "file=/dev/sda2,format=raw,readonly=on" \
    -snapshot \
    -m 2048 \
    -vga std \
    -display sdl

更好的方法:使用磁盘映像

即使分区未被使用,创建映像仍是最佳实践:

# 1. 创建分区映像
sudo dd if=/dev/sda2 of=test_partition.img bs=4M status=progress

# 2. 测试映像
qemu-system-x86_64 -drive file=test_partition.img,format=raw -m 2048

# 3. 测试多个分区
# 将多个分区合并为一个虚拟磁盘
cat /dev/sda1 /dev/sda2 > full_disk_test.img
qemu-system-x86_64 -drive file=full_disk_test.img,format=raw -m 2048

特殊用例:MBR/EFI系统分区测试

如果你想测试引导加载程序:

# 1. 创建包含MBR+分区的完整磁盘映像
# 备份前1MB(包含MBR和分区表)
sudo dd if=/dev/sda of=disk_mbr.img bs=512 count=2048
# 添加目标分区
sudo dd if=/dev/sda2 bs=4M >> disk_mbr.img

# 2. 测试引导
qemu-system-x86_64 -drive file=disk_mbr.img,format=raw -m 2048

风险矩阵

场景 风险等级 建议
同一磁盘的不同分区 ⚠️ 中等 使用readonly=on-snapshot
不同物理磁盘 ✅ 低 可以更自由地测试
外部/USB磁盘 ✅ 低 安全
包含当前系统的磁盘 🔴 高 绝对避免

推荐的测试流程

# 1. 识别目标分区
lsblk -f

# 2. 确保卸载
sudo umount /dev/sda2 2>/dev/null

# 3. 创建测试环境
TEST_DIR=$(mktemp -d)
cd $TEST_DIR

# 4. 创建映像(最安全)
sudo dd if=/dev/sda2 of=test.img bs=4M
sudo chown $USER:$USER test.img

# 5. 测试
qemu-system-x86_64 \
    -drive file=test.img,format=raw \
    -m 2048 \
    -accel kvm \
    -vga virtio \
    -display gtk

# 6. 清理
cd /
rm -rf $TEST_DIR

总结

可以,但需要满足:

  1. 目标分区未被挂载
  2. 添加readonly=on-snapshot参数
  3. 避免写入当前系统所在磁盘

最佳实践仍然是创建磁盘映像:

# 这是最安全的方法
sudo dd if=/dev/sda2 of=test_boot.img
qemu-system-x86_64 -drive file=test_boot.img,format=raw -m 2048

如果你坚持使用原始分区,至少添加:

qemu-system-x86_64 -drive file=/dev/sda2,format=raw,readonly=on -snapshot -m 2048

记住:数据无价,测试虚拟机时应始终优先考虑隔离性和安全性!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment