Минимализм-2
2010-06-27 03:46В продолжение темы. Дальше только для пользователей FreeBSD.
1. Для демонстрации идеи начнем с "Hello, World!"
#include <sys/syscall.h>
#define MESG "Hello, world!\n"
#define MESG_SZ (sizeof(MESG)-1)
int syscall(const int n, ...);
#define _exit(a) syscall(SYS_exit, a)
#define write(a, b, c) syscall(SYS_write, a, b, c)
int errno;
int main() {
write(1, MESG, MESG_SZ);
_exit(0);
return 0; /* make compiler happy */
}Написанная в таком стиле программа является строгим кодом на C (собирается gcc -ansi -pedantic -Wall без замечаний), не использует и не требует сервиса libc, общаясь с ядром FreeBSD непосредственно через системные вызовы и под FreeBSD 8.0/i386 компилируется в статический бинарник размером в 512 байт:gcc -Os -ansi -pedantic -Wall -I/usr/src/lib/libc/i386 -nostartfiles -nodefaultlibs -nostdlib -s -static -O99 -fomit-frame-pointer -Wl,--entry=main,--gc-section -o hello hello.c /usr/src/lib/libc/i386/sys/syscall.S /usr/src/lib/libc/i386/sys/cerror.S /usr/src/lib/libc/sys/__error.cЦена - отсутствие переносимости на другие OS.
2. FreeBSD, как и другие OS, наравне с "традиционными" файловыми системами на разделах дисков умеет использовать заранее подготовленные файл-образы файловых систем, сначала "подключая" (attach) образы, что создает в каталоге /dev новое "устройство", соответствующее файл-образу, а затем монтируя его как любое другое устройство. К сожалению, система загрузки FreeBSD пока не предоставляет готового сервиса по "подключению" произвольного количества образов средствами
loader без загрузки их полностью в память (есть штатный метод с загрузкой - директивами mfsroot_* в /boot/loader.conf).А всего-навсего надо-то один системный вызов (
MDIOCATTACH) на образ, а дальше монтировать можно уже штатно через /etc/fstab. Актуальность такого сервиса проявляется при создании "встроенных" решений для аппаратных систем с небольшим размером носителя (флеша) и RAM (необязательно на архитектуре i386). Можно было бы сжать файловую систему при помощи geom_uzip, "аттачить" её перед стартом /sbin/init как /dev/md0.uzip и прописать в /etc/fstab монтирование /dev/md0.uzip в качестве корня вместо действительного носителя. И не читать только для этого весь образ в дефицитную память.Если быть педантичным, то есть способ обойтись штатными средствами: использовать
/rescue/sh для запуска shell-скрипта перед вызовом /sbin/init (у loader есть и такая возможность), он подробно описан в статье http://wiki.freebsd.org/AvgLiveCD. Но для встроенных решений у него есть очевидный недостаток - он зависит от наличия /rescue/sh на загрузочном носителе, а этот файл (crunched binary) в FreeBSD 8.0 занимает чуть больше 4Mb. Для LiveCD это ничто, но встроенные системы могут иметь ненамного больше флеша. И ради одного системного вызова для них это может быть слишком большим оверхедом.3. Наилучшим решением было бы расширить функциональность загрузчика и обучить его передавать в ядро информацию о необходимости подключать указанные в
loader.conf файл-образы перед запуском /sbin/init, а также научить ядро использовать эту информацию и следовать её инструкциям. Но это относительно крупные изменения в системе.Более легковесным (и полностью рабочим) решением будет маленький статический бинарник mdtab, созданный по описанной в пункте 1 технологии. Бинарник умеет прочитать свой конфиг
/boot/mdtab.conf, в котором каждая строка описывает один файл-образ и состоит из двух полей, разделенных пробельными символами: имени сжатого geom_uzip-образа и точки монтирования. Затем он подключает и сразу монтирует (r/o) образ файловой системы. Размер бинарника для 8.0 получается менее 3Kb. Его можно запускать и в multiuser как любое другое приложение, а кроме того, можно использовать директиву init_path="/boot/mdtab" в loader.conf. В этом случае mdtab запускается ядром вместо /sbin/init с PID=1 и тогда он при окончании работы вместо _exit() запускает /sbin/init через execve, прозрачно передавая ему аргументы и environment.Исходный код mdtab и Makefile для сборки доступны тут: http://www.grosbein.net/freebsd/mdtab-0.1.tgz
Пример
/boot/mdtab.conf для одного образа на всю систему:В образ надо убрать все файлы и каталоги, кроме# Монтировать образ поверх корневой fs /root.uzip /
/boot и /dev. При таком варианте после загрузки ядра (и монтирования им корневой файловой системы и devfs) mdtab смонтирует образ "поверх" рута и скроет доступ к /boot и /dev. При этом devfs будет автоматически повторно смонтирована одним из системных rcNG-скриптов при загрузке.Можно сделать чуть иначе, монтируя образ не напрямую поверх рута, а в каталог
/tree. В этом варианте нужно в корне наделать симлинков типа /usr -> /tree/usr (и так далее для всех подкаталогов корня, кроме /boot и /dev). При такой настройке остается доступ к /boot и /dev тоже не будет монтироваться дважды.
no subject
Date: 2010-06-27 06:58 (UTC)