From: geekkoo
Newsgroups: email
Date: Mon, 9 Nov 2008 17:02:14 +0000 (UTC)
Subject: LiveCD из Slackware в домашних условиях
Иногда появляется необходимость создать LiveCD из уже установленного
дистрибутива Linux. Причины могут быть разные - например, вам не хочется
разбираться с новым Live дистрибутивом и вы полагаете, что своя рубашка
ближе к телу. Также возможно, что создаваемый вами LiveCD имеет другое
ядро, существенно отличающееся от имеющихся, так что простой
модификацией тут не обойтись.
В данном тексте как раз и будет рассказано как из Salckware сделать
LiveCD. Непосредственной причиной послужила необходимость создания
router-а из PC. Понятно, что роутер - это такая вещь, которую один раз
поставил, и забыл ... До тех самых пор пока она (после очередного
пропадания электричества) не перестанет загружаться. Вот тогда все
начинают бегать...
Использование LiveCD (понятно, что с настройками сети и файрволла,
подогнанными под вашу систему) в этом случае хорошо тем, что любая
проблема с оборудованием решается простой заменой на любое другое с
необходимым числом сетевых интерфейсов и втыканием в него вашего LiveCD
диска. Кроме того для роутера read-only корневая система (типа iso9660)
- это к тому же лишний плюс, поскольку представляет из себя
дополнительную преграду для злоумышленников и любителей поиграться с
подменой шелла.
Минус же состоит в том, что CDROM - это далеко не жёсткий диск, у него
нет BIOS кода, поэтому подготовка загрузочного сидюка существенно
сложнее от создания загрузочного HD. Кроме того, не следует забывать,
что от этого LiveCD (в отличии от жёсткого диска, который как сидел на
одном компе, так и сидит) требуется ещё и универсальность - т.е. воткнул
его в любой комп (независимо от того на каком интерфейсе находится
CD-drive), и он завёлся.
Как вы знаете (наверное), проблему с отсутствием BIOS кода загружаемые
сидюки решают созданием эмуляции загрузочной дискеты, которая копируется
на сам CD. Для тех, кто забыл (или не застал): дискета - это такая
маленькая чёрная штучка, которая все время сыпалась и имела смешной
объём 1.4 MБ. Т.е. из этого следует невесёлый вывод, что вам нужно
втиснуть ядро, initrd (от создания initrd вам всё равно не отвертеться,
иначе потеряется упомянутая выше универсальность) и загрузчик на
дискету. Есть, правда, хорошая новость - этот объём можно удвоить (до
2.8 MБ) и в итоге современные дистрибутивы в него (пока ещё)
помещаются, хотя в талии уже начинает жать ...
Подготовка образа диска.
Итак, задача стоит таким образом. Нам нужно создать систему на CD (или
DVD) с корневой файловой системой на iso9660. Поскольку полностью
сделать read-only корневую систему нельзя, то /etc, /var и /tmp нам
придётся перенести на tmpfs (и при желании /home на nfs). В то же время
хочется сделать систему максимально самодостаточной, не зависящий ни от
каких дополнительных сетевых хранилищ информации, чтобы перенос на
другое железо мог быть выполнен любым неквалифицированным оператором
(даже в стиле ``телефонного робота'').
Для начала готовим ветку, которая будет использована в качестве корневой
файловой системы.
mkdir /tmp/cdrom
Затем в эту ветку копируется содержимое корневой файловой системы (cp -a
/dev /root /usr /lib ... /tmp/cdrom) или же система устанавливается
туда по-новой. Если критично важно, чтобы система влезала на CD, то
следует ограничиться установкой /a и /n пакетов. Напомню, что у
installpkg в Slackware есть флаг -root /tmp/cdrom, который как раз и
делает что нам нужно - устанавливает пакеты в каталог отличный от /.
Для установки ядра отличного от ванильного лучше распаковать исходники
ядра в отдельной директории (они занимают большой объем - на CD точно не
влезут), сконфигурировать как вам хочется и установить, используя
переменные окружения:
Таким образом после команд make install и make modules_install ядро и
модули окажутся в /tmp/cdrom/boot и /tmp/cdrom/lib/modules/...
соответственно.
Теперь правим конфигурационные файлы (/etc) в соответствии с вашими
задачами. После того как всё будет готово, продолжим ...
Раз всё готово, то можно проделать chroot в свежеустановленный каталог.
По крайней мере это одна из базовых проверок (необходимая, но не
достаточная!), что система работоспособна.
и сделать пустой файл /etc/fastboot, чтобы при загрузке не происходила
проверка файловой системы.
После этого копируем каталоги:
cp -a /etc /etc1
cp -a /var /var1
Смысл этого действия - /etc, /var будут использоваться как mount-points
для tmpfs, а после монтажа в них будет копироваться содержимое /etc1 и
/var1. Проблема состоит только в том, что все это нужно проделать до
запуска init. Вот для этого нам и понадобится initrd.
Создание initrd
Initrd - это маленькая файловая система, которая монтируется при
запуске ядра и чьей задачей обычно является подготовка монтажа настоящей
большой корневой системы. На эту файловую систему помещается набор
системных утилит (типа ls, mkfs и др.), обычно упакованных в один
исполняемый файл busybox, скрипты и ядерные модули, которые ядро должно
загрузить прежде, чем будет смонтирована корневая файловая система
(например, модуль для самой корневой файловой системы и драйвер
контроллера диска). Можно было бы пересобрать ядро, чтобы
вкомпилировать эти модули в ядро, но многие системные администраторы
считают, что не царское это дело - ядра компилировать (для этого
программисты есть), поэтому initrd как раз для них.
Каждый дистрибутив имеет свои средства для создания initrd. В Slackware
для этого используется bash-скрипт mkinitrd.
mkinitrd -m iso9660:tmpfs:...
(мы по-прежнему в chroot-e). Параметры - это те модули, которые будут
помещены на initrd. iso9660 - должен быть обязательно (если только он не
вкомпилен в ядро). Но особо увлекаться добавлением модулей не следует.
Помним, что busybox весит 1.4 МБ. После сжатия он ужимается до 0.7,
отнимаем это число от 2.8, получаем 2.0 МБ на ядро и модули. Т.е.
generic-ядро из Slackware-12.1 ещё влезет, а вот huge - уже нет.
Так или иначе в каталоге /boot появится каталог /boot/initrd-tree. Это
как раз несжатый снимок initrd диска. Там нужно будет отредактировать
скрипт /boot/initrd-tree/init. Ищем ближе к концу кусок кода:
if [ ! -r /mnt/sbin/init ]; then
echo "ERROR: No /sbin/init found on rootdev (or not mounted). Trouble ahead."
и вставим как раз перед ним все те манипуляции с подменой каталогов, о
которых речь шла выше. Но для начала стоит выяснить на каком именно
диске находится наш LiveCD. Т.е. в момент загрузки линка /dev/cdrom у
нас ещё нет, так что придётся это делать вручную. ``Читал /proc, много
думал ...''
ROOTDEV=$(cat /proc/sys/dev/cdrom/info | sed -rne '/drive name/s%drive name:[[:blank:]]*([[:alnum:]]*)%/dev/1%p')
ROOTFS=iso9660
# Switch to real root partition:
echo 0x0100 > /proc/sys/kernel/real-root-dev
mount -o ro -t $ROOTFS $ROOTDEV /mnt
mount -t tmpfs -o size=100m none /mnt/var
mount -t tmpfs -o size=10m none /mnt/tmp
mount -t tmpfs -o size=10m none /mnt/etc
cp -a /mnt/var1/* /mnt/var
cp -a /mnt/etc1/* /mnt/etc
В конце скрипта init происходит подмена /mnt на / с помощью:
exec switch_root /mnt /sbin/init $RUNLEVEL
Так что файловая система на CD вместе с подмонтированными к ней
/var,/etc,/tmp окажется корневой. Что и требовалось. Обратите внимание,
что в файле fstab про tmpfs каталоги ничего не сказано. Это правильно -
oни уже смонтированы в initrd и этого достаточно.
После того как скрипт поправлен и все остальное на initrd-tree вас
устраивает, то нужно сжать эту ветку в файл initrd.gz, прогнав mkinitrd
по второму разу. В итоге получим файл /boot/initrd.gz размером порядка
0.7МБ.
Создание образа загрузочной дискеты
К этому моменту должны быть в наличии /boot/initrd.gz и ядро
/boot/vmlinuz. Все это надо записать на ``загрузочную дискету'', а потом
туда же в MBR скинуть загрузчик lilo. Поскольку последний раз дискету в
живую я видел несколько лет назад, то вместо неё будем использовать
loopback-device.
Нарежем его. Файл размером 2.88МБ назовём b.bin
#dd if=/dev/zero of=/b.bin bs=1K count=2880
Посадим его на /dev/loop0:
#/sbin/losetup /dev/loop0 b.bin
И отформатируем его. Файловая система может быть любая - хоть DOS, лишь
бы в ядре была её поддержка:
#/sbin/mke2fs /dev/loop0
А теперь создадим mount-point для него, смонтируем и скопируем туда ядро
и initrd.gz. Главное - чтоб места там хватило!
Если жалоб на недостаток места не было, то осталось запихнуть туда ещё и
загрузчик (это как анекдот про носорога и жирафа в холодильнике). Но
перед этим сочиним /etc/lilo.conf:
#образ дискеты у нас на loopbacke, при этом мы делаем вид, что это диск A с геометрией как у дискетки
boot = /dev/loop0
disk=/dev/loop0
bios=0x0
sectors=36
heads=2
cylinders=80
# но не забываем, что это все же загружаемый CD (el-torito)
el-torito-bootable-CD
compact
prompt
timeout = 100
#Ядро и initrd.gz находятся на том же образе, подмонтированном на /mnt/loop0.
#Туда же запишем и образовавшийся в процессе работы lilo map-файл
map=/mnt/loop0/map
image = /mnt/loop0/vmlinuz
#root роли не играет, все равно решает initrd
root = "LABEL=relay-boot1"
initrd = /mnt/loop0/initrd.gz
label = Linux-CD
read-only
Осталось только запустить lilo:
# /sbin/lilo
Warning: LBA32 addressing assumed
Added Linux-CD *
One warning was issued.
Если возникнут ошибки и более серьёзные предупреждения (map и
boot-record на разных дисках), то следует ещё раз проверить - а все ли
вы делали правильно?
Теперь осталось подчистить за собой loopback.
#umount /mnt/loop0
#/sbin/losetup -d /dev/loop0
И прощай, jail!
#exit
#cd ..
Собираем все в одну кучу - создание загрузочного CD
Делается одной командой:
mkisofs -b b.bin -o router.iso -R /tmp/cdrom
Указано, что диск использует полновесное Rock-Ridge расширение (-R),
диск загружаемый, где -b указывает загрузочный образ, причём все пути
относительно корневого каталога CD (/tmp/cdrom). В итоге у нас имеется
готовый образ загружаемого диска router.iso.
Эпилог
Вот и всё. Однако я не стал бы торопиться и жечь болванки. Лучше
воспользоваться эмулятором qemu и убедиться, что созданный выше образ
работоспособен, и загрузка продолжается по крайней-мере до login-а: