以下是将 Live ISO 中的 squashfs 文件系统提取并部署为可独立启动的常规 Linux 系统的完整步骤:
# 在现有 Linux 系统中操作(Live USB 或已安装系统)
sudo apt-get update
sudo apt-get install -y squashfs-tools grub-pc grub-efi-amd64
# 或对应发行版的等价包# 查看可用磁盘
lsblk
sudo fdisk -l
# 假设目标磁盘为 /dev/sda
TARGET_DISK="/dev/sda"
BOOT_PART="${TARGET_DISK}1" # EFI 分区 (建议 500MB-1GB)
ROOT_PART="${TARGET_DISK}2" # 根分区
# 或使用单个分区方案# 如果是从 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"# 常见位置
SQUASHFS_PATH="/mnt/iso/casper/filesystem.squashfs"
# 或
SQUASHFS_PATH="/run/live/medium/casper/filesystem.squashfs"
# 也可能是 /live/filesystem.squashfs
# 验证文件存在
ls -lh "$SQUASHFS_PATH"# 使用 fdisk 或 parted 创建分区
sudo fdisk "$TARGET_DISK"
# 创建 GPT 分区表(UEFI)或 MBR(传统 BIOS)
# 创建必要分区# 假设根分区为 /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"# 创建挂载点
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# 使用 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# 某些 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# 在目标系统中创建缺失的标准目录
sudo mkdir -p /mnt/target/{proc,sys,dev,run,tmp}# 获取分区 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# 使用 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# 安装到磁盘的 MBR
sudo grub-install --boot-directory=/mnt/target/boot --target=i386-pc "$TARGET_DISK"# 挂载 EFI 分区后安装
sudo chroot /mnt/target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=LINUX
sudo chroot /mnt/target update-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# 删除 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# 在 chroot 中创建用户
sudo chroot /mnt/target useradd -m -G sudo -s /bin/bash newuser
sudo chroot /mnt/target passwd newuser# 卸载绑定的文件系统
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# 需要确保 casper 不会在启动时查找 CD
sudo chroot /mnt/target apt-get remove --purge ubiquity casper -y
sudo chroot /mnt/target apt-get install --reinstall linux-generic# 使用 dracut 重新生成 initramfs
sudo chroot /mnt/target dracut --force --regenerate-all# 重新安装内核和引导
sudo chroot /mnt/target pacman -Syu linux linux-firmware grub
sudo chroot /mnt/target grub-mkconfig -o /boot/grub/grub.cfg# 使用 QEMU 测试
qemu-system-x86_64 -drive file="$TARGET_DISK",format=raw -m 2048# 重启并从目标磁盘启动
sudo reboot-
启动时卡住
- 检查内核参数中的 root=UUID 是否正确
- 验证 initramfs 是否包含必要的驱动程序
-
无法挂载根文件系统
# 在 GRUB 启动时按 e 编辑,添加: root=/dev/sda2 # 或实际分区 break=init
-
缺少驱动
# 在 chroot 中安装额外内核模块 sudo chroot /mnt/target apt-get install linux-modules-extra-$(uname -r)
#!/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 "安装完成!"- 数据安全:此过程会完全擦除目标磁盘,确保已备份重要数据
- 硬件兼容性:Live ISO 可能缺少专有驱动,可能需要额外安装
- 系统更新:安装后立即运行系统更新
- 许可证:确保遵守发行版的许可证条款
- UEFI/传统 BIOS:选择正确的引导安装方式
整个过程将 Live 系统的临时性 squashfs 转换为完整的、可独立启动的常规 Linux 安装。
绝对不建议直接使用 /dev/sda, 绝对不建议这样做!这会损坏你的系统!
技术原因:
- 当前Linux系统正在使用/dev/sda进行读写
- QEMU试图获得对同一物理磁盘的独占访问
- 这就像两个人同时修改同一份文档,结果必然混乱
安全的测试另一个启动分区, 可以,但有严格的限制和风险! 这比使用当前系统盘安全,但仍需谨慎。
假设你的磁盘布局:
/dev/sda1 # 当前Linux系统(正在使用)
/dev/sda2 # 另一个Linux安装(未使用)
/dev/sda3 # 数据分区
你可以相对安全地测试 /dev/sda2。
# USB磁盘通常是安全的
qemu-system-x86_64 -drive file=/dev/sdb,format=raw -m 2048# 检查哪些分区被挂载
mount | grep sda
# 或
lsblk# 如果目标分区被挂载,先卸载
sudo umount /dev/sda2# 添加 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 # 重要:使用快照模式-drive "file=/dev/sda2,format=raw,readonly=on"防止QEMU写入分区,保护数据。
qemu-system-x86_64 -drive file=/dev/sda2,format=raw -snapshot -m 2048- 所有写入都存储在临时文件
- 退出QEMU时丢弃所有更改
- 原始磁盘保持不变
-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如果你想测试引导加载程序:
# 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可以,但需要满足:
- 目标分区未被挂载
- 添加
readonly=on或-snapshot参数 - 避免写入当前系统所在磁盘
最佳实践仍然是创建磁盘映像:
# 这是最安全的方法
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记住:数据无价,测试虚拟机时应始终优先考虑隔离性和安全性!