LFS: Темна сторона сили. Частина 3

Передмова
Отже, настав час розставити останні крапки над «i» і розповісти про те, як з купи виконуваних файлів і бібліотек, які ми героїчно збирали і налаштовували у минулій статті отримати, нарешті, Linux.

1. Підсистема ініціалізації Unix System V
Ця підсистема ініціалізації довгий час використовувалася в Linux і була стандартом «де-факто». Проте час йде, і не можна в загальному-то називати даний підхід застарілим. Набагато точніше зауважити, що ця підсистема ініціалізації, в тренді розвитку систем сімейства GNU/Linux, поступилася своє місце systemd, народженої в надрах корпорації Red Hat. Існують дистрибутиви досі використовують сценарії ініціалізації. Проте всі популярні лінукси практично поголовно прийшли до використання systemd, причому останній здався консервативний Debian зі своєю донькою Ubuntu.

Взагалі-то я шкодую, що відразу не став збирати варіант LFS, використовує systemd. Просто, після першої невдалої спроби складання не хотілося відхиляться від стабільної траєкторії. Можливо, я ще повернуся до цього питання, можливо так і не повернуся. Час покаже. А поки розглянемо основні принципи роботи скриптів ініціалізації System V.

При завантаженні системи, завантажувач читає ядро Linux з кореневого розділу завантажувального носія. Після ініціалізації ядра керування передається процесу init, отримує ідентифікатор PID=1 (фізично розташований у файл /sbin/init). Даний процес працює у відповідності з параметрами, вказаними у файлі /etc/inittab.

За замовчуванням використовується сім рівнів ініціалізації системи

  • 0 — зупинка системи
  • 1 — завантаження системи у режимі одного користувача
  • 2 — завантаження системи в многопользовательском режимі без підтримки мережі
  • 3 — завантаження системи в многопользовательском режимі з підтримкою мережі
  • 4 — не використовується
  • 5 — завантаження системи в многопользовательском режимі з підтримкою мережі і графічним входом в систему
  • 6 — перезавантаження системи


Кожному рівню запуску відповідають сценарії ініціалізації, у разі LFS розташовані в каталозі /etc/rc.d/init.d/. Їх не доведеться писати самостійно — автори LFS подбали про це, включивши все необхідне для установки в пакет LFS-Bootscripts, який лежить на шляху $LFS/source. Нам залишається лише встановити цей пакет і зробити деякі мінімальний налаштування

2. Установка LFS-Bootscripts, налаштування мережі, /etc/inittab
Припустимо збирання пакетів на попередньому етапі вас втомила і з'явилися інші справи і ви вимкнули машину. Тепер вас знову необхідно потрапити в отриману систему. Для цього необхідно виконати chroot

Монтуємо розділ з системою і VFS:

$ su - root
# export LFS=/mnt/lfs
# mount /dev/sda6 $LFS
# mount-v --bind /dev $LFS/dev
# mount-vt devpts devpts $LFS/dev/pts-o gid=5,mode=620
# mount-vt proc proc $LFS/proc
# mount-vt sysfs sysfs $LFS/sys
# mount-vt tmpfs tmpfs $LFS/run

Виконуємо зміну кореня:

# chroot "$LFS" /usr/bin/env-i \
> HOME=/root TERM="$TERM" PS1='[\u:\w]\$ ' \
> PATH=/bin:/usr/bin:/sbin:/usr/sbin \
> /bin/bash --login

Перейдемо в каталог з вихідними кодами і встановимо потрібний пакет

# cd /source
# tar-pxf lfs-bootscripts-20150222.tar.bz2
# cd lfs-bootscripts-20150222
# make install

Нічого особливо хитрого і не передбачалося — скрипти просто встановляться за потрібне шляхах.

А ось тепер приступимо до налаштування. Згенеруємо правила Udev:

# bash /lib/udev/init-net-rules.sh

Далі мануал пропонує нам перевірити і відредагувати правило іменування мережевих інтерфейсів, розташовані в /etc/udev/rules.d/70-persistent-net.rules. І ось тут мене чекав облом — скрипт генерації видав помилку — не можу згенерувати цей файл.

Відповідь є в тому ж керівництві:
In some cases such as when MAC addresess have been assigned to a network card manually or in a virtual environment such as Qemu or Xen, the network rules file may not have been generated because addresses are not consistently assigned. In these cases, this method cannot be used.


Так, а ось випадок з «Qemu or Xen» він як раз мій — я збирав під віртуальною машиною (VirtualBox, як відомо використовує код Qemu). Ну що ж, напишемо правило іменування мережевої картки вручну. Причому тепер нам не треба використовувати команду cat для створення файлу — адже ми зібрали і налаштували цілий Vim! А Vim — це сила

# vim /etc/udev/rules.d/70-persistent-net.rules

Набиваємо текст правила:

# net device e1000
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="08:00:27:f8:4c:26", ATTR{dev_id}="0x0", ATTR{type}="1", KERNEL=="eth*", NAME=="eth0"

Дане правило, при виявленні ядром мережевого пристрою, з MAC-адресою, зазначеною нами в якості атрибута, присвоює йому ім'я eth0. MAC-адреса мережевої карти можна дізнатися давши в терміналі команду:

# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default 
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:f8:4c:26 brd ff:ff:ff:ff:ff:ff

Параметр link/ether у пристрої enp03s — це і є шуканий мак. Пристрій іменовано хост-системою (а ми пам'ятаємо, що ми лише змінили корінь і значення деяких змінних оточення, запустивши «бойовий» bash, але ми залишилися в хост-системі і всі пристрої нам доступні).

Тепер можна налаштувати доступ в мережу. У моєму випадку, при компіляції на ВМ, вона виходить в мережу через віртуальний NAT, тому потрібна наявність DHCP. Ми спеціально завантажили пакет dhcpcd, тепер ми зберемо його і встановимо в системі:

# tar-pxf dhcpcd-6.7.1.tar.bz2
# cd dhcpcd-6.7.1
# ./configure --libexecdir=/lib/dhcpcd --dbdir=/var/tmp
# make
# make install
# cd ..
# rm-rf dhcpcd-6.7.1/

Крім того, встановимо скрипти, необхідні dhcpcd для роботи:

# tar-pxf blfs-bootscripts-20150304.tar.bz2
# cd blfs-bootscripts-20150304
# make install-service-dhcpcd

Ну і, нарешті, створимо конфіг:

# vim /etc/sysconfig/ifconfig.eth0


C вмістом:

ONBOOT="так"
IFACE="eth0"
SERVICE="dhcpcd"
DHCP_START=""
DHCP_STOP=" k"

Зміст параметрів такий:

  • ONBOOT=«yes» — запуск служби при запуску системи
  • IFACE=«eth0» — отримання ip сервера на інтерфейс eth0
  • SERVICE=«dhcpcd» — запускається сервіс
  • DHCP_START="" — параметри запуску
  • DHCP_STOP=" k" — параметри зупинки (kill)


Створимо файл /etc/hostname, який пропишемо ім'я хоста:

echo "lfs" > /etc/hostname

Після цих операцій можна розраховувати на те, що після перезавантаження у нас підніметься мережу.

Тепер займемося налаштуванням init.

# vim /etc/inittab

Мануал пропонує наступний скрипт:

# Begin /etc/inittab

# Рівень запуску системи за замовчуванням - 3
id:3:initdefault:

# Ініціалізація системи (запускається при завантаженні системи)
si::sysinit:/etc/rc.d/init.d/rc S

# Запуск скрипта ініціалізації 
# для кожного рівня запуску

l0:0:wait:/etc/rc.d/init.d/rc 0
l1:S1:wait:/etc/rc.d/init.d/rc 1
l2:2:wait:/etc/rc.d/init.d/rc 2
l3:3:wait:/etc/rc.d/init.d/rc 3
l4:4:wait:/etc/rc.d/init.d/rc 4
l5:5:wait:/etc/rc.d/init.d/rc 5
l6:6:wait:/etc/rc.d/init.d/rc 6

# Реакція на натискання Ctrl + Alt + Del - перезавантаження
ca:12345:ctrlaltdel:/sbin/shutdown-t1-a-r now

# Скрипт запускається в однокористувальницькому режимі
su:S016:once:/sbin/sulogin

# Ініціалізація віртуальних терміналів
1:2345:respawn:/sbin/agetty --noclear tty1 9600
2:2345:respawn:/sbin/agetty tty2 9600
3:2345:respawn:/sbin/agetty tty3 9600
4:2345:respawn:/sbin/agetty tty4 9600
5:2345:respawn:/sbin/agetty tty5 9600
6:2345:respawn:/sbin/agetty tty6 9600

# End /etc/inittab

Рядки цього файлу складаються з чотирьох полів, розділених крапкою:

<id>:<runlevels>:action:process


  • id — ідентифікатор рядка — довільна комбінація, що містить від 1 до 4 символів. Допускається використання двох рядків з однаковими ідентифікаторами.
  • runlevels — рівні виконання, на яких задіюється дана рядок. Рівні перераховуються цифрами без всяких роздільників, наприклад 235 (працювати на 2, 3 і 5 рівнях)
  • process — процес, який має запускатися на зазначених рівнях (ім'я програми, що викликається на зазначених рівнях виконання)
  • action — дія, яка визначає додаткові умови виконання команди. Можливі значення

    • respawn — перезапуск процесу при його завершенні
    • once — виконати тільки один раз при переході на зазначений рівень

    • wait — запуск процесу і перехід init в режим очікування його запуску
    • sysinit — дії, виконувані init на самому початку, ще до переходу на рівень виконання. Процеси позначені таким чином запускаються до процесів позначених як boot і bootwait
    • boot — процес буде запущений на етапі завантаження системи незалежно від рівня виконання
    • bootwait — те ж саме що і boot, але з перекладом init в режим очікування виконання.
    • powerwait — дії, що виконуються при обриві харчування. Передбачає наявність UPS
    • ctrlaltdel — дія виконується по натисненню «трьох чарівних кнопок»
    • off — ігнорувати даний елемент
Для реалізації дій на різних рівнях виконання в LFS передбачається скрипт /etc/rc.d/init.d/rc, приймаючий в якості параметра рівень запуску.

Для виконання однокористувацького входу в разі збою завантаження викликається команда /sbin/sulogin, цей однокористувацький вхід і виконує.

Процес /sbin/shutdown запускається при зупинці/перезавантаження системи

/sbin/agetty — створює і ініціалізує віртуальний термінал.

Змінити рівень виконання можна в процесі роботи системи, давши команду від рута

# init <runlevel>

вказавши в якості параметра рівень запуску. Відома більшості команда halt це аліас на init 0, а команда reboot — аліас на init 6.

Дізнатися поточний рівень запуску, давши команду:

# runlevel

або:

# who-r

3. Годинник, локалізація та інші приємні дрібниці
Для вірної роботи системних годин створимо конфіг

/etc/sysconfig/clock
# Begin /etc/sysconfig/clock

UTC=1

# Set this to any options you might need to give to hwclock,
# such as machine hardware clock type for Alphas.
CLOCKPARAMS=

# End /etc/sysconfig/clock


Тут вказується, що апаратні годинник буде йти по універсальному всесвітнього часу, а поправку на временую зону ми вже внесли, коли налаштовували пакет GLibc.

Тепер необхідно правильно налаштувати консольний шрифт. Всі необхідні нам локалі ми встановили разом з GLibc. Нас цікавить кирилица, тому створюємо конфігураційний файл консолі в такому вигляді

/etc/sysconfig/console
# Begin /etc/sysconfig/console

UNICODE="1"
KEYMAP="us"
FONT="UniCyr_8x16"

# End /etc/sysconfig/console


  • UNICODE=«1» — вказуємо, що будемо використовувати локаль у кодуванні UTF-8
  • KEYMAP=«us» — розкладка консолі
  • FONT=«UniCyr_8x16 — задаємо кирилический консольний шрифт


Задамо локаль, налаштувавши профіль bash за замовчуванням

/etc/profile
# Begin /etc/profile

export LANG=ru_RU.UTF-8

# End /etc/profile


Для порядку слід так само „забиндить“ деякі клавіатурні настройки оболонкою і бібліотекою readline, отвественной за клавіатурний ввід

/etc/inputrc
# Begin /etc/inputrc

# Не виводимо нічого в першому рядку
set horizontal-scroll-mode Off

# Дозволяє 8-бітний enter
set meta-flag On 
set input-meta On

# Вимикаємо конвертацію 8-го біта
set convert-meta Off

# Залишаємо 8-ий біт для екрану
set output-meta On

# нічого, видимий або чутний
set bell-style none

# Все наступне - карта відповідностей escape-послідовностей значень, 
# містяться всередині першого аргументу, до специфічних функцій 
# readline

"\eOd": backward-word
"\eOc": forward-word

# for linux console
"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[3~": delete-char
"\e[2~": quoted-insert

# for xterm
"\eOH": beginning-of-line
"\eOF": end-of-line

# for Konsole
"\e[H": beginning-of-line
"\e[F": end-of-line

# End /etc/inputrc


Окрему увагу приділяти саме цьому конфіг не хочеться, тому детальний його розбір залишимо як домашнє завдання.

Наступний конфіг визначає імена оболонок, використання яких дозволено в системі

/etc/shells
# Begin /etc/shells

/bin/sh
/bin/bash

# End /etc/shells


На цьому первинна настройка системи закінчена, залишилося всього кілька останніх штрихів

4. Збірка ядра
Іронія полягає в тому, що збірка ядра — це менша частина всієї роботи. Йдемо в каталог /sources і розпаковуємо (в черговий раз) джерело:

# cd /sources
# tar-pxf linux-3.19.tar.bz2
# cd linux-3.19

Готуємо ядро до компіляції, перевіряючи дерево джерел:

# make mrproper

Необхідно згенерувати конфіг збірки ядра:

# make конфігураційного меню

Запуститься конфігуратор, знайомий багатьом не з чуток.

Що можна сказати про необхідної конфігурації. По-перше мануал по збірці LFS рекомендує перевірити установку наступної опції:



Підтримка монтування віртуальної файлової системи devtmpfs в /dev — динамічне створення файлів пристроїв пам'яті і монтування /dev на ранній стадії завантаження ядра.

Все інше залежить від вашої апаратної конфігурації і тих функцій, які ви б хотіли включити в ядро. Я, наприклад, додав лише повну підтримку NTFS, решту залишив за замовчуванням.

Зберігаємо конфіг як .config, виходимо з конфігуратора і збираємо ядро

# make

Встановлюємо модулі ядра:

# make modules_install

Копіюємо зібране ядро в каталог /boot, перейменувавши його:

# cp-v arch/x86_64/boot/bzImage /boot/vmlinuz-3.19-lfs-7.7

Зберігаємо map-файл і конфіг зібраного ядра:

# cp-v System.map /boot/System.map-3.19
# cp-v .config /boot/config-3.19

Доустанавливаем документацію:

# install-d /usr/share/doc/linux-3.19
# cp-r Documentation/* /usr/share/doc/linux-3.19

Створюємо конфіги для опціональною завантаження модулів, наприклад для підтримки USB:

# install-v-m755-d /etc/modprobe.d
# vim /etc/modprobe.d/usb.conf

/etc/modprobe.d/usb.conf
# Begin /etc/modprobe.d/usb.conf

install ohci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe-i ohci_hcd ; true
install uhci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe-i uhci_hcd ; true

# End /etc/modprobe.d/usb.conf

Прибираемся за собою:
# cd ..
# rm-rf linux-3.19/


5. Монтування файлових систем та налаштування завантажувача
Створюємо конфіг монтування /etc/fstab. У мене він виглядав ось так:

/etc/fstab
/dev/sda6 / ext4 defaults 1 1
/dev/sda2 swap swap pri=1 0 0
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
tmpfs /run tmpfs defaults 0 0
devtmpfs /dev devtmpfs mode=0755,nosuid 0 0


/dev/sda2 і /dev/sda6 — відповідно своп і кореневий розділ LFS-системи.

Так як я збирав LFS системи вже встановленої на HDD (Arch Linux), то для першої її завантаження я вважав за краще скористатися завантажувача Grub2 вже встановленому на жорсткий диск. Для налаштування я використовував конфіг для створення кастомного пункту завантажувального меню.

Виходимо із зібраної системи:

# loguot

І в хост-системі редагуємо файл:

/etc/grub.d/40_custom
#!/bin/sh
exec tail-n +3 $0
# This file provides an easy way to add custom menu entries. Simply the type
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.


menuentry "GNU/Linux, Linux 3.19-lfs-7.7" {

insmod=ext2
set root=(hd0,6)
linux /boot/vmlinuz-3.19-lfs-7.7 root=/dev/sda6 ro
}

Після чого перегенерируем конфіг завантажувача:

# grub-mkconfig-o /boot/grub/grub.cfg

І… перезавантажуємося:

# systemctl reboot

Якщо все гаразд і ми не помилилися, то з'явиться меню вибору ОС:



Вибираємо останній пункт нашої LFS-системи…



Так! Почалося завантаження, видно як піднімається мережний інтерфейс, чекаємо коли ми отримаємо ip і… екран логіна:



Логинимся як root:



І запускаємо що-небудь, що покаже нам правильну налаштування локалі:

# vim



Російська мова там де і має бути. Перевіряємо мережу:

# ping ya.ru

І спостерігаємо, як йде пінг:



Ну що ж,

Тепер, коли мета досягнута… Замість висновку
Ми спробували свої сили у складанні лінукса „з нуля“ (from scratch). І нам це вдалося. У нас є мінімальна працююча система, з якою можна робити все що завгодно — перенести на реальне залізо, спробувати перетворити в домашню систему. Можна помилуватися і забути, бо підтримувати домашню систему без пакетного менеджера досить важко.

Я робив це just for fun, отримав деякі нові знання, і в цілому залишився задоволений, чого бажаю і моїм читачам.

P. S.: зібрану мною систему завантажити тут. За посиланням — образ диска для VirtualBox. Параметри входу такі

login: root
пароль: 123456

login: maisvendoo
passwd: maisvendoo

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.