Содержание
- Введение
- Ядро
- crunchgen
- mfsroot
- Загрузочная дискета
1. Введение
Проблема подготовки загрузочной дискеты во FreeBSD обычно решается при помощи дистрибутива PicoBSD, который поставляется вместе с пакетом исходных кодов. Однако, бывают случаи когда такую дискету требуется подготовить своими руками.
Программные файлы FreeBSD обладают весьма внушительными размерами (например, во FreeBSD 4.6 файл команды ls занимает чуть менее 300Кб), поэтому основная проблема при подготовке загрузочной дискеты это острая нехватка свободного пространства. По этой причине от простого размещения файлов программ на дискете приходится отказаться, и в таком случае, возможна организация файловой системы в виртуальной памяти компьютера (MFS), где и будет храниться львиная доля всех файлов. Впрочем, это не относится к парадоксальной ситуации с ядром, которое должно располагаться на дискете в корневой директории, несмотря на то, что в обычном состоянии его размеры намного превосходят объем стандартной дискеты. Кроме того, при использовании MFS необходимо учитывать, что эта файловая система считывается из файла образа и отображается на оперативную память и, что естественно, любые изменения в файлах при каждой перезагрузке системы будут уничтожаться. Поэтому, использовать MFS для хранения конфигурационных файлов очень неудобно.
Подобные обстоятельства делают процесс подготовки загрузочной дискеты довольно сложным и сильно отличающимся от аналогичной операции в MS-DOS. Поэтому в двух словах поясню последовательность наших действий:
- Для начала, подготовим и сожмем при помощи gzip ядро, с минимальным набором опций, не забыв, однако, включить в него поддержку MFS.
- При помощи crunchgen соберем из исходных кодов один программный файл, объединяющий в себе основные программы операционной системы.
- Далее создадим mfsroot - образ файловой системы в виртуальной памяти, наполним его к файлами устройств и запишем на него crunch'еный бинарник.
- Подготовим файлы конфигурации и основные скрипты загрузки системы. В нашем случае эти файлы придется разделить на две группы: изменяемые и неизменяемые. Файлы первой группы будут размещены на файловой системе дискеты в каталоге /etc вне MFS, и, следовательно, при необходимости, могут быть изменены, файлы второй группы будут записаны на MFS и соответственно, изменения в них будут сохраняться до первой перезагрузки системы.
- Подготовим образ дискеты и запишем на него загрузчики ОС boot1, boot2 и loader. В loader.rc укажем, что при загрузке необходимо загрузить ядро kernel и из файла mfsroot организовать файловую систему в виртуальной памяти компьютера, Далее на образ дискеты запишем ядро и сжатый gzip'ом mfsroot, в каталог /etc поместим оставшиеся модифицируемые конфигурационные файлы.
Для наших опытов будем использовать FreeBSD 4.6-Release c полным наборов установленных исходных кодов.
2. Ядро
Нам нужно ядро, которое на дискете занимало бы как можно меньше места. Поэтому выбросим из него все лишнее и оставим, только самое необходимое. Допустим, что наше ядро будет называться SMALL, тогда создаем в каталоге /usr/src/sys/i386/conf файл SMALL:
machine i386 cpu I586_CPU cpu I686_CPU ident SMALL maxusers 10 options MATH_EMULATE # Support for x87 emulation options INET # InterNETworking options FFS # Berkeley Fast Filesystem options FFS_ROOT # FFS usable as root device [keep this!] options MFS # Memory Filesystem options MD_ROOT # MD is a potential root device options NFS # Network Filesystem options CD9660 # ISO 9660 Filesystem options COMPAT_43 # Compatible with BSD 4.3 [KEEP THIS!] device isa device pci # Floppy drives device fdc0 at isa? port IO_FD1 irq 6 drq 2 device fd0 at fdc0 drive 0 # ATA and ATAPI devices device ata0 at isa? port IO_WD1 irq 14 device ata1 at isa? port IO_WD2 irq 15 device ata device atadisk # ATA disk drives device atapicd # ATAPI CDROM drives options ATA_STATIC_ID # Static device numbering # atkbdc0 controls both the keyboard and the PS/2 mouse device atkbdc0 at isa? port IO_KBD device atkbd0 at atkbdc? irq 1 flags 0x1 device vga0 at isa? # syscons is the default console driver, resembling an SCO console device sc0 at isa? flags 0x100 # Floating point support - do not disable. device npx0 at nexus? port IO_NPX irq 13 # PCI Ethernet NICs that use the common MII bus controller code. # NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! device miibus # MII bus support device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') # Pseudo devices - the number indicates how many units to allocate. pseudo-device loop # Network loopback pseudo-device ether # Ethernet support pseudo-device pty # Pseudo-ttys (telnet etc) pseudo-device md # Memory "disks"
Примеры нескольких подобных ядер можно взять у PicoBSD (/usr/src/release/picobsd). В принципе, в ядро можно включить любые опции и драйвера, оптимизированные для каждого конкретного случая, однако необходимо помнить, что поскольку ядро будет загружать MFS-файловую систему, следующие строки обязательны:
options MFS # Memory Filesystem options MD_ROOT # MD is a potential root device pseudo-device md # Memory "disks"
теперь компилируем ядро:
config SMALL; cd ../../compile/SMALL; make depend; make all
Если все прошло удачно, у нас появится ядро, которое по нашим представлениям должно быть эталоном миниатюрности. Для справки, на FreeBSD 4.6 размер такого ядра у меня получился 1705820 байт, что все равно превышает объем 1,44Мб.
Остается "почистить" скомпилированное ядро:
strip kernel strip --remove-section=.note --remove-section=.comment kernel
и наконец сжать его:
gzip -v -n --best kernel
В результате компрессии, ядро стало занимать чуть более 600 Кбайт. Итак, нам удалось сократить размеры ядра более чем в 2 раза! И у нас остается еще место для корневой файловой системы.
3. Crunchgen
Проблему размещения программных файлов постараемся разрешить при помощи программы /usr/bin/crunchgen, спасибо James da Silva ). Эта программа собирает один большой бинарный файл из исходных кодов нескольких программ. Напишем для нее собственный конфигурационный файл crunch.conf:
buildopts -DNOIPSEC -DRELEASE_CRUNCH -DCRUNCHED_BINARY -DNOSECURE -DNOCRYPT -DNOPAM srcdirs /usr/src/bin srcdirs /usr/src/sbin/i386 srcdirs /usr/src/sbin srcdirs /usr/src/usr.bin srcdirs /usr/src/gnu/usr.bin srcdirs /usr/src/usr.sbin srcdirs /usr/src/libexec progs sh test echo hostname ln login getty stty progs inetd telnetd progs w kget reboot progs init ifconfig df cat progs cp rm mknod chmod chown mkdir ls syslogd progs sysctl route pwd_mkdb dev_mkdb progs mount umount swapon disklabel vnconfig progs kill mount_std progs pwd telnet progs passwd date progs mount_cd9660 mount_nfs ping traceroute ln mount_cd9660 cd9660 ln mount_nfs nfs ln test [ ln sh -sh ln mount_std procfs ln mount_std mount_procfs ln chown chgrp libs -lncurses -lmytinfo -lipx -lz -lpcap -lalias -lwrap libs -ledit -lutil -lmd -lcrypt -lmp -lgmp -lm -lkvm libs -lgnuregex -ltermcap -lipsec /usr/src/lib/libtelnet/libtelnet.a
По правде говоря, для наших целей, если произвести незначительные изменения, вполне подойдет один из аналогичных файлов PicoBSD. Далее запускаем crunchgen на выполнение:
crunchgen crunch.conf
Увидев "Run "make -f crunch.mk" to build crunched binary", выполняем:
make -f crunch.mk
Единственная проблема, с которой мне пришлось столкнуться при выполнении crunchgen, это ошибки при компиляции telnet. Для их устранения, мне пришлось вручную компилировать telnet, чтобы получить /usr/src/lib/libtelnet/libtelnet.a.
В результате, создается долгожданный программный файл crunch, который при размере чуть более 1Мб выполняет функции более сорока самых необходимых команд FreeBSD.
4. mfsroot
На самом деле если вычесть размеры сжатого ядра, на дискете у нас остается не так много свободного места, всего порядка 600 Кб и следовательно, организовывать корневую файловую систему прямо здесь не имеет никакого смысла, мы просто не сможем там разметить все наши файлы, не говоря уже про объемистый crunch'еный бинарник. Поэтому используем возможность создания файловой в виртуальной памяти компьютера, для этого создадим файл образа MFS, наполним его всеми необходимыми файлами, сожмем его при помощи gzip и наконец, поместим его в корневую директорию дискеты.
Подготовим MFS-образ корневой файловой системы. Пусть он будет располагаться в файле mfsroot:
dd if=/dev/zero of=mfsroot count=4096 bs=1k # Создадим mfs-образ. Для минимального набора # файлов, 4-х мегабайтов нам вполне хватит vnconfig -s labels -c /dev/vn0 mfsroot # Будем работать с mfsroot как с дисковым устройством disklabel -rw vn0 auto # Разметим и newfs -i 4096 -m 0 -p 0 -o space /dev/vn0c # организуем на нем файловую систему mount /dev/vn0c /mnt # и смонтируем ее в каталог /mnt
Теперь осталось воспроизвести на MFS-образе минимальный набор каталогов и заполнить файловую систему необходимыми файлами. Какие именно файлы и директории там будут располагаться зависит от воображения ее автора и целей создаваемой дискеты. В нашем случае, понадобятся каталоги /etc, /dev, /sbin, /usr, /var, /tmp, /flp:
mkdir /mnt/etc mkdir /mnt/sbin mkdir /mnt/dev mkdir /mnt/usr mkdir /mnt/var mkdir /mnt/tmp mkdir /mnt/flp
Полезно также сделать несколько ссылок:
cd /mnt ln -s sbin ./bin ln -s sbin ./stand ln -s ../sbin ./usr/bin ln -s ../sbin ./usr/sbin
В каталоге /dev надо создать минимальный набор устройств:
cd /mnt/dev mknod console c 0 0; chmod 600 console mknod kmem c 2 1 root:kmem; chmod 640 kmem mknod mem c 2 0 root:kmem; chmod 640 mem mknod null c 2 2; chmod 666 null mknod random c 2 3; chmod 644 random mknod urandom c 2 4; chmod 644 urandom mknod zero c 2 12; chmod 666 zero mknod io c 2 14; chmod 600 io mknod tty c 1 0; chmod 666 tty mknod klog c 7 0; chmod 600 klog mknod stdin c 22 0; chmod 666 stdin mknod stdout c 22 1; chmod 666 stdout mknod stderr c 22 2; chmod 666 stderr mknod pci c 78 0; chmod 644 pci mknod fd0 c 9 0; chmod 600 fd0 mknod ttyv0 c 12 0; chmod 644 ttyv0 mknod ttyv1 c 12 1; chmod 644 ttyv1 mknod ttyv2 c 12 2; chmod 644 ttyv2 mknod ttyv3 c 12 3; chmod 644 ttyv3 mknod ttyp0 c 5 0; chmod 666 ttyp0 mknod ttyp1 c 5 1; chmod 666 ttyp1 mknod ttyp2 c 5 2; chmod 666 ttyp2 mknod ttyp3 c 5 3; chmod 666 ttyp3 mknod ttyp4 c 5 4; chmod 666 ttyp4 mknod ttyp5 c 5 5; chmod 666 ttyp5 mknod ttyp6 c 5 6; chmod 666 ttyp6 mknod ttyp7 c 5 7; chmod 666 ttyp7 mknod ttyp8 c 5 8; chmod 666 ttyp8 mknod ttyp9 c 5 9; chmod 666 ttyp9 mknod vn0 c 43 2; chmod 644 vn0 mknod vn0a c 43 0; chmod 644 vn0a mknod vn0b c 43 1; chmod 644 vn0b mknod vn0c c 43 2; chmod 644 vn0c
Не забудем, также, в /sbin на MFS положить файл crunch и сделать на него необходимые жесткие ссылки:
#!/bin/sh сp crunch /mnt/sbin for i in `crunchgen -l crunch.conf` ; \ do \ ln /mnt/sbin/crunch /mnt/sbin/$i; \ done
Теперь осталось самое сложное - заполнить каталог etc на образе MFS. Однако своими миниатюризированными конфигурационными файлами нас выручит PicoBSD. Оттуда мы возьмем, слегка модифицировав, несколько жизненно необходимых файлов.
ttys:
vga none cons25 off secure ttyv0 "/sbin/getty Pc" cons25 on secure # Virtual terminals ttyv1 "/sbin/getty Pc" cons25 on secure ttyv2 "/sbin/getty Pc" cons25 on secure ttyv3 "/sbin/getty Pc" cons25 on secure # Pseudo terminals ttyp0 none network secure ttyp1 none network secure ttyp2 none network secure ttyp3 none network secure ttyp4 none network secure ttyp5 none network secure ttyp6 none network secure ttyp7 none network secure ttyp8 none network secure ttyp9 none network secure
gettytab:
default:\ :cb:ce:ck:lc:fd#1000:cl:im=\r\n%s/%m (%h) (%t)\r\n\r\n:sp#1200: P|Pc|Pc console:\ :ht:np:sp#115200: # Fixed speed entries 2|std.9600|9600-baud:\ :np:sp#9600: g|std.19200|19200-baud:\ :np:sp#19200: std.38400|38400-baud:\ :np:sp#38400: std.57600|57600-baud:\ :np:sp#57600: std.115200|115200-baud:\ :np:sp#115200: local.9600|CLOCAL tty @ 9600 Bd:\ :c0#0x0000c300:c1#0x0000cb00:c2#0x0000cb00:\ :o0#0x00000007:o1#0x00000002:o2#0x00000007:\ :i0#0x00000704:i1#0x00000000:i2#0x00000704:\ :l0#0x000005cf:l1#0x00000000:l2#0x000005cf:\ :sp#9600:
login.conf:
# Authentication methods auth-defaults:\ :auth=passwd: auth-root-defaults:\ :auth-login=passwd:\ :auth-rlogin=passwd:\ auth-ftp-defaults:\ :auth=passwd: default:\ :cputime=infinity:\ :datasize-cur=22M:\ :stacksize-cur=8M:\ :memorylocked-cur=10M:\ :memoryuse-cur=30M:\ :filesize=infinity:\ :coredumpsize=0:\ :maxproc-cur=64:\ :openfiles-cur=64:\ :priority=0:\ :requirehome@:\ :umask=022:\ :tc=auth-defaults: standard:\ :copyright=/etc/COPYRIGHT:\ :welcome=/etc/motd:\ :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,EDITOR=/usr/bin/ee:\ :path=~/bin /bin /usr/bin:\ :nologin=/var/run/nologin:\ :cputime=1h30m:\ :datasize=8M:\ :stacksize=2M:\ :memorylocked=4M:\ :memoryuse=8M:\ :filesize=8M:\
Поскольку образ MFS смонтирован в директорию /mnt, эти файлы должны быть записаны в каталог /mnt/etc.
Для загрузки этих 3-х файлов вполне хватит, однако, работать с такой системой будет практически невозможно. Для более или менее нормального функционирования, системе потребуется большинство конфигурационных файлов, наблюдаемых нами, на любой машине FreeBSD в каталоге /etc. Кроме того, как уже было сказано, изменения в файлах на MFS будут сохраняться только до перезагрузки системы. Решая эту проблему, воспользуемся опытом PicoBSD и разделим все конфигурационные файлы из каталога /etc на две группы. Первые, которые мы не планируем когда-либо изменять, запишем в каталог /etc на MFS, вторые тоже поместим в директорию /etc, но уже на файловой системе дискеты.
Как минимум, на MFS нам пригодятся файлы disktab, protocols, services и termcap, которые в очередной раз можно смело заимствовать у PicoBSD, поэтому, предполагая, что конфигурационные файлы PicoBSD располагаются в /usr/srs/release/picobsd/mfs-tree/etc, выполняем:
cp /usr/src/release/picobsd/mfs_tree/etc/disktab /mnt/etc cp /usr/src/release/picobsd/mfs_tree/etc/protocols /mnt/etc cp /usr/src/release/picobsd/mfs_tree/etc/services /mnt/etc cp /usr/src/release/picobsd/mfs_tree/etc/termcap /mnt/etc
Так как остальные конфигурационные файлы будут находится за пределами MFS, при загрузки системы их придется копировать на MFS в каталог /etc. Для этого к ttys, gettytab и login.conf в каталог /etc на MFS (в настоящий момент это /mnt/etc), добавим простой rc-файл:
#!/sbin/sh PATH=/sbin; export PATH mount -o rdonly /dev/fd0 /flp cd /etc cp /flp/etc/* . umount /flp . rc.main exit 0
Этот скрипт должен будет скопировать все файлы из директории /etc на дискете в одноименный каталог на образе MFS и затем вызвать "настоящий" rc-файл (rc.main), однако на этом остановимя немного позже, а сейчас, поскольку MFS-образ готов, выполняем:
umount /mnt # размонтируем /mnt и vnconfig -u vn0 # отключим связку mfsroot и /dev/vn0c
Завершив эксперименты с mfsroot, заархивируем его:
gzip --best mfsroot
В результате получается файл mfsroot.gz объемом около 600Кб, при условии что свободное пространство на MFS-образе заполнено нулями, таким образом, операции создания и удаления файлов не оставили за собой мусора в файловой системе. Наилучшие результаты сжатия mfsroot в этом случае достигаются путем записи заранее подготовленных файлов на их точные места на образе MFS.
5. Загрузочная дискета
Настало время подготовить образ загрузочной дискеты. В общем случае, процесс загрузки FreeBSD разделен на 4 этапа, каждому из которых соответствует определенный файл в файловой системе FreeBSD:
- MBR - /boot/boot0;
- Stage 1 - /boot/boot1;
- Stage 2 - /boot/boot2;
- Stage 3 - /boot/loader.
Разумеется, файлы boot0, boot1 и boot2 являются всего лишь копиями загрузочных областей дисков, которые, по понятным причинам, находятся вне файловой системы FreeBSD.
Поскольку мы планирует загружаться с дискеты, boot0 (MBR) нас не интересует, и в нашем случае, boot-процесс начнется со Stage 1 (/boot/boot1). Во время начальной загрузки BIOS пытается прочитать 1-й сектор нулевой дорожки нулевой стороны диска в дисководе "a:", это и должен быть boot1. Boot1 - весьма простая программа, основная цель которой найти и запустить boot2 (Stage2). В принципе, уже boot2 может загрузить ядро FreeBSD, однако, он, видимо, не может распознать формат заархивированного ядра, по крайней мере, мне так и не удалось заставить его сделать это. Далее, boot2 загружает loader (Stage3), который находится уже в файловой системе в каталоге /boot. В настоящее время loader и является основным средством загрузки ядра. Подробности порядка и особенностях загрузки FreeBSD описаны в handbook.
Таким образом, необходимо чтобы в загрузочных областях дискеты находились boot1 и boot2, а также, на дискете в каталоге /boot файловой системы FreeBSD должны быть записаны файлы loader и loader.rc.
Итак, создадим загрузочный образ дискеты. В командной строке выполняем:
dd if=/dev/zero of=flpImage count=1440 bs=1k # Создаем файл образа дискеты - flpImage vnconfig -s labels -c /dev/vn0 flpImage # Будем работать с ним как с устройством disklabel -Brw -b /boot/boot1 -s /boot/boot2 vn0c fd1440 # Помещаем на него boot1 и boot2 newfs -i 32768 -m 0 -p 0 -o space /dev/vn0с # Создаем на нем файловую систему vnconfig -u vn0 # Отключаемся от файла как устройства
Здесь flpImage - файл образа дискеты, который в последствии будет записан на дискету.
Теперь следует подготовить файл loader.rc, который будет выполнен программой loader, в момент, когда загрузка доберется до этапа Stage3. Этот простенький скрипт будет содержать следующие строки:
echo Loading kernel... # Выводим на экран сообщение о загрузки ядра load /kernel # и загружаем его echo Loading MFS... # Выводим сообщение о загрузки MFS-файловой системы load -t mfs_root /mfsroot # И загружаем ее autoboot 0 # Загружаемся сразу, а не ждем обычные 9 секунд.
Далее, полученный образ дискеты остается подмонтировать и записать на него /boot/loader и loader.rc:
vnconfig vn0 flpImage mount /dev/vn0c /mnt mkdir /mnt/boot cp /boot/loader /mnt/boot cp loader.rc /mnt/boot
На образе дискеты создадим каталог /etc, поместив в него несколько конфигурационных файлов:
hosts:
127.0.0.1 localhost localhost.mydomain 192.168.1.1 1f-bsd 1f-bsd.somewere.net
inet.d в нашем случае может состоять всего из одной строки:
telnet stream tcp nowait root /usr/sbin/telnetd telnetd
Файлы passwd, master.passwd и group можно подготовить свои, чтобы разрешить доступ только ограниченному кругу людей, или же взять с текущей работающей машины, и, таким образом, перенести на нашу систему всех пользователей.
Урезанные файлы disktab и services, уже по привычке, позаимствуем у PicoBSD, но rc.main, для простоты напишем свой:
#!/sbin/sh # add swap file dd if=/dev/zero of=/swapfile count=1024 bs=1k vnconfig /dev/vn0b /swapfile swapon /dev/vn0b # make password database pwd_mkdb -p ./master.passwd # create device database dev_mkdb # setup network hostname 1f-bsd ifconfig lo0 inet 127.0.0.1 ifconfig xl0 inet 192.168.1.1 netmask 255.255.255.0 # Start daemons syslogd inetd exit 0
И наконец, поместим в корневом каталоге дискеты сжатые ядро и mfsroot:
cp kernel.gz /mnt cp mfsroot.gz /mnt
Теперь можно смело размонтировать образ дискеты и отключить его от устройства vn0:
umount /mnt vnconfig -u vn0
Почти все готово, единственное, что остается сделать, это вставить дискету в дисковод и выполнить:
dd if=flpImage of=/dev/fd0
для того, чтобы записать подготовленный образ на дискету. Теперь, остается лишь загрузиться с нашей дискеты и проверить, действительно ли она работает.