Что происходит, когда включается компьютер с ОС Linux? Как сделать загрузку Windows первой в Grub Изменение порядка загрузки Grub через терминал.

вторичного загрузчика схему с картой размещения . Это делает работу с LILO занятием, требующем повышенной аккуратности, так как изменение процедуры загрузки не атомарно : сначала пользователь изменяет ядро или его модули, потом - редактирует файл /etc/ lilo .conf , в котором содержатся сведения обо всех вариантах загрузки компьютера, а затем - запускает команду lilo , которая собирает таблицы размещения для всех указанных ядер и вторичного загрузчика и записывает первичный и вторичный загрузчик вместе с картами в указанное место диска. Первичный загрузчик LILO (он называется LI ) можно записывать и в MBR , и в начало раздела Linux.

Простейший файл lilo .conf может выглядеть так:

Boot=/dev/hda map=/boot/map image=/boot/vmlinuz-up root=/dev/hda1 Пример 10.1. Простейшая настройка LILO: пример файла lilo.conf

Такая настройка LILO определяет только один вариант загрузки: первичный загрузчик записывается в начало первого жесткого диска (строчка boot=/dev/ hda ), карту размещения утилита lilo записывает в файл /boot/map , ядро добывается из файла /boot/vmlinuz-up , а запись root=/dev/hda1 указывает ядру , что корневая файловая система находится на первом разделе первого диска.

Одна из машин, за которыми случалось работать Мефодию, использовалась иногда для запуска единственной программы, написанной для MS-DOS. Исходные тексты этой программы давно потерялись, автор - тоже, поэтому на машине пришлось устанавливать и MS-DOS и Linux. В результате lilo .conf оказался таким:

# cat /etc/lilo.conf boot=/dev/hda map=/boot/map default=linux-up prompt timeout=50 image=/boot/vmlinuz-up label=linux-up root=/dev/hda5 initrd=/boot/initrd-up.img read-only image=/boot/vmlinuz-up label=failsafe root=/dev/hda5 initrd=/boot/initrd-up.img vga=normal append=" failsafe noapic nolapic acpi=off" read-only other=/dev/hda1 label=dos other=/dev/fd0 label=floppy unsafe Пример 10.2. Настройка LILO на двухсистемной машине

Здесь Linux была установлена на пятый раздел диска (о нумерации разделов в IBM-совместимых компьютерах будет рассказано в лекции 11), а на первом находится MS-DOS. Кроме загрузки MS-DOS предусмотрено два варианта загрузки Linux и еще один - любой операционной системы с дискеты. Каждый вариант загрузки помечен строкой label=вариант . При старте LILO выводит простейшее 3Если установлен графический вариант интерфейса, то окно может быть сколь угодно изукрашенное. окошко, в котором перечислены все метки (в данном случае - " linux-up ", " failsafe ", " dos " и " floppy "). Пользователь с помощью "стрелочек" выбирает нужный ему вариант и нажимает Enter . При необходимости пользователь может вручную дописать несколько параметров , они передадутся ядру системы. Если пользователь ничего не трогает, то по истечении тайм-аута выбирается метка, указанная в поле default .

Еще несколько пояснений. Метки linux-up и failsafe в примере используют одно и то же ядро (vmlinuz-up ), но во втором случае перенастраивается режим графической карты и добавляются параметры, отключающие поддержку необязательных для загрузки аппаратных расширений (многопроцессорность, автоматическое управление электропитанием и т.п.). Строчку, стоящую после append= , пользователь мог бы ввести и самостоятельно, это и есть параметры ядра . Поле initrd= указывает, в каком файле находится стартовый виртуальный диск (ему посвящен раздел " Стартовый виртуальный диск и модули" этой лекции), а внушающая некоторые опасения надпись " unsafe " (для метки floppy ) означает всего лишь, что дискета - съемное устройство, поэтому бессмысленно во время запуска lilo проверять правильность ее загрузочного сектора и составлять карту .

Наконец, записи вида other=устройство говорят о том, что LILO неизвестен тип операционной системы , находящейся на этом устройстве, а значит, загрузить ядро невозможно. Зато ожидается, что в первом секторе устройства будет обнаружен еще один первичный загрузчик , LILO загрузит его и передаст управление по цепочке. Так и загружается MS-DOS на этой машине: первичный загрузчик берется (по метке dos ) из начала первого раздела первого диска.

GRUB

Подсистема загрузки GRUB устроена более сложно. Она также имеет первичный загрузчик , который записывается в первый сектор диска или раздела, и вторичный загрузчик , располагающийся в файловой системе . Однако карта размещения в GRUB обычно используется только для так называемого "полуторного" загрузчика ("stage 1.5") - по сути дела, драйвера одной определенной файловой системы . Процедура загрузки при этом выглядит так. Первичный загрузчик загружает полуторный по записанной в него карте размещения . Эта карта может быть очень простой, так как обычно полуторный загрузчик размещается непосредственно после первичного в нескольких секторах 4Т.е. на нулевой дорожке нулевого цилиндра, начиная с сектора 2. Эта область диска часто не используется под файловые системы (см. лекцию 11). подряд, или в ином специально отведенном месте вне файловой системы . Полуторный загрузчик умеет распознавать одну файловую систему и находить там вторичный уже по имени (обычно /boot/ grub /stage2 ). Наконец, вторичный загрузчик , пользуясь возможностями полуторного, читает из файла /boot/ grub /menu.lst меню, в котором пользователь может выбирать варианты загрузки так же, как и в LILO . Таким образом, обновление и перенастройка установленного GRUB не требует пересчета карт размещения и изменения чего-то, кроме файлов в каталоге /boot/ grub .

По требованию Мефодия Гуревич установил на двухсистемную машину GRUB . При этом файл /boot/ grub /menu.lst получился таким:

# cat /boot/grub/menu.lst default 0 timeout 50 title linux-up kernel (hd0,4)/boot/vmlinuz-up root=/dev/hda5 initrd (hd0,4)/boot/initrd-up.img title failsafe kernel (hd0,4)/boot/vmlinuz-up root=/dev/hda5 failsafe noapic nolapic acpi=off initrd (hd0,4)/boot/initrd-up.img title floppy root (fd0) chainloader +1 title dos root (hd0,0) chainloader +1 Пример 10.3. Настройка GRUB на двухсистемной машине

Разница между lilo .conf только в синтаксисе, да еще в том, что жесткие диски и разделы на них GRUB именует по-своему, в виде (hdномер_диска , номер_раздела ), причем нумеровать начинает с нуля. Метки (" title ") тоже нумеруются с нуля, так что запись default 0 означает, что по истечении тайм-аута будет загружена самая первая конфигурация (по имени " linux-up ").

Изучая руководство по GRUB , Мефодий обнаружил гораздо более важное отличие от LILO . Оказывается, в GRUB не только параметры, но и сами файлы (ядро , стартовый виртуальный диск и т.п.) распознаются и загружаются в процессе работы. Вместо пунктов меню можно выбрать режим командной строки , подозрительно похожий на bash , в котором можно заставить GRUB загрузить какое-нибудь другое, не предписанное конфигурацией, ядро , посмотреть содержимое каталогов файловой системы , распознаваемой полуторным загрузчиком , и даже содержимое этих файлов, невзирая ни на какие права доступа: система-то еще не загружена. Мало того, можно по-своему перенастроить загрузчик и записать результаты настройки. Так и не успев насладиться неожиданной свободой, Мефодий в один прекрасный день обнаружил, что выход в командную строку защищен паролем.

Действия ядра Linux в процессе начальной загрузки

Итак, проходит в три этапа.

  1. Загрузчик из ПЗУ определяет, с каких устройств можно грузиться и, возможно, предлагает пользователю выбрать одно из них. Он загружает с выбранного устройства первичный загрузчик и передает ему управление.
  2. Первичный загрузчик определяет (а чаще всего - знает), где находится вторичный загрузчик - большая и довольно интеллектуальная программа. Ему это сделать проще, чем программе из ПЗУ : во-первых, потому что для каждого устройства первичный загрузчик свой, а во-вторых, потому что его можно легко изменять при изменении настроек загружаемой системы. В схеме, предлагаемой LILO и GRUB , первичный загрузчик не вступает в разговоры с пользователем, а немедленно загружает вторичный и передает ему управление.
  3. Вторичный загрузчик достаточно умен, чтобы знать, где находится ядро системы (возможно, не одно), предложить пользователю несколько вариантов загрузки на выбор, и даже, в случае GRUB , разрешает задавать собственные варианты загрузки. Его задача - загрузить в память ядро и все необходимое для старта системы (иногда - модули, иногда - стартовый виртуальный диск ), настроить все это и передать управление ядру .

Ядро - это и мозг, и сердце Linux. Все действия, которые нельзя доверить отдельной подзадаче (процессу) системы, выполняются ядром . Доступом к оперативной памяти, сети, дисковым и прочим внешним устройствам заведует ядро . Ядро запускает и регистрирует процессы, управляет разделением времени между ними.

Загрузка операционной системы, это многоступенчатый процесс. В различных дистрибутивах Linux процесс загрузки может несколько изменяться, но общая схема примерно одинакова и состоит из следующих стадий:

    В момент запуска процессор передаёт управление по определённому физическому адресу в ПЗУ. В этот момент начинается выполнение кода BIOS/UEFI. Производится инициализация оборудования и выбирается загрузочный носитель. В случае BIOS происходит считывание в ОЗУ начального загрузчика и передача управления на него. Начальный загрузчик обычно занимает один сектор на диске (MBR) и ограничен размером 384 байт (512 байт – сектор диска, минус 128 байт – таблица разделов). В зависимости от типа загрузочного устройства загрузочный сектор может считываться из разных мест:

    • При загрузке с дискеты или HDD загрузчик читается из первого сектора физического носителя;
    • При загрузке с CD/DVD – из первого сектора образа загрузочного диска, размещённого в структуре данных CD;
    • При сетевой загрузке – из первого сектора образа загрузочного диска, скачиваемого с сервера по протоколу tftp.

    При форматировании диска в MBR вместо загрузчика иногда пишется программа, которая пишет на экране информационный текст "No bootable device -- insert boot disk and prress any key"

1.1 Начальный загрузчик считывает в память основной загрузчик (GRUB, LiLo, NTLDR) и передаёт управление ему. Поскольку начальный загрузчик очень мал, то, как правило, в его код жестко прописывают сектора, из которых надо прочитать код основного загрузчика. На HDD это может быть пространство между MBR и первым разделом на диске (нулевая дорожка) или зарезервированное место внутри ФС (зарезервированный Inode в ext2fs). На дискете и при использовании образа диска при загрузке с CD или по сети – основной загрузчик может располагаться сразу вслед за первичным загрузчиком и занимать весь объём образа.

При загрузке через UEFI загрузчик считывается целиком из файла на специальном разделе.

    Загрузка ядра (vmlinuz) и вспомогательного образа диска (initrd, initramfs). Загрузчик GRUB представляет из себя мини ОС, поддерживающую все основные файловые системы. GRUB ищет конфигурационный файл, в котором прописаны пути к образу ядра и образу вспомогательного диска. При необходимости образ ядра распаковывается в ОЗУ, формируется область памяти, содержащая параметры, передаваемые из загрузчика в ядро, в том числе адрес образа вспомогательного диска.

    Ядро загружаемое через GRUB должно соответствовать соглашениям multiboot или multiboot2 . В соответствии с соглашением, образ ядра включает структуру (например в секции данных), которая начинается с магического числа и содержит информацию о желаемом положении ядра в памяти и точке на которую надо передать управление. Перед передачей управления в ядро в регистр EAX помещается ещё одно магическое число, а в регистр EBX - адрес таблицы с параметрами, подготовленными загрузчиком.

    Вспомогательный диск необходим современным Linux системам из-за модульности ядра и содержит драйверы (ATA, NFS, RAID и т.п.), необходимые для получения доступа к основной файловой системе. Внутри образа находится файловая система в формате архива cpio.

    На этом этапе создаётся процесс с pid=1 , в котором происходит выполнение скрипта init , находящегося в корневом каталоге вспомогательного диска. Параметры, передаваемые ядру, фактически передаются в init , как аргументы командной строки.

    Скрипт содержит команды загрузки необходимых драйверов в виде модулей ядра, создание временных файлов устройств в каталоге /dev для доступа к этим модулям, сканирование дисковых разделов для обнаружения и инициализации RAIDов и логических томов. После инициализации логических дисков, делается попытка смонтировать корневую файловую систему, заданную параметром root= . В случае бездисковой сетевой загрузки корневой каталог подключается по NFS.

    На экран выдаются сообщения о загрузке драйверов и о поиске виртуальных томов подсистемы LVM. Этап завершается перемонтированием корневого каталога на основную файловую систему и загрузку в процесс с pid=1 основной программы /sbin/init (или её аналога).

    В классическом UNIX"е и старых версиях Linux (примерно до 2012 года) программа init считывает конфигурационный файл /etc/inittab , инициализирует текстовые консоли и, как правило, запускает необходимые службы с помощью набора скриптов, расположенных в каталогах /etc/init.d и /etc/rc*.d . В современных дистрибутивах Linux в файле /sbin/init находится более современная программа запуска служб. Наиболее популярной из подобных программ является systemd , который позволяют существенно сократить время этого этапа загрузки.

На экран на этом этапе выдаются строки, сообщающие о запуске служб, и информация об успешности данного процесса ( или ).

Загрузчик GRUB

Загрузиться с установочного диска в режим восстановления - Rescue mode. Для этого в момент загрузки на приглашение boot: необходимо ввести linux rescue

Если всё пойдёт нормально, то корневой каталог основной системы будет смонтирован в /mnt/sysimage , загрузочный каталог в /mnt/sysimage/boot . Кроме того текущие каталоги /proc , /sys и /dev будут смонтированы в соответствующие подкаталоги /mnt/sysimage . Если это не случится, то придётся проделать эти операции вручную.

Когда все каталоги смонтированы, можно сменить корневой каталог

#если выяснится, что вы что-то забыли смонтировать, то можно выйти по ^D chroot /mnt/sysimage

и пересобрать initrd

#копируем старый файл cp -p /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.bak #создаём новый dracut -f #если версия ядра в основной системе отличается от версии на установочном диске, указываем её явно dracut -f /boot/initramfs-2.6.32-358.el6.x86_64.img 2.6.32-358.el6.x86_64

#копируем старый файл cp -p /boot/initrd-$(uname -r).img /boot/initrd-$(uname -r).img.bak #создаём новый mkinitrd -f -v /boot/initrd-$(uname -r).img $(uname -r) #если версия ядра в основной системе отличается от версии на установочном диске, указываем её явно mkinitrd -f -v /boot/initrd-2.6.18-371.el5.img 2.6.18-371.el5

Cd / sync telinit 6

Полный пример с драйвером i2o_block (SCSI адаптер Adaptec 2010S), который не загружается автоматически. Пример выполняется в CentOS 5, поскольку в стандартном ядре CentOS 6 поддержка этого драйвера отключена.

После загрузки с CD в Rescue mode выдаётся сообщение, что Linux разделы не найдены и их надо монтировать самостоятельно.

#Загружаем драйвер insmod i2o_block #Проверяем, что всё сработало lsmod .... dmesg ... #Создаём файлы устройств на основе информации в dmesg mkdir /dev/i2o mknod /dev/i2o/hda b 80 0 mknod /dev/i2o/hda1 b 80 1 mknod /dev/i2o/hda2 b 80 2 #Активируем VolumeGroup lvm vgchange -a y #Монтируем тома mkdir /mnt/sysimage mount /dev/mapper/VolGroup00-LogVol00 /mnt/sysimage mount /dev/i2o/hda1 /mnt/sysimage/boot #Монтируем спецкаталоги mount --bind /proc /mnt/sysimage/proc mount --bind /dev /mnt/sysimage/dev mount --bind /sys /mnt/sysimage/sys

Далее по инструкции, только при создании образа диска надо указать программе mkinitrd дополнительную опцию --preload=i2o_block и отключить сервисы readahead , поскольку они приводят к зависанию драйвера i2o_block:

Chkconfig early-readahead off chkconfig later-readahead off

В прошлый раз мы говорили о том, что происходит при загрузке Linux: вначале стартует загрузчик, он загружает ядро и развертывает временный диск в оперативной памяти, ядро запускает процесс init, init находит настоящий корневой диск, производит такой хитрый переворот - вместо временного виртуального диска на это же самое место в корневой каталог монтируется реальный диск, с этого реального дисков процесс init загружает в себя другой init, который есть на этом реальном диске. После всех этих операций UNIX переходит в состояние обычной работы.

В этой лекции я расскажу, что делает классическая программа init в сочетании со скриптами rc.d в стиле System V (Систем пять). System V - это классическая версия UNIX на которой построены коммерческие UNIX.

Судя по названию, rc.d это некий каталог. Есть такая традиция UNIX - если вся конфигурация чего-либо умещается в один файл, и он называет config, то при разбиении его на отдельные файлы, которые подключаются к основному, создают каталог с аналогичным именем и добавляют к имени.d – config.d. Буква d означает, что это директория и там лежат вспомогательные части конфигурационного файла. У формата конфигурационных файлов программы init есть две традиции: вариант System V, в котором каждая деталь конфигурации держится в отдельном файле в каталоге rc.d, и традиция BSD систем, в которой есть один файл /etc/rc, содержащий много скриптов и переменных, которые отвечают за поведение системы.

В любом случае, при старте системы у нас создается процесс с PID=1, в котором запущена программа, которая называется init. Как вы видели в прошлый раз, если программу init убить, то ядро впадает в панику и прекращает всяческую работу.

Классический System V init читает файл /etc/inittab и выполняет ряд предписаний, которые прописаны в этом файле. Inittab этот текстовый файл каждая строка которого, это, по сути дела, одна команда или какое-то правило поведения. Inittab выглядит так:

id:3:initdefault:

si::sysinit:/etc/rc.d/rc.sysinit

l3:3:wait:/etc/rc.d/rc 3

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

Вначале строки стоит метка. В чем большой смысл этой метки я не очень понимаю. Можно считать, что это простой текст и все. Вторым пунктом стоит либо так называемый уровень загрузки, либо пустое значение. Уровень загрузки - это либо одно число от 0 до 6, либо список чисел через запятую. Дальше идет некое действие. Действия бывают следующие: wait, respawn, sysinit, ctrlaltdel. Есть и другие действия, но это самые используемые. Наконец, в конце строки написана некая команда с именем исполняемого файла и аргументов, которые этой команде надо передать.

Действие sysinit выполняется однократно при старте системы.

Действие ctrlaltdel это на самом деле не совсем действие – это обработчик сочетания клавиш control alt del. Само нажатие перехватывается ядром системы, и информация об этом пересылается в процесс init, который должен выполнить определенную команду. Например, может быть выполнена команда shutdown, которая выполнит выключение компьютера. В принципе сюда можно прописать любую другую программу, например, echo, которая после нажатия control alt del будет выдавать на все терминалы системы какое-нибудь сообщение. камина консолью так

Действие wait означает, что необходимо запустить команду, дождаться пока она закончится и только после этого продолжить обработку следующих строк. Не знаю, могут ли запускаться такие действия в параллель. Скорее всего, нет.

Действие respawn означает, что надо запустить программу и не дожидаясь ее завершения, перейти в дальнейшем действиям. Если эта программа в последующем завершится, то необходимо ее рестартовать.

Итак, есть однократное выполнение с ожиданием результатов и многократное выполнение в асинхронном режиме – запустились, дождались пока закончить, запустили слова.

Уровни загрузки - это некая условность, которая позволяет управлять загружаемыми службами. Ближайший аналог в windows – это загрузка в безопасном режиме, когда грузится только ограниченное число драйверов и стартует минимальное количество служб, загрузка с отладкой, когда каждое действие дополнительно протоколируются и обычная полноценная загрузка.

В Linux по традиции выделяется 6 вариантов загрузки. Это деление довольно условно.

0 и 6 это выключение. 0 - полное выключение электричество, а 6 - режим перезагрузки.

4 в Linux вообще пропущен

Остаются четыре уровня загрузки:

1 - однопользовательский режим. Если передать загрузчику ключевое слово single, то мы окажемся в однопользовательском режиме, где запущен только один процесса и это шелл администратора системы. Этот режим используется для восстановления системы.

3 - нормальный многопользовательский текстовый режим, когда запущены все службы, работает сеть, работают все драйверы.

2 - тоже текстовый режим, но без подключения сетевых дисков. Дело в том, что традиционные сетевая файловая система nfs, которая используется в UNIX, чрезвычайно устойчива к повреждениям сети. Если мы выключили файловый сервер или обрезали сетевой кабель, то сетевая файловая система nfs будет предпринимать многочисленные попытки восстановиться и эти попытки настолько длительны, что я ни разу не смог дождаться времени, когда же наконец появится сообщение об ошибке. Возможно это произойдёт через час, а может и через 6 часов. Всё это время драйвер nfs будет держать компьютер, не давая ничего сделать. Поэтому, если у нас упала сеть или файловый сервер в настройках написано, что при старте необходимо подмонтировать внешние диски, то попытка загрузится в полноценный режим приведёт к тому, что у вас все зависнет. Для этого случая и предусмотрен второй вариант загрузки - все как в третьем, только сетевые диски не подключаются. Сам сетевой адаптер работает, IP адрес назначается, интернет доступен.

5 - то же самое что и 3, но с запуском x window - графического интерфейса.

режим 2 включает себя 1 + многопользовательский режим. 3 включает 2 + монтирование сетевых файловых систем. Наконец, 5 включает в себя 3 + запуск графической подсистемы. Будет ли это реализовано последовательно или нет - это проблема дистрибутива. Вообще говоря, администраторы могут самостоятельно настроить файл inittab так, чтобы эти режимы запускались последовательно, а можно сделать так чтобы все было абсолютно независимо - переключаясь в очередной режим, убираем все что было сделано на предыдущем шаге, и настраиваем все с нуля.

Рассмотрим строки реального файла. Они очень просты.

l3:3:wait:/etc/rc.d/rc 3

Запускается какая-то программа, которая должна выполнить все необходимые действия, которые ожидаются на третьем уровне. Наверно, на третьем уровне нужно настроить сетевые интерфейсы, запустить драйвер терминалов, стартовать какие-то службы. Только после того, как всё этого завершится мы сможем работать в системе. Поскольку надо дождаться завершения запуска, мы выбираем действие wait.

Программа запуска называется rc и запускается с номером уровня в качестве параметра. Сама программа init достаточно простая. Она умеет построчно читать свой файл с простым синтаксисом и стартовать новые процессы, запуская какие-то вспомогательные программы. Вся логика уровней загрузки спрятана в скрипте rc. Запустив rc с параметром 3 мы перейдем на третий уровень, с параметром 5 - на пятый.

Программа rc тоже очень простая. Это скрипт который выполняет все файлы в каталогах, соответствующих уровню загрузки, например, /etc/rc3.d/. В этих каталогах находятся исполняемые файлы, которые принимают один параметр - либо start, либо stop. Если файл запущен с параметром start, то он стартует службу, если с параметром stop, то останавливает её. Например, network start будет настраивать сетевые интерфейсы, а network stop будет переводить интерфейсы в выключенное состояние. Кроме сетевых интерфейсов есть скрипты подключения/отключение сетевых файловых систем, запуска/остановки сервисов и т.д.

Имена файлов в каталогах построенным по определенным правилам. Они начинаются либо с буквы K либо с буквы S, за которыми идет число и имя службы.

Скрипт rc просматриваем содержимого каталога rc3 и выбирает оттуда все файлы которые начинаются с буквы K (kill). Файлы упорядочиваются в порядке возрастания номера и выполняются с параметром stop. Потом те же действия выполняются с файлами на букву S (start), которые запускаются с параметром start. Вот в общем и вся процедура перехода на определенный уровень.

Можно предположить, что в каталоге /etc/rc0.d/ лежат только файлы, начинающиеся на букву K, поскольку при выключении надо все остановить, а в каталоге /etc/rc1.d/ будет один файл на буку S для запуска консоли администратора.

Для простоты программирования есть отдельный каталог /etc/init.d/, в котором лежат те же самые файлы только без буквы цифр в начале имени. На самом деле, файлы в каталогах уровней это просто символические ссылки на основные файлы. Так /etc/rc3.d/S10apache это ссылка на файл /etc/init.d/apache. Буквы и цифры в названии ссылок нужны для того, чтобы скрипт rc вызвал их в нужном порядке и с нужными аргументами.

В системах, которые построены по такому принципу, чтобы стартовать или остановить какую-либо службу в каталоге /etc/init.d/ надо найти файл который, который ей соответствует, и запустить его с параметром start или stop. Чем не нравится запускать службы именно таким способом - явно вызывая скрипты. Дело в том, что в командной строке linux замечательно работает автодополнение. С его помощью очень быстро можно ввести путь до файла запуска.

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

Программа chkconfig позволяет манипулировать символическими ссылками на соответствующие скрипты. Чтобы посмотреть, что стартует, а что останавливаться на каждом из уровней можно воспользоваться командой ls и выдать список скриптов в соответствующем каталоге, но проще воспользоваться командой chkconfig –list. Программа chkconfig пробегает по всем каталогам rc и выдает список того что стартует, а что останавливается на каждом уровне. Если мы хотим, чтобы при старте системы у нас что-то автоматически стартовала определенная службу мы выполняем chkconfig <имя службы> on и скрипт создает ссылку для запуска в нужном каталоге и с правильным именем. Запуск chkconfig <имя службы> off приводит к удалению ссылки для запуска и созданию ссылки для остановки. Таким образом программа chkconfig позволяет управлять списком служб, которые стартуют в момент старта системы.

Ещё одна программа - service используется для ручного запуска и остановки служб. Service это обертка, которая позволяет не обращаться напрямую к скрипту, а указать имя службы и сказать хотим мы ее стартовать или остановить. В bash, который я использую, нет автодополнения для команды service, поэтому мне проще набрать путь к скриптам.

В стартовых скриптах аргументы start и stop должны обрабатываться обязательно. Кроме того, можно придумать какие-то свои аргументы, которые будут делать что-то полезное.

В большинстве скриптов реализована опция status, которая показывает запущена служба или нет. Когда мы выполняем start, то скрипт после успешного запуска службы получает ее идентификатор PID и записывать его в определенный файл. По команде stop файл удаляется. Обычно такие файлы создаются в каталоге /var/run/. Команда status проверяет есть ли такой файл. Его нет, то сообщает, что служба не запущена. Если файл есть, то она извлекает из него идентификатор процесса и проверяет текущий список процессов. Если этот идентификатор присутствует все запущено, если программа по каким-то причинам поломалась, то статус выдаёт, что была сделана попытка запустить эту службу - файл существует, но сама служба не запущена.

Опция restart последовательно выполняет внутри скрипта две команды – сначала stop, а потом старт. Это совершенно необязательная команда - просто удобная. Наконец, есть службы, которые позволяет на ходу перечитать какие-то конфигурационные файлы. Для них добавляют команду reload, задачей которой является отправка службе сигнала о том, что конфигурация изменилась. Отдельный случай, команды save и load для сохранения конфигурации брандмауэра.

Если администратор системы вместо остановки или старта отдельных службы хочет всю систему перевести на определенный уровень, то этого можно достичь одним из двух способов. Можно вызвать прямо программу /sbin/init. Если ее вызвать с определенным числом в качестве параметра, то она выполнит все инструкцию из файла inittab, для которых прописывал соответствующий уровень. Если запустить, например, /sbin/init 1, то init найдет в своем конфигурационном файле все строчки, в которых есть уровень 1 и выполнит их. В некоторых системах команда shutdown реализована как /sbin/init 0, поскольку нулевой уровень соответствует остановке системы. В последнее время для перехода между уровнями появилась специальная программа под названием telinit, которая является ссылкой на init. Её задача – переслать процессу init сигнал о том, что администратор желает перейти на определенный уровень. telinit q сообщает init о том, что надо перечитать файл inittab. В старых системах это достигалось посылкой сигнала SIGHUP процессу с PID=1 (kill –HUP 1).

Ещё несколько строк в inittab, это запуск терминалов

1:2345:respawn:/sbin/mingetty tty1

Для того, чтобы обеспечить диалоговую доступ к системе, вы inittabе может присутствовать некоторое количество строчек такого рода. 2345 это уровни, на которых надо запускать команду, respawn означает, что программу надо перезапускать в случае завершения. Программа getty – это программа управления терминалом. Традиционно терминал в UNIX называется телетайпом, поскольку первыми терминалами были электрические пишущие машинка. Соответственно, tty это сокращение от телетайпа. Mingetty – программа, которая умеет работать с виртуальными терминалами на персональном компьютере. Она умеет настраивать драйвер терминала, а в качестве параметров получает имя устройства терминала, который надо настроить. В каталоге /dev/ есть файл устройства tty1, который соответствует первому виртуальному терминалу. Если бы у нас был модем и мы хотели бы инициализировать его момент загрузки, то могли бы вызвать getty с параметром ttyS0, который соответствует порту COM1. При инициализации модема можно было бы задать дополнительные параметры: скорость соединения 19200 бод, 7 или 8 бит в байте, четность, количество стоп-битов.

S0:2345:respawn:/sbin/getty ttyS0 19200 8 n 1

В прошлый раз я рисовал цепочку, в которой процесс вызовом fork делаются свою копию, дочерняя копия вызовом exec загружает в свою память другую программу, а после завершения сообщает об этом родительскому процессу.

Текстовые пользовательские сеансы устроены на таких цепочках: сначала init делает свою копию и запускает в ней программу mingetty. Mingetty инициализирует терминал и клавиатуру, а потом запускает в том же процессе программу login. Login выводит на экран приглашения на ввод имени и пароля и, если все прошло успешно то назначает себе привилегии пользователя и в том же процессе, затирая самого себя, запускает интерпретатор пользователя, например, bash. Когда пользователь набирает команду exit, то интерпретатор завершает жизненный путь этого процесса. Когда процесс завершается, init получает об этом сигнал. Init смотрит, что полагается делать, видит действие respawn, снова запускает программу mingetty, которая заново инициализирует терминал и все повторяется. Таким образом каждый сеанс находится внутри одного процесса. Как только мы вышли из сеанса наш процесс закончился и тотчас же запустилась программа, которая почистит за нами терминал и восстановит все настройки по умолчанию.

В файле inittab есть есть ещё одно специальное ключевое слово initdefault - уровень по умолчанию. Если через ядро init получил параметр single, то мы загрузимся на уровень 1. Если через загрузчик ничего не передали, то используется значение по умолчанию. Если после установки графической оболочки оказалось, что наш компьютер слабоват для графики, то можно установит уровень по умолчанию на 3, и после следующей перезагрузки мы попадаем на третий уровень - то есть в текстовый режим. Установили систему без графического режима, потом доустановили все пакеты для x window, поменяли уровень по умолчанию на 5 и после следующей перезагрузки попали сразу в графический режим.

В этой системе скриптов иногда хочется сделать что-то свое, например, при старте удалить все файлы в каталоге /tmp/. Для этого есть отдельный файл под названием /etc/rc.local, который запускается после всех остальных. Это просто скрипт без параметров, в который можно прописать всё, что угодно. Например, на одном из моих роутеров в момент старта системы в этом файле прописываются таблицы маршрутизации. Мне было лень искать где находятся соответствующие стандартные скрипты из дистрибутива и проще оказалось прописать команды в rc.local.

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

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

Надо сказать, что задачи на устранение различных неисправностей при загрузке системы часто встречаются в различных экзаменах на сертификацию по направлениям ОС.

Первым делом после включения компьютера происходит выполнение специального кода запуска, который представлен в виде базовой системы ввода-вывода (BIOS). Системе BIOS известна почти вся конфигурация железа. Есть сведения с какого устройства считывать первые 512 байт (MBR).

Именно в MBR (Master Boot Record) хранится программа первичной загрузки (stage 1), в которой содержится информация о том, в каком месте диска расположена программа вторичной загрузки (stage 2), которая загружает саму операционную систему.

Таким загрузчиком в нашем конкретном примере является GRUB (Grand Unified Boot Loader). Есть и промежуточный этап (так называемый stage 1.5), помогающий загрузчику ОС определить особые параметры файловой системы. Эта подпрограмма используется, если загрузчик GRUB не был установлен прямо в MBR.

После получения управления GRUB отображает список операционных систем (Linux/Windows и различных версий ядра Linux), если они доступны. В ином случае управление переходит на командную строку GRUB.

Предположим, что всё идёт как надо и мы выбрали нужную нам операционную систему (или версию ядра). В этом случае GRUB переходит к своему любимому делу – загружает саму операционную систему.

Вся информация о ходе процесса загрузки выводится на экран (если в опциях загрузки ядра отсутствует параметр quiet ), а так же в журнальный файл /var/log/dmesg . Просмотреть который можно непосредственно, либо используя утилиту dmesg .

По выводу служебной информации можно сделать выводы о параметрах оборудования и программного обеспечения, таких как версии ядра ОС, количество оперативной памяти, количество и характеристики процессоров, жесткие диски и соответствующие им разделы, сетевые карты, файл подкачки и многое другое.

Анализ этой информации в случае невозможности загрузки ОС может пролить свет на возникшую проблему, поэтому этот файл считается достаточно важным для траблшутинга.

Когда ядро системы загружено, производится базовая настройка необходимых устройств, подсистемы LVM и RAID и диск в оперативной памяти initrd, позволяющий загрузить необходимые драйверы.

Дальнейшие действия по загрузке процессов сильно отличаются в зависимости от версии ОС. В RHEL5 используется традиционный процесс загрузки служб SysV. В RHEL6 уже есть частичное распараллеливание загрузки процессов, причем по необходимости, а не все подряд. В новых версиях RHEL (с версии ядра 3.0) процесс ещё больше оптимизирован за счёт использования программы systemd, так же как в Fedora с 15-ой версии. В этом случае используется асинхронный режим работы, ускоряющий загрузку ОС.

Передав управление процессу init ядро переходит в особый режим и принимает обращения всех процессов через специальный универсальный интерфейс системных вызовов. На этом загрузку Linux можно считать завершенной.

Вам так же понравится:

Операционная система Linux Курс лекций. Учебное пособие Исправляем брешь CVE-2015-0235 в Linux

Linux как и любая другая операционная система загружается в несколько основных этапов: -> Досистемная загрузка -> Первичный загрузчик Linux -> Вторичный загрузчик -> Загрузка пользовательского пространства (INIT ).

Такой подход нужен в связи с тем, что операционная система — это логически сложная структура, следовательно её загрузка довольно таки сложна для компьютера. Исходя из такой сложности и непонятности появилась идея разбить процесс загрузки ОС на более элементарные этапы. Первый этап самый простецкий и легковесный для компьютера, а последний самый большой и тяжёлый.

Рассмотрим досистемную загрузку

Задача досистемной загрузки — выбрать как загружать ядро операционной системы .

То, как именно загрузить ядро пользователь может выбрать самостоятельно. Для того, чтобы выбрать нужна специальная система управления. Такую систему управления принято называть загрузчик . В Linux наиболее популярными и часто используемыми загрузчиками являются загрузчик LILO (Linux Loader) и загрузчик GRUB (Grand Unified Bootloader) . Они предоставляют пользователю возможность выбрать заранее настроенный тип загрузки. Оба эти загрузчика имеют текстовый (консольный) и графический варианты интерфейса. Основная и ключевая задача таких загрузчиков: загрузить в память компьютера ядро и всё необходимое для успешного старта системы.

В этих настройках можно выбрать стандартную загрузку ОС Linux, можно вызвать системную утилиту (небольшую программу специального назначения), прописать какие программы активировать при загрузке операционной системы и многое многое другое.

Таким нехитрым образом мы разобрались с «загрузчик ядра ОС Linux «!

Лучший способ понять, как работает операционная система Linux, - это проследить поэтапно ее загрузку. Именно во время загрузки запускаются все те механизмы, что приводят ОС в движение. Процесс этот сложный, многоступенчатый и порой запутанный. Изучать его интересно, а открытия, которые вы сделаете при этом, могут сильно вас удивить.

В целом загрузку Linux дистрибутива можно разделить на 5 этапов:

  1. Загрузчик.
  2. Запуск и начальная инициализация ядра.
  3. Обнаружение оборудования, загрузка драйверов и подключение файловых систем.
  4. Запуск системных служб (демонов).
  5. Старт графической или консольной пользовательской сессии.

Мы пройдемся по всем стадиям и узнаем, что происходит во время загрузки типичного дистрибутива Linux, немного отклонившись в сторону BSD, macOS и Android по пути. Во многих случаях это позволит понять, почему процесс загрузки Linux именно такой, какой есть.

1. Загрузчик

Все начинается с загрузчика, которому во время старта машины BIOS передает управление. В старые времена, когда Linux был не так популярен, в качестве загрузчика использовался LILO (Linux Loader) - простой, очень примитивный и не позволяющий менять конфигурацию загрузки на лету. Фактически конфигурационный файл был вшит в сам загрузчик, и его приходилось переустанавливать после каждой смены настроек: обновил ядро, забыл переустановить, и твой ноутбук больше не грузится.

Сегодня загрузкой Linux практически в любом дистрибутиве занимается Grub, изначально разработанный для операционной системы GNU/Hard. Grub гораздо сложнее LILO и фактически сам является полноценной ОС. Он не просто читает конфиг загрузки (обычно это /boot/grub/grub.cfg) прямо с диска, но и позволяет исправить этот конфиг на месте. Grub имеет встроенную командную строку, работает с десятком различных файловых систем и позволяет формировать сложные цепочки загрузки.

Как только пользователь выбирает нужный пункт меню (либо по истечении тайм-аута), Grub находит связанный с этим пунктом меню образ ядра Linux на диске (обычно это файл /boot/vmlinuz), а также закрепленный за ним образ initramfs (о нем чуть позже), загружает их в память и передает управление ядру.

Чтобы увидеть меню Grub в Ubuntu, необходимо удерживать Shift

2. Ядро и initramfs

Получив управление, ядро начинает первичную инициализацию: запускается подсистема управления памятью, настраивается обработчик прерываний, инициализируются необходимые для дальнейшей работы ядра структуры данных. Когда эта работа будет закончена, ядро распаковывает архив initramfs (обычно он имеет имя вида /boot/initramfs-linux.img и представляет собой архив cpio, сжатый с помощью gzip) в файловую систему в оперативной памяти (tmpfs), делает ее корневой файловой системой и запускает скрипт /init (в различных дистрибутивах имя может отличаться).

Initramfs включает в себя базовый набор компонентов Linux-дистрибутива: стандартные системные каталоги /bin, /lib, /etc и так далее, простейший командный интерпретатор (обычно ash), набор команд BusyBox, несколько вспомогательных библиотек и набор модулей ядра (драйверов), предназначенных для работы с различными накопителями и файловыми системами.

Этапы загрузки Linux. Содержимое initramfs.

Смысл существования initramfs в том, чтобы решить проблему курицы и яйца: загрузить драйверы для подключения реальной корневой файловой системы до того, как она будет подключена. Именно это и происходит, когда система запускает скрипт /init. Он определяет установленные в систему накопители, загружает в ядро драйверы для работы с ними, а затем подключает нужный раздел нужного накопителя (о том, какой именно, ядро узнает благодаря переданному при загрузке параметру root) к корню, перекрывая таким образом содержимое initramfs. Затем скрипт запускает /sbin/init, с которого и начинается следующий шаг загрузки ОС.

Загрузка Linux. Скрипт init из initramfs.

3. Первичная инициализация

После того как скрипт /init из initramfs заканчивает свою работу, он запускает утилиту /sbin/init реальной файловой системы. С этого момента начинается инициализация самой ОС: загрузка необходимых драйверов, подключение файловых систем и разделов подкачки, настройка сетевых интерфейсов и запуск системных служб.

Исторически /sbin/init была очень простой утилитой, которая занималась только тем, что передавала управление определенным скриптам в зависимости от переданного ей параметра (скрипты располагались в каталогах /etc/rcX.d/, где X - уровень загрузки). Каждый скрипт отвечал за строго определенную операцию: один подключал перечисленные в файле /etc/fstab файловые системы, другой конфигурировал сетевые интерфейсы, еще один запускал демон cron (он занимается запуском периодических задач), еще один - демон syslog (он отвечает за прием журнальных сообщений и их запись на диск) и так далее. Этот стиль инициализации получил имя SystemV по имени версии UNIX, в которой он появился.

Достоинство стиля инициализации SystemV в его крайней простоте: его легко понять, его легко реализовать, с ним просто работать. Однако он абсолютно не подходит к современным реалиям.

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

Чтобы обойти эти проблемы, разработчики macOS в свое время создали альтернативу /sbin/init под названием launchd. Это без преувеличения гениальная разработка - launchd не только умеет контролировать жизненный цикл служб, но и запускает их лишь тогда, когда эти службы становятся нужны. Причем делает это весьма неординарным образом.

О том, как это происходит, мы еще поговорим. Сейчас в истории с launchd нас интересует другое, а именно то, что под его впечатлением был создан тот самый systemd. Сегодня systemd - часть большинства дистрибутивов Linux. Он гораздо сложнее /sbin/init и даже launchd, а в его конструкции нет и намека на уровни запуска и скрипты. Systemd оперирует понятием юнит (unit), который может олицетворять собой службу, операцию монтирования, операцию настройки сетевого интерфейса и другие.

Загрузка Linux. Конфиг юнита демона Tor.

Для описания юнитов используется специальный декларативный язык, поэтому допустить ошибку конфигурации сложнее, чем при написании скрипта. Юниты могут иметь зависимости друг от друга и запускаются параллельно либо когда в них возникает необходимость. Например, службы (демоны), не зависящие от сетевого подключения, могут быть запущены раньше настройки сетевого интерфейса, другие - сразу после его настройки, третьи - только тогда, когда к ним обращаются приложения или другие службы.

4. Запуск демонов

Запуск служб (демонов) - один из ключевых моментов загрузки Linux. Особое место здесь занимает демон udev, без которого типичный дистрибутив Linux окажется неработоспособен.

Udev занимается управлением содержимым каталога /dev. Как мы все знаем, в Linux-системах этот каталог используется для хранения так называемых файлов устройств - особого типа файлов, олицетворяющих собой те или иные компоненты ПК. Именно с помощью файлов устройств в Linux происходит работа с оборудованием: читаешь файл /dev/sda1 и получаешь содержимое первого раздела первого жесткого диска, записываешь данные в /dev/fb0 и выводишь картинку на экран.

В раннем UNIX каталог /dev был статичен. Он содержал набор файлов на все случаи жизни: даже если в ПК не была установлена звуковая карта, файл /dev/dsp для вывода звука все равно существовал. Когда количество различного оборудования было невелико, а plug’n’play еще не родился, проблем не было: всего лишь десяток-другой файлов. Но со временем он все больше захламлялся и в итоге превратился в помойку.

Первый вариант решения этой проблемы состоял в том, чтобы подключить к /dev виртуальную файловую систему (devfs), содержимым которой управляло бы ядро. Оно находило все установленное оборудование и создавало файлы только для тех устройств, которые реально присутствуют в машине.

Такое решение до сих пор используется в macOS и FreeBSD, но разработчики Linux пошли другим путем. Здесь есть специальная файловая система sysfs, подключенная к каталогу /sys. Это нечто вроде подробной базы данных обо всех устройствах ПК, начиная от процессора и контроллера прерываний и заканчивая мышками и геймпадами.

Загрузка Linux. С помощью /sys можно не только получить информацию об устройствах, но и управлять ими.

С помощью /sys можно не только получить информацию об устройствах, но и управлять ими.

На основе информации, извлеченной из /sys, демон udev создает файлы устройств в /dev. Во время первого старта он проходит по всем устройствам в /sys, а затем засыпает и ждет, пока не будет добавлено или удалено устройство: воткнул флешку - в /sys появились новые файлы, udev проснулся и создал на их основе файл устройства в /dev, загрузив нужные драйверы.

Еще один важный для UNIX-систем демон - syslog. Это своего рода агрегатор логов приложений, складывающий их все в каталог /var/logs. В основанных на systemd дистрибутивах вместо него обычно используется systemd-journald, который хранит логи в специальном бинарном формате (syslog оперирует текстом). В него можно добавлять новые записи, но удалять нельзя. Это защита от взломщиков, которые могли бы удалить нужные строки из файлов, чтобы скрыть следы своего пребывания в системе.

В среднестатистическом дистрибутиве Linux также есть другие демоны:

  • cron - отвечает за выполнение задач по времени. Может запускать команды через определенные промежутки или в четко заданное время. Простейший вариант использования - создание бэкапа по ночам;
  • cups - демон печати. Следит за очередью отправленных на печать документов и отдает их принтеру;
  • systemd-logind - управляет пользовательскими сессиями, позволяет быстро переключаться между сессиями, дает разрешение на автомонтирование устройств от лица пользователя и выполняет другие задачи;
  • dbus - демон, обслуживающий работу шины данных, позволяющей приложениям обмениваться информацией. В основном используется в средах рабочего стола и графических приложениях;
  • NetworkManager - конфигуратор сетевых интерфейсов. Используется только в десктопных вариантах дистрибутивов и может быть заменен на аналог. Например, wicd.

В большинстве своем демоны обмениваются информацией с приложениями и другими демонами с помощью UNIX-сокетов. Это канал коммуникации, закрепленный за файлом. Например, демон cups создает сокет /var/run/cups/cups.sock (в разных дистрибутивах расположение может отличаться). Записывая в него данные, можно отправлять документы на печать.

Именно эту особенность используют launchd и systemd, чтобы запускать демоны только по мере необходимости. Трюк состоит в том, чтобы заранее создать сокеты для всех системных демонов, а сами демоны запускать только тогда, когда кто-либо запишет данные в сокет; нет смысла запускать cups при загрузке или в любой другой момент, если никто не отправляет задания на печать.

5. X Window System и PAM

Последний этап загрузки - запуск менеджера логина. В консоли функцию менеджера логина выполняет связка утилит getty (обычно используется ее более продвинутый вариант agetty) и login. Getty представляет собой рудимент, оставшийся со времен мейнфреймов и удаленных терминалов (название расшифровывается как get teletype). Он выводит в терминал текстовое сообщение и затем запускает утилиту login, которая спрашивает логин и пароль пользователя. Когда пользователь вводит корректный пароль, login запускает от его имени шелл, указанный в файле /etc/passwd.

Графический менеджер логина называется дисплейный менеджер (Display Manager), и в каждой графической среде он свой. KDE использует менеджер KDM, GNOME - GDM, также есть возможность использовать универсальный дисплейный менеджер, например Slim. В любом случае задача дисплейного менеджера - вывести на экран окно запроса имени пользователя и пароля, а после авторизации либо запустить оконный менеджер напрямую, либо выполнить ряд команд, записанных в пользовательский файл ~/.xinitrc.

Этапы загрузки Linux. Дисплейный менеджер KDM в Debian.

Одновременно с запуском дисплейного менеджера запускается графическая система X Window System, а в современных дистрибутивах - Xorg. Это клиент-серверная система вывода графики на экран, где сервер отвечает за компоновку общей картинки, сформированной различными приложениями-клиентами. X Window System - не графическая среда, а лишь прослойка, позволяющая приложениям отправлять картинку на экран и получать события ввода от пользователя. Чтобы построить на ее основе графический интерфейс, также нужен менеджер окон (window manager), который позволит пользователю управлять окнами приложений.

Менеджер окон может работать как обособленно (например, fluxbox, window maker, i3), так и в составе комплексной среды рабочего стола, (KDE, GNOME, XFCE). Кроме менеджера окон, они также включают в себя набор средств для формирования полноценного десктопа: панель задач в нижней или верхней части экрана, док, систему расположения иконок на рабочем столе и прочее. Обычно каждый из этих элементов управляется одним или несколькими специальными приложениями.

Независимо от того, какой способ входа использует юзер, за контроль доступа всегда отвечает PAM. Это модульная система аутентификации пользователя, которая может проверять его личность самыми разными способами, попутно выполняя ряд проверок. По умолчанию PAM использует аутентификацию исключительно с помощью пароля, но, поменяв конфигурационные файлы /etc/pam.d, порядок аутентификации можно изменить, добавив к нему, например, необходимость приложить палец к сканеру отпечатков, вставить специальную флешку-ключ и даже использовать подтверждение с помощью смартфона. О том, как это сделать, мы уже писали.

Загрузка Linux. Конфигурационный файл PAM утилиты login

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

Вместо заключения

Так выглядит загрузка современного дистрибутива Linux. Некоторые не особо важные и не особо интересные детали я опустил, но попытался рассказать о самом главном. Если вдуматься, это не такой уж и сложный процесс, фактически операционная система готова принимать команды пользователя уже на этапе подключения initramfs, все остальное - запуск окружения, которое необходимо для полноценной работы пользователя.