Chroot

Материал из ALT Linux Wiki

Чрут (команда chroot, от англ. change root) - это временная смена корня. Может выполняться с разными целями. Например, загружаемся с ALT Rescue флэшки и чиним поломанную систему, для чего монтируем корень поломанной системы и делаем в него чрут. Все нижеописанные действия требуют полномочий root.

Подготовка к переходу в целевую систему

mkdir /mnt/target
mount /dev/sda2 /mnt/target
cp -Lf /etc/resolv.conf /mnt/target/etc/
mount --bind /dev /mnt/target/dev

Предполагается, что корень целевой системы находится во втором разделе первого диска (/dev/sda2). Перед тем, как сменить корень, мы уже подняли сеть. Но, чтобы в чруте работало преобразование имён в IP-адреса, мы скопировали текущий /etc/resolv.conf, например, на случай, если будем ставить пакеты из сети. Также мы сделали bind-mount ВСЕХ устройств из исходной системы. Все необходимые устройства должны быть в будущем /dev. bind-mount решает эту задачу одной командой, потому что, как правило, в исходной системе все имеющиеся устройства уже доступны через devtmpfs в /dev. Однако, если мы не доверяем этому чруту, не хотим, чтобы из него можно было оказать негативное воздействие на исходную систему, из которой мы заходим в этот чрут, то делать bind-mount напротив, не следует. Достаточно вручную определить в /mnt/target/dev только необходимые ноды устройств (man mknod).

Переход в целевую систему

PS1="(CHROOT) $PS1" chroot /mnt/target /bin/bash

В простом случае так. PS1 рекомендуется менять, чтобы визуально отличать приглашение в чруте от приглашений в других терминалах. Вместо /bin/bash можно указать свою любимую оболочку. Предлагаемый выше вызов как бы перенесёт вас в целевую систему, в точку, когда система с ядром и initrd уже отработали, когда загрузились все службы, когда было дано дано приглашение войти в систему, разве что без ввода логина и пароля. На самом деле ничего этого конечно не было, просто при запуске процесс /bin/bash получил в качестве "корневой" директорию /mnt/target. Ни /bin/bash, ни что-либо из него запущенное не смогут увидеть директории выше уровнем, им доступно только содержимое /mnt/target, которое они видят как "/". Но есть ещё один существенный нюанс. Команда выше передаёт все переменные окружения из исходной системы, а это далеко не всегда желательно. Более длинный, но более безопасный вариант запуска мог бы выглядеть следующим образом:

chroot /mnt/target /usr/bin/env -i PS1="(CHROOT) $PS1" LANG=C \
    PATH="$PATH" HOME="/root" USER="root" TERM="linux" LC_ALL=C /bin/bash

Здесь мы очищаем ВСЕ переменные среды для новой оболочки и устанавливаем всего несколько переменных, передавая им определённые значения. Такой подход позволит избежать всевозможных side-эффектов при дальнейшей работе в чруте. Другой нюанс заключается в том, что с высокой вероятностью мы загрузились с ДРУГОЙ версией ядра, возможно даже из другого дистрибутива GNU/Linux. Команды типа uname -r, uanme -a покажут всё верно, то бишь информацию о реально загруженном ядре, на которую ориентируются такие скрипты, как make-initrd. По умолчанию они просто выругаются, не найдя такого ядра в вашем чруте, поэтому их нужно запускать иначе:

make-initrd -f <ваше-ядро-в-чруте>

Первым делом в целевой системе

mount /proc
mount /dev/pts
mount -t sysfs none /sys

Отнюдь не всё это может потребоваться. Если какая-то программа ругается, что ей нужен sysfs, например, lspci без него работать не станет, можно смонтировать и потом, по мере необходимости. Если хотите понять, почему первые две команды выше имеют сокращённую форму, а третья команда - полную форму, загляните в /etc/fstab. Что характерно для ALT Linux, может быть совершенно иначе в других дистрибутивах. Не забывайте об этом, чрутясь куда-то ни туда. :)

Другой нюанс при работе в чруте связан с hostname. Если хотите его переустановить перед работой с некоторыми утилитами, сделайте это так:

hostname <нужное_имя_хоста>
/bin/bash

То есть повторно запустите /bin/bash в чруте после смены имени хоста. Если хост показывался в приглашении, то теперь он будет правильный. И не забудьте, что выходить из чрута придётся двойным "exit"!

Выход из чрута

(CHROOT) $PS1# umount /sys || umount -l /sys
(CHROOT) $PS1# umount /dev/pts || umount -l /dev/pts
(CHROOT) $PS1# umount /proc || umount -l /proc
(CHROOT) $PS1# exit
$PS1# umount /mnt/target/dev || umount -l /mnt/target/dev
$PS1# umount /mnt/target || umount -l /mnt/target
$PS1# rmdir /mnt/target

Не забываем отмонтировать всё, что было смонтировано ранее. Обращаем внимание на синтаксис.