Пару дней назад уже была статья на тему: как улучшить образ Raspberry Pi OS. Там я просто редактировал образ без выполнения команд «изнутри». Но, благодаря связке chroot и QEMU, можно пойти несколько дальше: эмулировать выполнение команд arm процессора, работая на процессоре amd64 (в принципе, архитектура хоста не столь важна, суть в том что она отличается), внутри образа операционной системы без запуска этой самой системы и целевого устройства.

Таким образом можно будет сделать много чего интересного, к примеру, скомпилировать пакет под Raspberry Pi OS. Я же установлю эмулятор терминала sakura, просто для демонстрации работоспособности.

Установка sakura в Raspberry Pi OS, используя QEMU + chroot.

Подготовка

qemu-arm-static

Для начала нам нужен статически (чтобы не зависеть от операционной системы хоста) слинкованный исполняемый файл эмулятора QEMU под архитектуру arm. Обычно этот файл называется qemu-arm-static. В Debian/Ubuntu есть пакет с ним и его можно легко установить:

# apt install qemu-user-static

Вполне вероятно, что и в вашем дистрибутиве есть что-то подобное. А вот в ArchLinux же исполняемые файлы QEMU слинкованы динамически и нужно ручками всё собирать из AUR.

Такой способ не универсальный. Для дистрибутивов, в которых нет статически слинкованных исполняемых файлов QEMU, можно поискать этот файл в сети. Так как он слинкован статически, то зависит разве что от версии ядра и можно вскрыть тот же пакет для Ubuntu под архитектуру хоста и получить бинарный файл. Я же нашёл такую ссылку для amd64, где можно скачать qemu-arm-static.

Затем можно поместить скаченный файл в /usr/bin:

# cp ~/Downloads/qemu-arm-static /usr/bin
# chmod +x /usr/bin/qemu-arm-static

Найдём по какому пути располагается qemu-arm-static в системе:

# find / -name qemu-arm-static 2>/dev/null
/usr/bin/qemu-arm-static

В дальнейшем я буду использовать этот путь.

binfmt_misc

Поддержка binfmt_misc должна быть включена в ядре. Оставлю это на ваш откуп, так как в ядре моего дистрибутива она уже была включена по-умолчанию:

# cat /proc/sys/fs/binfmt_misc/status
enabled

Добавим путь к нашему qemu-arm-static для обработки бинарных файлов под архитектуру arm:

echo ':qemu-arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:CF' > /proc/sys/fs/binfmt_misc/register

Если всё хорошо, то вывод выполнения следующих команд должен быть похож:

# ls /proc/sys/fs/binfmt_misc/
DOSWin	qemu-arm  register  status
# cat /proc/sys/fs/binfmt_misc/qemu-arm 
enabled
interpreter /usr/bin/qemu-arm-static
flags: OCF
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00fffffffffffffffffeffffff

Если же где-то закралась ошибка, то всегда можно удалить ассоциацию (но на данном этапе делать этого не нужно):

# echo -1 > /proc/sys/fs/binfmt_misc/qemu-arm
# ls /proc/sys/fs/binfmt_misc/
DOSWin	register  status

Образ Raspberry Pi OS

Образ нужно скачать с официального сайта и разархивировать. Предположим, что в нашей рабочей директории уже есть образ операционной системы (для статьи нет разницы, full или lite версия ОС, поэтому он назван нейтрально):

# ls
raspios.img

В дальнейшем будет использовано это имя образа.

chroot в образ Raspberry Pi OS

Для начала создадим виртуальное устройство, которое было бы отображением образа операционной системы и найдём на нём разделы:

# losetup --show --find --partscan raspios.img
/dev/loop0

/dev/loop0 — это имя виртуального устройства, которое назначила ему операционная система. На нём должно быть два раздела:

$ ls /dev/loop0*
/dev/loop0  /dev/loop0p1  /dev/loop0p2
  1. /dev/loop0p1 — раздел с точкой монтирования /boot.
  2. /dev/loop0p2 — корень файловой системы, точка монтирования /.

Создадим точку монтирования для разделов и подключим их:

$ mkdir root
# mount -t ext4 /dev/loop0p2 root
# mount -t vfat /dev/loop0p1 root/boot

Теперь осталось примонтировать служебные папки файловой системы, чтобы операционная система не потерялась после chroot и была вполне работоспособна:

# mount --bind /dev root/dev/
# mount --bind /dev/pts root/dev/pts
# mount --bind /sys root/sys/
# mount --bind /proc root/proc/

Теперь можно сделать chroot в Raspberry Pi OS:

# chroot root

Всё, мы внутри, и можно изменять образ по-своему желанию. При этом, благодаря эмуляции, мы можем выполнять большинство команд. Конечно, есть ограничения, ведь сама по себе операционная система, а значит и systemd, и демоны не были запущены — что-то да не будет работать. Но у нас есть работоспособная сеть с операционной системы хоста, вкупе с эмуляцией этого хватит для удаления программ, их установки и компиляции.

Но почему-то глобальная переменная PATH выглядит странной и некоторые утилиты недоступны. Это легко исправить изменив её:

# export PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
Изменение PATH после chroot в Raspberry Pi OS

Решил для примера установить эмулятор терминала:

# apt update
# apt install sakura
# apt clean
# uname -a

Всё вполне работает, что и видно на первом изображении в посте.

Завершение изменений

Для выхода из chroot следует воспользоваться командой:

# exit

Можно удалить файл с историей команд bash’a, который был записан в сеансе:

# rm root/root/.bash_history

И какие-то другие временные файлы, созданные вами. Затем останется только отмонтировать все файловые системы в обратном порядке, удалить виртуальное устройство и сбросить дисковый кэш.

# umount root/proc/
# umount root/sys/
# umount root/dev/pts
# umount root/dev/
# umount root/boot/
# umount root/
# losetup -d /dev/loop0
# sync

Изменённый образ готов для записи на MicroSD карточку!

Заключение

Осталось за кадром пару нюансов:

  • На стандартном образе сравнительно небольшой объём свободного пространства. Ведь по задумке тот расширяется при первом запуске Raspberry Pi OS. Его можно увеличить.
  • Всё это можно и нужно автоматизировать.

Позже планирую их раскрыть.

Навигация по записям