chroot

出自 ArchWiki

chroot 是一种操作,它更改当前运行进程及其子进程的表观根目录。在这种修改后的环境中运行的程序无法访问该环境目录树之外的文件和命令。这种修改后的环境称为 chroot 监狱

原理

更改根目录通常用于对无法启动和/或登录的系统执行系统维护。常见的例子有

另请参见 Wikipedia:Chroot#局限性

要求

为了使用 chroot,您需要另一个 Linux 安装或安装介质(任何发行版),具有

  • Root 权限(有关替代方案,请参阅#无需 root 权限)。
  • 与要 chroot 进入的系统相同的指令集架构。可以使用 uname -m (例如 i686 或 x86_64)发现当前环境的架构。也可以使用 QEMU 来执行不具有匹配原生架构的代码。
  • chroot 环境中需要的内核模块已加载。
  • 如果需要,启用交换分区
    # swapon /dev/sdxY
  • 如果需要,已建立互联网连接。

准备新的根位置

chroot 目标应该是一个包含文件系统层次结构的目录。

安装指南中,此目录将是 /mnt。对于现有安装,您需要自己将现有分区挂载到 /mnt

运行 lsblk 并记下您的安装的分区布局。它通常类似于 /dev/sdXY,如果您有 NVMe 驱动器,则类似于 /dev/nvme0nXpY

挂载文件系统

# mount /dev/sdXY /mnt

如果您有 EFI 系统分区 并且需要在其中进行更改(例如,更新 vmlinuzinitramfs 镜像)

# mount /dev/sdXZ /mnt/esp

如果您有任何独立分区,也请挂载它们。

在以下示例中,/path/to/new/root 是新根目录所在的目录(例如 /mnt)。

用法

注意
  • 某些 systemd 工具(如 hostnamectllocalectltimedatectl)无法在 chroot 内部使用,因为它们需要活动的 dbus 连接。[1]
  • 将用作 chroot 新根目录(/)的文件系统必须是可访问的(即,已解密,已挂载)。

使用 chroot 主要有两种选择,如下所述。

使用 arch-chroot

bash 脚本 arch-chroot(8)arch-install-scripts 软件包的一部分。arch-chroot 包装了 chroot(1) 命令,同时确保重要功能可用,例如挂载 /dev/proc 和其他 API 文件系统,或将 /etc/resolv.conf 暴露给 chroot

进入 chroot

使用新根目录作为第一个参数运行 arch-chroot

# arch-chroot /path/to/new/root

您现在可以执行现有安装中的大多数操作。某些需要 D-Bus 的任务将无法工作,如#用法中所述。

退出 chroot

要退出 chroot,请使用

# exit

运行单个命令并退出

要从 chroot 运行命令并再次退出,请将命令附加到行尾

# arch-chroot /path/to/new/root mycommand

例如,要为位于 /mnt/archchroot 运行 mkinitcpio -p linux,请执行

# arch-chroot /mnt/arch mkinitcpio -p linux

在 Btrfs 上运行

在具有子卷的 Btrfs 根文件系统上,您必须确保在进入 chroot 之前,所有子卷都已按照 fstab 中的指定正确挂载。

来自 archinstall 的 Btrfs 默认设置示例

# mount -o subvol=@ /dev/sdXY /mnt
# mount -o subvol=@home /dev/sdXY /mnt/home
# mount -o subvol=@pkg /dev/sdXY /mnt/var/cache/pacman/pkg
# mount -o subvol=@log /dev/sdXY /mnt/var/log
# mount -o subvol=@snapshots /dev/sdXY /mnt/.snapshots
# mount /dev/sdXZ /mnt/boot
# arch-chroot /mnt
提示: 您可能还想指定其他挂载选项,例如 压缩

使用 chroot

如果您直接运行 chroot,则在实际 chroot 之前需要执行以下步骤。

首先,挂载临时 API 文件系统

# cd /path/to/new/root
# mount -t proc /proc proc/
# mount -t sysfs /sys sys/
# mount --rbind /dev dev/
警告: 当使用 --rbind 时,dev/sys/ 的某些子目录将无法卸载。在这种情况下尝试使用 umount -l 卸载将会破坏您的会话,需要重新启动。如果可能,请改用 -o bind

以及可选的

# mount --rbind /run run/

如果您正在运行 UEFI 系统,您还需要访问 EFI 变量。否则,在安装 GRUB 时,您将收到类似于以下消息: UEFI variables not supported on this machine

# mount --rbind /sys/firmware/efi/efivars sys/firmware/efi/efivars/

接下来,为了在 chroot 环境中使用互联网连接,复制 DNS 详细信息

# cp /etc/resolv.conf etc/resolv.conf

最后,使用 bash shell 将根目录更改为 /path/to/new/root

# chroot /path/to/new/root /bin/bash
注意: 如果您看到错误
  • chroot: cannot run command '/usr/bin/bash': Exec format error,则可能是主机环境和 chroot 环境的架构不匹配。
  • chroot: '/usr/bin/bash': permission denied,使用执行权限重新挂载:mount -o remount,exec /path/to/new/root
    • 如果检查这没有帮助,那么确保新环境的基本组件完好无损(如果它是 Arch 根目录,请尝试 paccheck --root=/path/to/new/root --files --file-properties --md5sum glibc filesystem,来自 pacutils

chroot 后,可能需要加载本地 Bash 配置

# source /etc/profile
# source ~/.bashrc
提示: 可选地,创建一个唯一的提示符,以便能够区分您的 chroot 环境
# export PS1="(chroot) $PS1"

完成 chroot 后,您可以通过以下方式退出

# exit

然后卸载临时文件系统

# cd /
# umount --recursive /path/to/new/root
注意: 如果出现错误,提示类似于 umount: /path: device is busy,这通常意味着:程序(甚至是 shell)仍在 chroot 中运行,或者仍然存在子挂载。退出程序并使用 findmnt -R /path/to/new/root 查找,然后 umount 子挂载。卸载某些东西可能很棘手,并且可以尝试使用 umount --force。作为最后的手段,使用 umount --lazy 只是释放它们。在任何情况下,为了安全起见,如果这些问题未解决,请尽快 reboot 以避免将来可能发生的冲突。

从 chroot 运行图形化应用程序

如果您的系统上运行着 X server,您可以从 chroot 环境启动图形化应用程序。

为了允许 chroot 环境连接到 X server,请在 X server 内打开一个虚拟终端(即在当前登录用户的桌面内),然后运行 xhost 命令,该命令授予任何人连接到用户 X server 的权限(另请参阅 Xhost

$ xhost +local:

然后,要将应用程序定向到来自 chroot 的 X server,请在 chroot 内设置 DISPLAY 环境变量以匹配拥有 X server 的用户的 DISPLAY 变量。因此,例如,运行

$ echo $DISPLAY

作为拥有 X server 的用户,以查看 DISPLAY 的值。如果该值为“:0”(例如),则在 chroot 环境中运行以下命令

# export DISPLAY=:0

无需 root 权限

Chroot 需要 root 权限,这在某些情况下可能不希望或不可能由用户获得。但是,有各种方法可以使用替代实现来模拟类似 chroot 的行为。

PRoot

PRoot 可用于更改表观根目录并使用 mount --bind 而无需 root 权限。这对于将应用程序限制在单个目录或运行为不同 CPU 架构构建的程序很有用,但由于所有文件都由主机系统上的用户拥有,因此它具有局限性。PRoot 提供了一个 --root-id 参数,该参数可以用作类似于 fakeroot 的方式(尽管功能更有限)来解决其中一些限制的变通方法。

Fakechroot

fakechroot 是一个库 shim,它拦截 chroot 调用并伪造结果。它可以与 fakeroot 结合使用,以模拟作为普通用户的 chroot

$ fakechroot fakeroot chroot ~/my-chroot bash

Unshare

unshare(1)util-linux 的一部分,可用于创建新的内核命名空间。这适用于常用的 chroot 命令。例如

$ unshare --map-root-user chroot ~/namespace /bin/sh

技巧与诀窍

chroot 检测

systemd-detect-virt --chroot 检测是否在 chroot 环境中调用。有关检测其他虚拟化环境的信息,请参阅 systemd-detect-virt(1)。有关更广泛的讨论以及传统工具的用法,请参阅 how-do-i-tell-im-running-in-a-chroot

故障排除

arch-chroot: /path/to/new/root 不是挂载点。这可能会产生不良的副作用。

在执行 arch-chroot /path/to/new/root 时,会发出警告

==> WARNING: /path/to/new/root is not a mountpoint. This may have undesirable side effects.

有关解释和使用绑定挂载使 chroot 目录成为挂载点的示例,请参阅 arch-chroot(8)

参见