Все о Linux. LinuxRSP.Ru


Cвежие новости Linux и BSD, анонсы статей и книг прямо в почтовый ящик!
Подписаться письмом


 Сегодняшние новости:

25 лет исполнилось ядру Linux

Релиз KDevelop 5.0

Oracle открывает код JDK9 для ARM

Выпущен Timewarrior 1.0.0

Релиз Android 7.0

Percona Memory Engine для MongoDB на базе WiredTiger

PowerShell открыт и доступен для Linux

Форк TrueCrypt: VeraCrypt 1.18

Релиз Snapcraft 2.14

Релиз Go 1.7

Стабильный выпуск рабочего стола Lumina

Вышла первая версия аналога OpenCV - DCV 0.1

Выпуск минималистичной программы для мониторинга jsonmon 3

В MIT разработали новый язык программирования

Первый релиз Qt5Gtk2

Godot 2.1 - новая версия открытого игрового движка

Свободная цифровая станция звукозаписи: Ardour 5.0

Обновление SkypeWeb Plugin for Pidgin

Вышла версия 3.0 Android File Transfer для Linux (и для OS X)

Программный аналог MIDI-контроллера для создания музыки: Launchpadd v1.3

Mozilla спонсирует поддержку Python 3.5 в PyPy

Ef 0.08 - программа для моделирования динамики заряженных частиц

Обновление текстового редактора TEA до версии 42.0.0

Релиз OpenOrienteering Mapper 0.6.4

Вышли Guix и GuixSD 0.11

Релиз Opera 39

Выпуск LibreOffice 5.2

В OpenSSH обнаружены и устранены некоторые уязвимости

Эмулятор FCEUX 2.2.3

Компания Билайн переходит на российскую СУБД с открытым исходным кодом Tarantool

Google

 Новые статьи :

Утилиты для восстановления потерянных данных в Linux

Лучшие файловые менеджеры для Android

20 лучших бесплатных книг о Linux

Как сгенерировать открытый/закрытый SSH-ключ в Linux

Grive - клиент Google Drive для Linux с открытым исходным кодом

Протокол IPv6: варианты подключения

Сервер из образа: DHCP + TFTP + Initrd + OpenVZ

Обзор веб-панелей управления хостингом

Приёмы работы с Vim

Nginx как Reverse Proxy для сайта, использующего SSL

Разработка модулей ядра Linux

Мониторинг нагрузки http-сервера Apache 2

Перевод комментариев к файлу конфигурации Squid

Решение проблем при использовании "1c предприятие" 8.2 в Linux

Advanced Bash-Scripting Guide Искусство программирования на языке сценариев командной оболочки







Rambler's Top100





 
 

Вся система в одном файле. Часть 1

Сижу я однажды после бессонной ночи в интернете, читаю HOWTO. И попадается мне очень интересная HOWTO-шка под названием "Loopback-Root-FS (использование loopback устройства Linux для создания файловой системы Linux, которая может запускаться из DOS-раздела без изменения системы разделов)" О как. Там идет речь о создании корневой файловой системы ext2 внутри файла, лежащего на разделе MS-DOS. И о запуске всей системы с помощью 3 файлов: загрузчика LOADLIN, ядра и этого файла с ext2 внутри.... Правда, там еще свап предлагают создать.... Тоже в файле на разделе DOS. Ну конечно я свап создал ... на 16 метров :) Чисто на всякий пожарный. Однако по ходу дела возникло много вопросов, в ходе решения которых я узнал много интересного...

Итак, в начале я создал командой dd все необходимые файлы:

#dd if=/dev/zero of=/root/initrd.img bs=1024 count=4096
(Это - заполненный нулями файл размером в 4 Мб, который вскоре будет нести в себе файловую систему Ext2 для Initial RAM drive).
#dd if=/dev/zero of=/root/linuxdsk.img bs=1024 count=16384
(Тут будет корневая ФС, размер [count=], разумеется, нужно выбирать разумно, исходя из того, сколько места есть на диске и сколько места хочется получить внутри файла когда там будет создана файловая система... Я "навскидку" решил, что мне для тренировки хватит 16 Мб)
#dd if=/dev/zero of=/root/linuxswp.img bs=1024 count=16384
(Тот самый свап... При наличии 128 Мб ОЗУ и отсутствии Х-ов он может быть и таким маленьким... Хотя можно создать и больший, если надо.)

Такие маленькие файлы, заполненные нулями, создаются на PII-420 с быстрым современным HDD очень недолго. Однако при создании вскоре (интереса для) 5Гб файла мне пришлось пойти попить чайку :)

Теперь, когда файлы созданы, в них создается файловая система (в этом случае - ext2, потом мне пришлось создавать в основном системном файле ext3, но об этом позже).
# cd /root
# mke2fs -i 1024 -b 1024 -m 5 -F -v initrd.img
# mke2fs -i 1024 -b 1024 -m 5 -F -v linuxdsk.img
# mkswap linuxswp.img

Значения всех опций можно узнать в man-странице mke2fs

Теперь пора примонтировать созданные файлы:

# mount -o loop /root/linixdsk.img /mnt/disk
(Монтируем как loopback-устройство к каталогу /mnt/disk)
# mount -o loop /root/initrd.img /root/initrd
(Разумеется, я этот каталог сначала создал в /root )

Захожу в каталог /mnt/disk и вижу там папку lost+found :) Сюрприз...
В /root/initrd она тоже есть. Ладно, она же ведь пока пустая и ничем не мешает :)
Теперь пора наполнить содержимым обе файловые системы - скопировать туда необходимые файлы и каталоги.
Начать видимо следует с initrd.img, смонтированного у меня к /root/initrd, т.к. в HOWTO был так описан процесс загрузки всей этой системы:

---cut on-------
Последовательность загрузки Linux

Чтобы понять, как загрузочный электронный диск работает в процессе загрузки системы, изучим порядок событий при загрузке системы.

1. Ядро загружается в память. Эту операцию производит LILO или LOADLIN. В этот момент выводится сообщение Loading...
2. Образ электронного диска загружается в память, это тоже делает LILO или LOADLIN. В этот момент также выводится сообщение Loading...
3. Производится инициализация ядра, включая обработку опций командной строки и подключение электронного диска в виде корневой файловой системы.
4. На загрузочном электронном диске запускается программа /linuxrc.
5. Корневое устройство переключается в соответствии с параметром ядра.
6. Запускается программа /etc/init, которая уже производит настраиваемую пользователем последовательность загрузки.

Это упрощенное описание того, что происходит на самом деле, но этого достаточно, чтобы описать, как запускается ядро и как используется электронный диск.
---cut off----

Ну значит поехали... Там же чуть ниже приведен ПРИМЕР содержимого загрузочного эл. диска (aka Initial RAM drive)

---cut on----
Содержимое загрузочного электронного диска, которое я использовал, приведено ниже. Оно заняло примерно 800 Кб, если принимать в расчет излишки файловой системы.

total 18
drwxr-xr-x 2 root root 1024 Jun 2 13:57 bin
drwxr-xr-x 2 root root 1024 Jun 2 13:47 dev
drwxr-xr-x 2 root root 1024 May 20 07:43 etc
drwxr-xr-x 2 root root 1024 May 27 07:57 lib
-rwxr-xr-x 1 root root 964 Jun 3 08:47 linuxrc
drwxr-xr-x 2 root root 12288 May 27 08:08 lost+found
drwxr-xr-x 2 root root 1024 Jun 2 14:16 mnt

./bin:
total 168
-rwxr-xr-x 1 root root 60880 May 27 07:56 ash
-rwxr-xr-x 1 root root 5484 May 27 07:56 losetup
-rwsr-xr-x 1 root root 28216 May 27 07:56 mount
lrwxrwxrwx 1 root root 3 May 27 08:08 sh -> ash

./dev:
total 0
brw-r--r-- 1 root root 3, 0 May 20 07:43 hda
brw-r--r-- 1 root root 3, 1 May 20 07:43 hda1
brw-r--r-- 1 root root 3, 2 Jun 2 13:46 hda2
brw-r--r-- 1 root root 3, 3 Jun 2 13:46 hda3
brw-r--r-- 1 root root 7, 0 May 20 07:43 loop0
brw-r--r-- 1 root root 7, 1 Jun 2 13:47 loop1
crw-r--r-- 1 root root 1, 3 May 20 07:42 null
crw-r--r-- 1 root root 5, 0 May 20 07:43 tty
crw-r--r-- 1 root root 4, 1 May 20 07:43 tty1
crw-r--r-- 1 root root 1, 5 May 20 07:42 zero

./etc:
total 3
-rw-r--r-- 1 root root 2539 May 20 07:43 ld.so.cache

./lib:
total 649
lrwxrwxrwx 1 root root 18 May 27 08:08 ld-linux.so.1 -> ld-linux.so.1.7.14
-rwxr-xr-x 1 root root 21367 May 20 07:44 ld-linux.so.1.7.14
lrwxrwxrwx 1 root root 14 May 27 08:08 libc.so.5 -> libc.so.5.3.12
-rwxr-xr-x 1 root root 583795 May 20 07:44 libc.so.5.3.12

./lost+found:
total 0

./mnt:
total 0
---cut off----

Приняв это за основу, я скопировал актуальные для моей системы версии файлов.... Опа... Со времени написания HOWTO прошло почти 4 года, и "начинка" заняла почти 2.5 мега... Разумеется, с этим можно бороться, призвав на помощь к примеру "The Linux Bootdisk HOWTO" раздел "Уменьшение размера корневой файловой системы" (для нас это будет размер первоначальной корневой системы, т.к. корневой впоследствии станет другая, еще пока даже не заполненная система в файле linuxdsk.img) Кстати, Bootdisk HOWTO мне очень пригодилось, когда я создавал основную структуру каталогов и файлов в linuxdsk.img .... Сколько я нового и интересного узнал о старте Linux-системы... Но это позже, т.к. в начале я читал не очень внимательно (за что поплатился чуть позже).

В общем, я призвал на помощь mc и копировал, копировал, копировал.... Чтобы узнать, кому какие библиотеки нужны, я вызывал команду ldd и получал список требуемых библиотек и их расположение.
Я даже не забыл создать внутри будущей корневой ФС файлик /etc/fstab :

#cat /mnt/disk/etc/fstab

/dev/loop0 / ext2 defaults 1 1
/dev/loop1 swap swap defaults 1 1

Уф. Через некоторое время я, кажется, всё упаковал и в /root/initrd, и в/mnt/disk (т.е. в файлы /root/initrd.img и /root/linuxdsk.img, подключенные сейчас туда). Пора писать скрипт linuxrc и готовить ядро ...

Черт! Ядро... Срочно прочитав секцию "Создаём ядро Linux" Loopback-Root-FS HOWTO, я понял, что при очередной недавней компиляции ядра я забыл вкомпилировать в него поддержку loopback FS. Она была (иначе бы опция -o loop команды mount не сработала), но в виде модуля... И еще я прочитал о необходимости патчить ядро, для обеспечения возможности загрузки с oopback-устройства. Правда там самое новое из упомянутых ядер серии 2.3.х у меня же 2.4.21 с патчем для поддержки xfs. Полез в свой /usr/src/linux и начал там поиск... Оказалось что со времен серии 2.2.х некоторые описания структур ядра "переехали" - я, например, нашел список устройств для загрузки в
usr/src/linux/init/do_mounts.c :

---cut on---

static struct dev_name_struct {
const char *name;
const int num;
} root_dev_names[] __initdata = {
{ "nfs", 0x00ff },
{ "hda", 0x0300 },
{ "hdb", 0x0340 },
{ "loop", 0x0700 },
{ "hdc", 0x1600 },
{ "hdd", 0x1640 },
{ "hde", 0x2100 },
{ "hdf", 0x2140 },
{ "hdg", 0x2200 },
{ "hdh", 0x2240 },
{ "hdi", 0x3800 },
{ "hdj", 0x3840 },
{ "hdk", 0x3900 },
{ "hdl", 0x3940 },
{ "hdm", 0x5800 },
{ "hdn", 0x5840 },
{ "hdo", 0x5900 },

---cut off---

Там очень длинная структура, желающие могут ознакомиться....

А в HOWTO рекомендовалось делать так

---cut on----
Для ядер версий 2.0.x в файл /init/main.c надо добавить одну строку, в соответствии с уже измененной версией, приведенной ниже. В строке, которую надо добавить написано "loop", 0x0700.

static void parse_root_dev(char * line)
{
int base = 0;
static struct dev_name_struct {
const char *name;
const int num;
} devices[] = {
{ "nfs", 0x00ff },
{ "loop", 0x0700 },
{ "hda", 0x0300 },

...

{ "sonycd", 0x1800 },
{ NULL, 0 }
};

...

}

Для ядер версий 2.2.x в файл /init/main.c надо добавить три строки, в соответствии с уже измененной версией, приведенной ниже. Надо добавить строку, в которой написано "loop", 0x0700, а также предшествующую и следующую за ней:

static struct dev_name_struct {
const char *name;
const int num;
} root_dev_names[] __initdata = {
#ifdef CONFIG_ROOT_NFS
{ "nfs", 0x00ff },
#endif
#ifdef CONFIG_BLK_DEV_LOOP
{ "loop", 0x0700 },
#endif
#ifdef CONFIG_BLK_DEV_IDE
{ "hda", 0x0300 },

...

{ "ddv", DDV_MAJOR /kernel/fs/ [не исключаю, что модули можно и кучей свалить в /lib/modules, только зачем создавать бардак?]. Правда, модуль loop.o лежит среди блочных {block} устройств, но ведь никто не мешает засунуть в InitialRAM drive все, что нужно для монтирования корневой ФС..... К примеру драйверы USB для монтирования корня с флешки....

Скопировал из своей действующей системы все нужные модули в соотв. каталог /root/initrd . Там у меня до сих пор болтался примонтированный файл /root/initrd.img. Теперь принимаемся за скрипт /linuxrc (тут корень уже для загрузившегося с этим RAM-диском ядра...).

В HOWTO был приведен пример:

---cut on---

Файл /linuxrc

Файл/linuxrc на загрузочном электронном диске нужен для того, чтобы произвести все приготовления, необходимые для подключения зацикленного устройства как корневого.

Скрипт, приведенный ниже пытается подключить /dev/hda1 как раздел msdos, и если это происходит удачно, то он настраивает файлы /linux/linuxdsk.img как /dev/loop0 и /linux/linuxswp.img как /dev/loop1.

#!/bin/sh

echo INITRD: Trying to mount /dev/hda1 as msdos
# echo INITRD: Попытка подключить /dev/hda1 как msdos

if /bin/mount -n -t msdos /dev/hda1 /mnt; then

echo INITRD: Mounted OK
# echo INITRD: Подключение успешно
/bin/losetup /dev/loop0 /mnt/linux/linuxdsk.img
/bin/losetup /dev/loop1 /mnt/linux/linuxswp.img
exit 0

else

echo INITRD: Mount failed
# echo INITRD: Подключение не удалось
exit 1

fi

Первое устройство /dev/loop0 станет корневым, а второе - /dev/loop1 - станет swap-пространством.

----cut off----

Я немного подредактировал скрипт под свою таблицу разделов (я решил поместить файлы linuxdsk.img и linuxswp.img в каталог /linux-loop на корневом в текущий момент устройстве /dev/hda5). Исправить тип в команде mount минутное дело. Очень быстро скрипт был надлежащим образом записан, проверен, закомментирован русским языком :).

Теперь отмонтируем примонтированные устройства
# umount /mnt/disk
# umount /root/initrd

Теперь можно сжать образ загрузочного RAM-диска.
#cd root
#gzip -c -9 initrd.img > initrdgz.img
(все уже поняли, что файлы могут называться как угодно и подключаться куда угодно, однако файл RAM-диска, похоже, должен иметь имя initrd*.img, что легко получить, скопировав его в /boot с нужным именем. Да, стоит внимательно посмотреть, что там еще в /boot есть... И вообще, работать под рутом надо аккуратно.... Однажды в ходе этой (многочасовой) эпопеи я чуть не остался без всех своих модулей в /lib/modules/ - просто вместо F5 в mc нажал F6. Хорошо, опомнился вовремя.)

Теперь осталось подготовить все для загрузки свеженабранной "с бору по сосенке" :) Linux-системы.

linuxdsk.img идет в /linux-loop, туда же отправляется linuxswp.img
Ядро у меня уже лежит в /boot (грузить вся я буду с помощью lilo)
Кладем туда же в /boot наш initrdgz.img

Модифицируем /etc/lilo.conf, добавляя туда секцию вида:

---cut on ---
image=/boot/bzImage-ran0
label=loop-i586
initrd=/boot/initrdgz.img
vga=normal
append="root=/dev/loop0"
read-only
---cut off---

ПРЕДУПРЕЖДЕНИЕ!!! Тут я совершил ошибку, видимо... Слепо скопировал "как написано было". Ядро, видимо, получило сначала команду append="root=/dev/loop0", и молча проигнорировало наличие RAM-диска, вывалившись в итоге с kernel panic по поводу невозможности смонтировать корневую ФС. Полез читать /usr/src/linux/Documentation/initrd.txt и man initrd. Понял, что существуют два механизма смены корневой ФС в процессе работы. Мне удалось реализовать только более старый вариант, через proc filesystem.

Выдержка из man initrd:

---cut on----

СМЕНА НОРМАЛЬНОЙ КОРНЕВОЙ ФАЙЛОВОЙ СИСТЕМЫ
По умолчанию, конфигурация ядра (например, установленная в файле ядра с помощью rdev или на этапе компиляции ядра) или установки загрузчика используются определения нормальной корневой файловой системы.

Для NFS-монтируемой нормальной корневой файловой системы нужно использовать загрузочные опции nfs_root_name и nfs_root_addrs для задания установок NFS. За дополнительной информацией по NSF-монтируемой корневой ФС обращайтесь к файлу документации к ядру nfsroot.txt. Также дополнительная информация по установкам корневой файловой системы содержится в документации к LILO и LOADLIN.

Кроме того, /linuxrc может сменить нормальное корневое устройство. Для того, чтобы /linuxrc сменил это устройство, должен быть подмонтирован каталог /proc. После монтирования /proc, /linuxrc сменяет нормальное корневое устройство, записывая установки в файлы proc /proc/sys/kernel/real-root-dev, /proc/sys/kernel/nfs-root-name, и /proc/sys/kernel/nfs-root-addrs. Что касается физического корневого устройства, оно меняется, если /linuxrc записывает номер нового устройства корневой файловой системы в /proc/sys/kernel/real-root-dev. Для корневой файловой системы NSF корневое устройство меняется, если /linuxrc записывает установки NSF в файлы /proc/sys/kernel/nfs-root-name и /proc/sys/kernel/nfs-root-addrs, а затем записывает 0xff (например,номер псевдо-NFS-устройства) в файл /proc/sys/kernel/real-root-dev.

Так, например, следующие команды изменят нормальное корневое устройство на /dev/hdb1:

echo 0x365 >/proc/sys/kernel/real-root-dev

В качестве примера для NSF, следующие команды изменят нормальное корневое устройство на каталог NSF /var/nfsroot на локальном сетевом NSF-сервере с IP-адресом 193.8.232.7 для системы с IP-адресом
193.8.232.7 и именем 'idefix':

echo /var/nfsroot >/proc/sys/kernel/nfs-root-name
echo 193.8.232.2:193.8.232.7::255.255.255.0:idefix
>/proc/sys/kernel/nfs-root-addrs
echo 255 >/proc/sys/kernel/real-root-dev

---cut off---

Мне оставалось только догадаться, что в моем случае для /dev/loop0 нужно написать строчку вида echo 0x700 >/proc/sys/kernel/real-root-dev .

Я прописал монтирование /proc и эту строку в /linuxrc, убрал в lilo.conf строчку 'append' и система загрузилась.... Почти. Дальше у меня была долгая пляска вокруг init, однако мне так хотелось спать, что я решил оставить все разборки с init на завтра.... Да и этот текст не стоит IMHO делать очень длинным...Насчет init я как-нибудь попозже напишу.

Я пользовался следующими документами:
1. Bootdisk-HOWTO (как создать загрузочную дискету под Линукс)
2. Loopback-Root-FS (использование loopback устройства Linux, для создания файловой системы Linux, которая может запускаться из DOS-раздела без изменения системы разделов)
3. Документация ядра 2.4.21
4. man initrd

Андрей Рандрианасулу


      

Связь | О проекте LinuxRSP | Реклама | О Linux
© 1999-2017 LinuxRSP