Chroot: различия между версиями

Материал из ALT Linux Wiki
Строка 53: Строка 53:
(CHROOT) $PS1# umount /proc || umount -l /proc
(CHROOT) $PS1# umount /proc || umount -l /proc
(CHROOT) $PS1# exit
(CHROOT) $PS1# exit
hostname <исходный_хост>
$PS1# umount /mnt/target/dev || umount -l /mnt/target/dev
$PS1# umount /mnt/target/dev || umount -l /mnt/target/dev
$PS1# umount /mnt/target || umount -l /mnt/target
$PS1# umount /mnt/target || umount -l /mnt/target

Версия от 03:55, 31 марта 2018

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

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

mkdir /mnt/target
mount /dev/sda2 /mnt/target
cp -Lf /etc/resolv.conf /mnt/target/etc/
mount --bind /dev /mnt/target/dev
hostname <целевой_хост>

Предполагается, что корень целевой системы находится во втором разделе первого диска (/dev/sda2). Перед тем, как сменить корень, мы уже подняли сеть. Но, чтобы в чруте работало преобразование имён в IP-адреса (и обратно), мы скопировали текущий /etc/resolv.conf, например, на случай, если будем ставить пакеты из сети.

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

Последней командой мы переустановили hostname. Если имя хоста выводится в приглашении, то во время работы в чруте имя будет ожидаемым. Также это необходимо для работы с некоторыми утилитами, привязывающимися к имени хоста, например, mdadm. Не забывайте вернуть оригинальный hostname по возвращении в исходную систему!

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

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, может быть совершенно иначе в других дистрибутивах. Не забывайте об этом, чрутясь куда-то не туда. :)

Выход из целевой системы

(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
hostname <исходный_хост>
$PS1# umount /mnt/target/dev || umount -l /mnt/target/dev
$PS1# umount /mnt/target || umount -l /mnt/target
$PS1# rmdir /mnt/target

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

Чрут в экзотическую систему

В случае, если в целевой системе отсутствует команда mount, что совсем не характерно для ALT Linux, смонтировать в ней /proc, /sys и /dev/pts не получится. Тогда придётся сделать это заранее до перехода в экзотический чрут.

mount -t proc none /mnt/target/proc
mount -t sysfs none /mnt/target/sys
mount -t devpts none /mnt/target/dev/pts

либо так:

mount --bind /proc /mnt/target/proc
mount --bind /sys /mnt/target/sys
mount --bind /dev/pts /mnt/target/dev/pts

Хотя последняя форма наиболее универсальная, есть целый ряд причин, по которым предпочтительно монтировать эти три файловые системы только по мере необходимости, и только изнутри самого чрута.

Кроме того, возможен чрут из 64-бит исходной системы в 32-бит целевую систему. В ALT Linux для этих целей используется setarch.

setarch i586 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

При отсутствии /usr/bin/env в целевой системе, что также не характерно для ALT Linux, достаточно поменять аргументы местами, например:

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

Enjoy! ;-)