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

Материал из ALT Linux Wiki
мНет описания правки
 
(не показано 20 промежуточных версий 2 участников)
Строка 8: Строка 8:
cp -Lf /etc/resolv.conf /mnt/target/etc/
cp -Lf /etc/resolv.conf /mnt/target/etc/
mount --bind /dev /mnt/target/dev
mount --bind /dev /mnt/target/dev
hostname <целевой_хост>
</source>
</source>


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


=== Переход в целевую систему ===
=== Переход в целевую систему ===
Строка 18: Строка 23:
</source>
</source>


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


<source lang="text">
<source lang="text">
Строка 25: Строка 30:
</source>
</source>


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


<source lang="text">
<source lang="text">
make-initrd -f <ваше-ядро-в-чруте>
make-initrd -k <ваше-ядро-в-чруте>
</source>
</source>


=== Первым делом в целевой системе ===
=== Первым делом в целевой системе ===
Первая и наиболее предпочтительная форма подключения '''/proc''', '''/sys''' и '''/dev/pts'''. ''Про другие варианты говорится далее...''


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


Другой нюанс при работе в чруте связан с '''hostname'''. Если хотите его переустановить перед работой с некоторыми утилитами, сделайте это так:
=== Выход из целевой системы ===
 
<source lang="text">
hostname <нужное_имя_хоста>
/bin/bash
</source>
 
То есть повторно запустите '''/bin/bash''' в чруте после смены имени хоста. Если хост показывался в приглашении, то теперь он будет правильный. И не забудьте, что выходить из чрута придётся двойным "'''exit'''"!
 
=== Выход из чрута ===


<source lang="text" highlight="4">
<source lang="text" highlight="4">
Строка 57: Строка 55:
(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
Строка 66: Строка 65:
=== Чрут в экзотическую систему ===
=== Чрут в экзотическую систему ===


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


<source lang="text">
<source lang="text">
mount --bind /proc /mnt/target/proc
mount -t proc none /mnt/target/proc
mount --bind /sys /mnt/target/sys
mount -t sysfs none /mnt/target/sys
mount --bind /dev/pts /mnt/target/dev/pts
mount -t devpts none /mnt/target/dev/pts
</source>
</source>


Строка 77: Строка 76:


<source lang="text">
<source lang="text">
mount -t proc none /mnt/target/proc
mount --bind /proc /mnt/target/proc
mount -t sysfs none /mnt/target/sys
mount --bind /sys /mnt/target/sys
mount -t devpts none /mnt/target/dev/pts
mount --bind /dev/pts /mnt/target/dev/pts
</source>
</source>
Хотя последняя форма наиболее универсальная, есть целый ряд причин, по которым предпочтительно монтировать эти три файловые системы только по мере необходимости, и только изнутри самого чрута.


Кроме того, возможен чрут из '''64-бит''' исходной системы в '''32-бит''' целевую систему. В '''ALT Linux''' для этих целей используется '''setarch'''.
Кроме того, возможен чрут из '''64-бит''' исходной системы в '''32-бит''' целевую систему. В '''ALT Linux''' для этих целей используется '''setarch'''.
Строка 89: Строка 90:
</source>
</source>


При отсутствии '''/usr/bin/env''' в целевой системе, что также не характерно для '''ALT Linux''', достаточно поменять аргументы местами, например:
<source lang="text">
/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
</source>
=== А можно ли попроще? ===
Да, можно. Так как мы используем [[Rescue|ALT Rescue]], то сразу после загрузки нам доступен скрипт mount-system (о чём будет подсказка). Делаем так:
mount-system
chroot /mnt/system1
Если что-то пошло не так, то переходим к началу статьи.
И чтобы отмонтировать:
unmount-system
'''Enjoy!''' ;-)
{{Category navigation|title=Восстановление|category=Rescue|sortkey={{SUBPAGENAME}}}}
[[Категория:HOWTO]]
[[Категория:HOWTO]]

Текущая версия от 06:40, 4 апреля 2023

Чрут (команда 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 -k <ваше-ядро-в-чруте>

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

Первая и наиболее предпочтительная форма подключения /proc, /sys и /dev/pts. Про другие варианты говорится далее...

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

А можно ли попроще?

Да, можно. Так как мы используем ALT Rescue, то сразу после загрузки нам доступен скрипт mount-system (о чём будет подсказка). Делаем так:

mount-system
chroot /mnt/system1

Если что-то пошло не так, то переходим к началу статьи.

И чтобы отмонтировать:

unmount-system

Enjoy! ;-)