Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

VPS в России, Европе и США

Бесплатная поддержка и администрирование

Оплата российскими и международными картами

🔥 VPS до 5.7 ГГц под любые задачи с AntiDDoS в 7 локациях

💸 Гифткод CITFORUM (250р на баланс) и попробуйте уже сейчас!

🛒 Скидка 15% на первый платеж (в течение 24ч)

Скидка до 20% на услуги дата-центра. Аренда серверной стойки. Colocation от 1U!

Миграция в облако #SotelCloud. Виртуальный сервер в облаке. Выбрать конфигурацию на сайте!

Виртуальная АТС для вашего бизнеса. Приветственные бонусы для новых клиентов!

Виртуальные VPS серверы в РФ и ЕС

Dedicated серверы в РФ и ЕС

По промокоду CITFORUM скидка 30% на заказ VPS\VDS

Назад Содержание Вперед

Введение в POSIX'ивизм

(C) Алексей Федорчук, 2005
Опубликовано на сайте LinuxCenter

Глава 13. Общесистемное конфигурирование

В главе 4 говорилось о том, что понимание принципов устройства системы незаменимо при ее конфигурировании и, главное, в отличие от знания конкретных рецептов, имеет универсальный, не зависящий от дистрибутива и даже операционки, характер. Настало время продемонстрировать это на практике. Тем более, что настройка общесистемных параметров загрузки и инициализации - необходимый этап в индивидуализации любой ОС POSIX-семейства. И для понимания этих принципов необходимо представлять, как эти самые операции - загрузка и инициализация, - происходят.

Содержание

Введение

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

Под загрузкой операционной системы понимается запуск на исполнение специальной программы, которая называется образом ядра системы (или просто ядром), а также, возможно, сопряженных с ним модулей. Как уже говорилось, образ ядра - почти обычный бинарный исполняемый файл. И специфика его запуска - только в том, что, если любые другие программы запускаются под управлением какой-либо ОС, считываясь с файловой системы, которую эта ОС воспринимает в качестве родной, то ядро обязано запуститься как бы само собой, без всякой операционки (ибо оно-то и есть операционка), и с носителя, о котором система ничего не знает (поскольку сама она еще не загружена). Не случайно в англоязычной литературы для процесса загрузки общепринята метафора называется bootstrapping, что столь же аллегорически можно перевести как "поднятие себя за шнурки своих ботинок". И хотя в реальной жизни такое не каждому удается, в мире POSIX-систем такая процедура осуществляется регулярно - и, как правило, успешно - остается только вспомнить барона Мюнхгаузена, вытащившего себя из болота, дергая за волосы...

Образ ядра содержит все необходимое для чистого bootstrapping'а - загрузочный сектор, первичный загрузчик и собственно исполняемый код ядра. Однако загрузить его с нормальной файловой системы невозможно - ведь о существовании таковых ядро узнает только после того, как будет загружено. Следовательно, образ ядра должен лежать на raw-устройстве (дисковом разделе, дискете, и так далее), файловой системы лишенном. И потому такой способ применяется почти исключительно при использовании для старта Linux или BSD с загрузочной дискеты - например, для аварийно-спасательных работ. В прочих же случаях для загрузки ядра системы применяются специальные программы, именуемые, как и следовало бы ожидать, загрузчиками. Они загружают ядро системы, отвечают за определение оборудования, подгрузку соответствующих ему модулей и запуск первого процесса уже работающей операционки - процесса init.

После этого в действие вступает система инициализации. Ее роль - обеспечить, посредством соответствующих стартовых скриптов (они же - сценарии инициализации), запуск основных системных процессов - сервисов, или демонов. А также - вызвать команды для получения терминала (процессы getty) и авторизации пользователей (login). Окончание старта и знаменуется приглашением к авторизации - все остальное относится уже к сфере влияния пользовательского окружения (userland). Зрительно этапы загрузки и инициализации отличаются тем или иным визуальным представлением выводимых сообщений (если вывод сообщений о ходе стартовых процессов, конечно, не отключен напрочь - в некоторых дистрибутивах Linux встречается и такое). Во FreeBSD и DragonFlyBSD, например, сообщения о ходе загрузки выводятся символами радикально белого цвета, сменяемыми на этапе инициализации обычным приглушенно-белым. В Linux картина внешне прямо противоположна - приглушенно-белая гамма в ходе старта и ярко-белая - при инициализации. А в NetBSD и OpenBSD сообщения о ходе загрузки даются на синем фоне...

Загрузка и инициализация - это первое, что в любой ОС видит пользователь. Правда, пользователю POSIX-совместимой системы такое удовольствие выпадает много реже, чем "подоконнику". Нормальный режим эксплуатации домашней Unix-машины - это ее включение рано утром и выключение - поздно вечером. (Правда, представления о "рано" и "поздно" у всех свои). А служебная Unix-машина по хорошему выключаться вообще не должна - вплоть до полной физической амортизации. Ну а необходимость в рестарте системы по ходу работы в Linux или BSD возникает чрезвычайно редко. Собственно, только после пересборки и реинсталляции нового ядра (или переносе корневого раздела - но это уже вообще исключительный случай) - во всех прочих случаях реконфигурирования системы можно обойтись и без этого.

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

Так что давайте проследим основные стадии ее и посмотрим, где и как (а главное - зачем) в нее можно вмешаться.

О загрузке и загрузчиках

Начать изучение старта системы резонно с первого ее этапа - а именно, собственно загрузки. Как уже было сказано, управление этим этапам осуществляет специальная программа, которая по русски так и называется - загрузчик. хотя в английском для нее употребляется два термина - loader и boot manager (что, как мы увидим со временем, немного разные вещи, но сейчас это не принципиально).

На самом деле любой загрузчик включает в себя две или даже три относительно независимые части - даже если он распространяется в виде единого пакета, как Lilo или GRUB. Чтобы убедиться в этом, представим себе, как происходит запуск машины на "железном", так сказать, уровне (имеется ввиду - intel-совместимой персоналки, на иных архитектурах все обстоит несколько иначе).

Перво-наперво после включения питания запускается программа, прошитая в ПЗУ компьютера (BIOS). Она выполняет проверку железа, после чего отыскивает носитель, установленный в BIOS Setup в качестве первого загрузочного устройства (для определенности - винчестер), на нем - первый физический блок, содержащий так называемую главную загрузочную запись (MBR - Master Boot Record).

Содержимое MBR - это, во-первых, таблица дисковых разделов, тех самых четырех, в один из которых мы ранее установили DragonFly. А во-вторых - некий код, принимающий на себя управление от BIOS по окончании его работы. В стандартном MBR - том, что записан на "свежевкрученном" винчестере или восстанавливается после DOS-команды FDISK /mbr, - этот код только и может, что отыскать первый физический раздел диска (primary partition) и передать управление на его загрузочный сектор. Чего вполне достаточно для загрузки операционок вроде DOS или Windows 9X/ME с первого (или единственного) раздела. Но явно мало в любом другом случае - например, если на диске установлено несколько ОС, которые, естественно, не могут уместиться в одном разделе.

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

Подобно MBR, загрузочный сектор раздела (Boot Record - уже не Master!) содержит информацию о его разметке (Disk Label), зависящие от используемой в данной ОС ее схемы, и управляющий код, принимающий эстафету от программы, записанной в MBR. И этот код - вторая составная часть загрузчика. Правда, и ее возможности также не могут быть богатыми - ведь размер загрузочного сектора раздела составляет те же 512 Кбайт. И потому на нее возлагается одна-единственная функция - передать управление программе, лежащей за пределами загрузочного сектора. Которая, собственно, и должна опознать корневой раздел ОС и несомую им файловую систему, после чего, прямо или опосредованно, загрузить ее ядро.

Легко догадаться, что первые две составляющие загрузчика, в сущности, не имеют отношения ни к какой операционке, и не являются частями файловой системы вообще. А вот с третьей - возможны варианты. Она может входить в файловую иерархию загружаемой ОС, как Lilo, или представлять собой нечто вроде самостоятельной мини-ОС, как GRUB (не случайно его настоятельно рекомендуют устанавливать в собственный дисковый раздел, не монтируемый по умолчанию к корню любой из загружаемых им операционок).

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

Особенности загрузчиков Lilo и GRUB

К тому же BSD Loader - далеко не самый распространенный из мультисистемных загрузчиков в свободном POSIX-мире. Многие пользователи Linux применяют в этом качестве Lilo (Linux Loader). Те же, кто по долгу или прихоти использует множество (более двух) операционных систем, да еще и меняют их, как перчатки, обычно отдают предпочтение загрузчику GRUB ( GRand Unified Bootloader).

Загрузчик Lilo и его настройка - предмет подробного описания в любой толстой книге про Linux. Поэтому скажу про него лишь пару строк. Это - такой же "цепочечный" загрузчик, как и BSD Loader. То есть в общем случае он записывается в MBR загрузочного диска, откуда при старте машины опознает дисковые разделы - как первичные, так и расширенные. И если раздел несет на себе метку Linux native - загрузит с него образ ядра Linux (изначально Lilo для этого и предназначался, его функции мультисистемного загрузчика вторичны). Если же тип раздела - иной, Lilo в состоянии "по цепочке" передать управление на его загрузочный сектор, и дальнейшее будет определяться тем кодом, что записан в последнем.

Тип файловой системы для Lilo по большому счету безразличен - то есть он способен загрузить ядро Linux с любой из ее многочисленных нативных файловых систем. Однако до недавнего времени он не мог выполнить эту операцию с файловой системы ReiserFS в случае, если в ней использовался так называемый tailing (или упаковка хвостов - см. главу 9). Хотя ныне это, как-будто бы изжито, при размещении ReiserFS на корневом разделе обычно все равно рекомендуется выделять специальный раздел /boot с файловой системой Ext2fs - под ядро и служебные его файлы, для страховки. Ведь, хотя использование тайлинга можно отключить, он автоматически восстанавливается при реинсталляции ядра на файловой системе, несущей оное.

Для разделов "чуждых" операционок тип их файловой системы для Lilo безразличен тем более - ведь, как уже было сказано, он просто передает управление на их загрузочные сектора. И поэтому, если озаботиться тем, чтобы в загрузочном секторе BSD-слайса был записан код boot1 из BSD Loader, то Lilo благополучно справится с загрузкой любой ОС этого семейства. А возможность записи соответствующего кода при установке BSD-систем предоставляется. Точно таким же способом - по "цепочке" - Lilo может обеспечить загрузку DOS, Windows 3.X/9X/ME и Windows NT/2000/XP.

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

Варианты загрузки через Lilo описываются в его специальном конфигурационном файле - /etc/lilo.conf. Это простой текстовый файл, доступный для изменения в текстовом редакторе (при наличии полномочий суперпользователя, разумеется). Он содержит несколько секций - общую, описывающую условия загрузки в целом и отдельные - описание каждого варианта загрузки.

Общая секция в виде отдельных строк содержит:

  • имя устройства, с которого выполняется запуск Lilo (именно Lilo, а не Linux или иной ОС), для случая первого диска это будет как boot=/dev/hda;
  • время ожидания выбора вариантов загрузки - timeout=##, где ## - время в миллисекундах;
  • имя варианта, загружаемого по умолчанию, которое должно соответствовать тому, что далее будет указано в секции этого варианта;
  • указание на режим - нынче это, как правило, строка вида lba32.

Содержание отдельных секций различается в зависимости от того, предназначен этот вариант для загрузки Linux или иной ОС. В общем случае обязательными здесь будут две строки. Первая - это метка варианта (label) - его уникальный идентификатор в виде произвольной, но, желательно, мнемонически прозрачной последовательности символов, например: linux, freebsd, windows. Вторая же - имя устройства, несущего загружаемую ОС или его корневую систему (вроде /dev/hda1, /dev/hda5, и так далее).

Секция варианта, загружающего Linux, кроме обязательного идентификатора, должна включать:

  • имя файла, содержащего образ ядра, с указанием пути относительно корневого каталога, заданного в одной из следующих строк, что обычно выглядит как image=/boot/bzImage или image=/boot/vmlinuz;
  • имя устройства, несущего корневую файловую систему, для случая первого раздела на первом диске это будет root=/dev/discs/disc0/part1 при использовании файловой системы устройств или /dev/hda1 - без оной (или при использовании udev - см. Интермедию 12);
  • указание монтировать корневую файловую систему при загрузке ядра в режиме "только для чтения" read-only; это не значит, что она станет недоступной для изменений - в процессе инициализации файловые системы будут перемонтированы в соответствие с их описанием в /etc/fstab.

Кроме того, в Linux-секции /etc/lilo.conf вносятся строки, определяющие видеорежим при загрузке (например, vga=791 - режим графической консоли с разрешением 1024x768) и строки, передающие ядру некоторые параметры, вроде append="devfs=nomount" (запрет на монтирование файловой системы устройств, требующийся при задействовании механизма udev), или append="ide-scsi" (включение эмуляции протокола SCSI через IDE-шину).

Секции для не-Linux вариантов, как правило, не содержат ничего, кроме имени устройства несущего раздела и метки варианта:

other=/dev/discs/disc0/part1                                                             
label=dos

Lilo может использоваться и исключительно для загрузки единичной Linux-системы в сочетании с любым мультисистемным загрузчиком, отвечающим за загрузку систем прочих (BSD Loader, GRUB, вплоть до NT Loader). В этом случае в общей секции /etc/lilo.conf в качестве загрузочного устройства следует указать имя корневого раздела Linux-системы - ведь тогда Lilo будет стартовать уже с его загрузочного сектора (а не с MBR диска):

boot=/dev/hda1

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

Как уже было сказано, Lilo напрямую с файловыми системами не работает - даже файловыми системами Linux. Конфиг же этого загрузчика лежит в каталоге /etc, представляющем собой часть файлового древа инсталлированной Linux-системы, которая при старте машины еще не загружена. Как же загрузчик узнает о собственной конфигурации?

Очень просто, о существовании собственного конфига в момент запуска Lilo и не подозревает. Необходимые данные для его опознания прошиты в виде бинарного кода в загрузочном секторе - диска или раздела. И делается это одноименной командой - /sbin/lilo. При запуске она обращается к файлу /etc/lilo.conf, исходя из значения строки

boot=/dev/имя_устройства

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

Added имя_рек

где имя_рек - метка (label) добавленного или модифицированного пункта меню.

Из чего становится очевидным, что каждое изменение конфигурации загрузчика должно сопровождаться его переустановкой - перезапуском программы /sbin/lilo.

Сказанным в предыдущих абзацах определяются и два принципиальных ограничения на использование Lilo вообще. Первое вытекает из положения конфига этого загрузчика внутри файловой системы Linux. Так что для изменения его конфигурации из другой операционной системы необходимо иметь доступ к той файловой системе, на которой лежит корень инсталлированного Linux'а, причем в режиме записи. И если примонтировать Ext2fs/Ext3fs к файловой системе FreeBSD или DragonFlyBSD в режиме read/write можно без проблем (ныне это не потребует даже пересборки ядра и той, и другой ОС), то доступ из любой ОС BSD-семейства к разделам с ReiserFS или XFS в настоящее время невозможен (и неизвестно, будет ли возможен в обозримом будущем).

Конечно, можно взять за правило размещать корневую систему Linux только на разделе с Ext2fs/Ext3fs. Однако второе ограничение - необходимость перезапуска /sbin/lilo, - этим не обходится, ведь эта программа предназначена для работы в родной ОС, сиречь Linux (интересно, а пробовал ли кто-нибудь запустить /sbin/lilo под FreeBSD в режиме Linux Compability?). И, соответственно, непременное условие для переконфигурирования Lilo - возможность запуска Linux в каком-никаком виде, хотя бы - с rescue-дискеты или LiveCD.

Есть и третье ограничение, не столь важное: относительно слабые (по сравнению с GRUB) интерактивные возможности. Конечно, Lilo позволяет в режиме командной строки вмешиваться руками в ход загрузки - но только загрузки Linux же (например, передавать параметры ядру). Да и то - в ограниченном объеме. Возможности же вмешательства в ход загрузки чужой ОС вообще заканчиваются в момент выбора соответствующего ей варианта.

Раз уж речь зашла об ограничениях Lilo, то, пользуясь случаем, подчеркну: прочие ограничения, на которые можно нат олкнуться в литературе, как то: невозможность загрузить ядро Linux с области диска, лежащей за пределами первых 1024 его цилиндров, или с логического раздела в разделе Extended DOS, - давно потеряли силу. И пользователь любого современного дистрибутива о них может смело забыть.

Так что основная сфера применения Lilo - это работа преимущественно (или исключительно) в Linux, при эпизодическом использовании какой-либо другой ОС. Причем рискну предположить, что под другой ОС будет выступать, скорее всего, какая-либо из версий Windows. Экспериментирование же с многочисленными операционками разных семейств - это, по моему мнению, прерогатива GRUB.

Как и Lilo, GRUB неоднократно был предметом описания в различных (преимущественно онлайновых) документах. Наиболее полное (из числа мне известных) содержится в цикле статей Владимира Попова, который можно найти здесь: http://unix.ginras.ru/linux/base011.html. К которой я отсылаю любознательного читателя, затронув ниже лишь основные особенности и возможности этой программы.

Если Lilo, как и следует из его названия, создавался в первую очередь для загрузки Linux при сохранении возможности старта Windows, то целью разработчиков GRUB изначально было создание универсального мультизагрузчика, максимально независимого от любой операционной системы. История его началась в 1995 году, когда операционная система GNU Hurd (микроядерная ОС светлого будущего, столь же отдаленного, как и коммунизм в мировом масштабе) достигла той степени развития, что могла уже быть загружена. И встал вопрос - каким же образом это сделать, так как существовавшие тогда загрузчики оказались на это неспособными.

Конечно, с точки зрения идеологии GNU, логично было бы изобрести для этой цели собственный (еще один) загрузчик, в полной мере отвечающий идеалам свободы и демократии. Однако, к счастью для всего прогрессивного человечества, был избран иной путь: Multiboot Specification - универсальный метод загрузки ядер, этой самой спецификации соответствующих. Причем сама спецификация бралась отнюдь не с потолка - в ее основу легли особенности существующих ядер Linux и BSD-систем. Ведь, как я уже говорил, файлы их образов самодостаточны для запуска и несут в себе всю необходимую информацию - и дело упирается только в то, что в обычной ситуации они расположены на носителе с файловой системой, поддержка которых начинается только после загрузки соответствующего ядра. Так что суть универсальности предложенного метода и заключалась в том, чтобы загрузчик получил средства доступа к файловой системе.

Зримым же, действительно универсальным, воплощением Multiboot Specification и стал мультисистемный загрузчик GRUB. Собственно, единственным его ограничением для полноценного использования (ниже станет ясно, что "неполноценное" использование GRUB вообще ничем не ограничено) была совместимость с файловой системой загружаемой ОС. Ибо, в отличие от BSD Loader и Lilo, GRUB способен работать с очень многими файловыми системами напрямую, без всякого использования ресурсов соответствующей операционки - "монтировать", читать с них данные, подвергать их редактированию и записывать изменения. Что превращает его в своеобразную мини-ОС, имеющую к тому же свой собственный, шелл-подобный, интерфейс пользователя.

Можно выделить две степени совместимости GRUB с файловыми системами - полную и частичную. Полностью совместимые файловые системы - это те, что способны нести GRUB сам по себе. И в их числе - абсолютно все нативные файловые системы Linux (включая JFS, имевшие некогда место проблемы с "монтированием" ReiserFS, насколько я знаю, в прошлом), Minix и FAT. То есть загрузчик GRUB может стартовать с любого носителя, отформатированного соответствующим образом - дискового раздела, дискеты Linux (на которых применяется файловая система Minix) или DOS (с файловой системой FAT). Хотя по причинам, которые скоро станут понятны, разработчики рекомендуют размещать GRUB на самостоятельном разделе с файловой системой Ext2fs.

Частично совместимые с GRUB файловые системы сами по себе нести его не могут. Но после своего старта он способен их идентифицировать, прочитать и загрузить с них ядро, если оно отвечает Multiboot Specification. И в эту группу попадают практически все файловые системы свободных операционок, внутренний формат которых общедоступен - кроме Linux, тут мы видим также все варианты FFS и UFS, используемых BSD-семейством. Если же какая-то из таких файловых систем (как правило, из числа только что созданных) кажется несовместимой с текущей версией GRUB - это исключительно временное явление. Потому что для любой открытой файловой системы нет никаких препятствий получить свою поддержку в GRUB.

Приведу пример: с появлением 5-й ветки FreeBSD она обрела новую нативную файловую систему, UFS2, несколько отличную от прототипа - UFS просто. В результате единовременная версия GRUB (0.93) оказалась неспособной работать с ней напрямую (ниже я покажу, что это все равно было обходимо). Однако уже для версии 0.94 появился патч поддержка UFS2, а с версии 0.95 GRUB поддерживает эту файловую систему, что называется, "из тарбалла".

Можно видеть, что в списке частично совместимых с GRUB файловых систем нет тех, что созданы Самой Великой Софтверной компанией, в частности - всех вариантов NTFS. Что понятно - ведь их внутреннее устройство - тайна за семью печатями. Однако мир свободного софта в очередной раз подтверждает справедливость утверждения, что на самое хитрое ухо (вариант для дам) всегда найдется болт с левой резьбой. Существует он и здесь: операционки, файловые системы которых для GRUB недоступны, могут быть загружены "по цепочке" - передачей управления на загрузочный сектор соответствующего раздела. Тот же способ можно применить и для загрузки свободных ОС, файловые системы которых временно не поддерживаются на моей памяти таковыми бывали периодически некоторые версии OpenBSD и FreeBSD 5-й ветви. К слову сказать - даже "ухо с закоулками" (несовместимость ядра с Multiboot Specification, имеющая место для DOS/Windows9X/ME) не оказывается помехой для винта от GRUB. И указанные операционки могут быть столь же успешно загружены "цепочечным" методом.

Таким образом, универсализм GRUB в рабочем (то есть установленном и настроенном) состоянии сомнений не вызывает. Однако с точки зрения установки и настройки он предстает столь же независимым от любой ОС. Ибо устанавливается он с самодостаточной загрузочной дискеты. А с недавнего времени, благодаря усилиям Владимира Попова, это можно проделать и с мультизагрузочного LiveCD (который можно скачать отсюда). То есть: наличия инсталляции какой-либо ОС (или дистрибутива Linux не требуется).

Что же касается конфигурирования GRUB, то, если следовать приведенным ранее рекомендациям разработчиков (установке GRUB на отдельный дисковый раздел с файловой системой Ext2fs - и резоны к тому сейчас прояснятся), то и тут никаких сложностей не предвидится ни в одной из свободных ОС. В Linux этот раздел монтируется как каталог /boot, куда, вместе с файлами собственно загрузчика (в подкаталоге /boot/grub) помещаются также файлы ядра (/boot/vmlinuz и подобные ему). Причем разработчики опять же рекомендуют монтировать /boot не автоматически при старте Linux - после ее загрузки никакой необходимости к этому каталогу в обычных условиях нет), а руками - по мере необходимости (установки нового ядра или реконфигурации GRUB).

За настройку загрузки GRUB отвечает специальный файл, доступный из Linux как /boot/grub/menu.lst. Это простой текстовый файл, который можно модифицировать в любом редакторе. Причем, что ценно, предварительно проверив работоспособность вносимых изменений в интерактивном режиме. Описывать его формат в деталях не буду, он очень прост и станет ясным и приводимого в заключении примера.

Так что для конфигурирования же GRUB из какой-либо иной ОС требуется только возможность чтения раздела с Ext2fs и записи в него. А, как уже говорилось, получить такую возможность из FreeBSD и DragonFlyBSD ныне никакого труда не составит (да и в случае Net- или OpenBSD в худшем случае потребуется только пересборка их ядер). Так что рекомендация разработчиков о выборе файловой системы загрузочного раздела становится понятной - прочие файловые системы Linux BSD-семейством не поддерживаются, а FAT... ну он FAT и есть, всерьез говорить о нем не стоит.

Таковы основные особенности (и возможности) GRUB. О деталях его установки, настройки и интерактивной работы в ходе загрузки можно было бы написать еще много. Однако это уже проделано Владимиром Поповым, и повторяться я не буду. Памятуя и о прекрасной штатной документации этой программы, правда, в нелюбимом мною формате (info grub, стандартный man grub содержит лишь краткие о ней сведения). Так что в качестве завершающего штриха просто приведу прокомментированный (строки комментариев, как обычно, отмечены символом #) пример своего конфига, который долгое время верой и правдой служил мне при загрузке Archlinux.

# Config file for GRUB - The GNU GRand Unified Bootloader
# /boot/grub/menu.lst

# Общая конфигурация загрузчика
timeout   5
	# Время ожидания выбора загружаемой ОС в секундах
default   0
	# ОС, загружаемая по умолчанию
	# (в данном случае Linux)
color light-blue/black light-cyan/blue
	# Цветовая гамма меню (мне такая нравится)

# Секция, отвечающая за загрузку Archlinux
# (0) Arch Linux
title  Arch Linux  [/boot/vmlinuz]
	# Идентификатор ОС
	# он же - пункт меню загрузчика
root   (hd0,1)
	# Устройство, несущее корневую файловую систему:
	# 2-й раздел 1-го диска в нотации GRUB
	# В нотации Linux ему соответствует устройство
	# /dev/discs/disc0/part2 в следующей строке
kernel (hd0,0)/vmlinuz root=/dev/discs/disc0/part2 ro 
	# где
	#  (hd0,0)/vmlinuz - положение файла образа ядра
	# на загрузочном устройстве в нотации GRUB -
	# 1-м разделе 1-го диска
	# root=/dev/discs/disc0/part2
	# имя устройства с корневой файловой системой
	# уже в нотации Linux (при использовании devfs)
	# ro - предписание монтировать его в режиме read-only

А в ближайшей же интермедии я остановлюсь на вопросе, недостаточно освещенном в источниках - загрузке с помощью GRUB систем BSD-клана (в том числе и при отсутствии доступа к их файловой системе).

Задачи инициализации

Итак, тем или иным способом загрузка ядра и всего сопутствующего ему хозяйства успешно завершена. В дело вступает главный калибр любой POSIX-системы - процесс init. Это первый (в прямом и переносном смысле его PID равен единице) пользовательский (то есть работающий в пользовательском пространстве ядра, юзерланде, процесс, и запускается он исполнением одноименного файла /sbin/init.

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

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

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

А следующая задача процесса init - это вызов и отработка сценариев инициализации, или стартовых скриптов, собранных в каталоге /etc и (или) его подкаталогах. Они столь сильно зависят от операционки (а внутри Linux - еще и от конкретного дистрибутива), что дать их обобщенную характеристику практически невозможно. Можно только констатировать, что сценарии инициализации - это обычные сценарии оболочки, рассчитанные на исполнение стандартным POSIX-шеллом (/bin/sh в BSD-системах и, обычно, /bin/bash - в Linux). Они включают в себя последовательности команд, призванные монтировать файловые системы, активизировать область своппинга, устанавливать системные часы, запускать те или иные службы и демоны, включая сетевые соединения.

Команды, образующие стартовые сценарии, получают свои опции, их значения и аргументы из специальных файлов конфигурации, также имеющих своим местопребыванием /etc и его подкаталоги. Конфигурационные файлы (или по простому конфиги) представляют собой либо простые базы данных опций и аргументов команд, либо списки имен переменных, (соответствующих опциям команд, используемых в скриптах) с присвоенными им значениями. Конфиги от скриптов легко отличимы при просмотре каталога /etc отсутствием у первых бита исполнения.

Сказанное может показаться не очень понятным, поэтому попытаюсь продемонстрировать на примере. Например, обязательная процедура на стадии отработки сценариев инициализации - монтирование необходимых файловых систем в режиме чтения/записи; и перемонтирование - ведь при загрузке ядра несущая его корневая файловая система монтируется в режиме "только для чтения". Это выполняется прямой директивой

$ mount -a

предписывающей смонтировать все файловые системы, и входящей в состав одного из стартовых сценариев (каком именно - зависит от оперционки и дистрибутива). А вот что понимается под словом "все" (имя опции -a - от all) - то есть список аргументов (устройств и точек монтирования), а также опций, с которыми должна быть смонтирована та или иная файловая система, - и составляет содержание специальной базы данных, хранимой в файле /etc/fstab. Мы уже знакомились с ним в соответствующей интермедии, однако позволю себе напомнить обобщенный его формат (т ем паче, что это один из немногих конфигов, формат которого идентичен во всех POSIX-системах).

Это - очень простая база данных, каждая запись которой соответствует подлежащей монтированию файловой системе, а поля, разделителем которых являются символы пробела (пробелов) или табуляции, следующие:

имя файла устройства, несущего файловую систему;
точка монтирования - каталог в файловой иерархии;
тип файловой системы;
опции монтирования (часто имеет значение default).

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

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

Наконец, третья непременная задача процесса init - теч, что в главе 7 мы рассмотрели как получение терминала (запуск процесса getty), установку его свойств и подготовку к авторизации - вытеснение его процессом login. Эта процедура также по разному выполняется в разных системах, хотя тут многообразие не столь и велико, как при отработке стартовых скриптов.

В ходе инициализации могут выполняться и некоторые другие задачи, скажем, конфигурирование приложений, не входящих в базовую систему, но, тем не менее, запускаемых в качестве стартовых сервисов (демонов). Поскольку такие программы устанавливаются отдельно от системы (и не в обязательном порядке), сценарии их запуска и сопряженные с ними конфиги лежат не в каталоге /etc, а в других, подчас весьма неожиданных, местах (/usr/etc, /usr/local/etc и так далее). Типичным примером здесь является httpd - демон, управляющий web-сервером Apache. Однако все это - уже не обязательные составляющие этапа инициализации.

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

Первый потенциальный источник ошибок инициализации - отсутствие "бита чистого размонтирования", выявляемое при начальной проверке файловых систем. В этом случае делается вывод о некорректности завершения предыдущего сеанса и возможности существования противоречий в ней. Таковыми могут быть, например, записи в каталогах, которым не соответствуют идентификаторы каких-либо файлов. Или, напротив, идентификаторов файлов, не приписанных ни к каким каталогам.

Для проверки, действительно ли такие противоречия имеют место быть (а отсутствие clean byte отнюдь не влечет их неизбежности) и, при необходимости, исправления выявленного безобразия, запускается утилита проверки файловой системы fsck (это разные программы, в зависимости от типа проверяемых файловых систем). Если такая проверка завершается успешно - то есть противоречий в структуре файловой системы на самом деле нет или могут быть исправлены автоматически - опять же все хорошо, процесс init возвращается к выполнению своих задач, если нет - снова возможны варианты, зависящие от ОС и "тяжести повреждений". Худший случай - когда серьезные противоречия обнаруживаются в корневой файловой системе, это знаменует окончание нормальной инициализации с переходом в однопользовательский режим, когда монтируется только корневая файловая система - и в режиме read only.

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

Более серьезные последствия будут иметь ошибки при монтировании файловых систем, самый частый источник которых - синтаксически неправильное их описание в файле /etc/fstab (то есть элементарные опечатки). Особенно серьезным будет невозможность монтирования корня файлового древа - этом случае ядро впадет в панику (т.н. Panic mode) и продолжение загрузки окажется невозможным.

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

Впрочем, оснований для паники нет - даже при впадении в панику ядра, все возможные при инициации системы ошибки исправимы тем или иным способом. Ибо легкий флирт, в том числе и с операционной системой, подобно насморку, переносится на ногах, и постельный режим необходим лишь в тяжелых случаях. В одних ситуациях достаточно завершить процесс загрузки и чуть подправить конфиги, в других - загрузиться в однопользовательском режиме и провести проверку и ремонтирование файловых систем вручную, в третьих придется грузиться с rescue-носителя (например, LiveCD). А вот хирургического вмешательства - сиречь полной переустановки системы, - скорее всего, не потребуется никогда. Впрочем, все это будет предметом отдельного разговора в одной из ближайших интермедий.

Оборотная сторона инициализации системы - это ее останов или рестарт, различий между этими процессами практически нет. И отвечает за него команда shutdown, которая может быть дана от лица суперпользователя или члена группы operator. С опцией -h она вызывает останов машины, с опцией -r - ее перезагрузку. И еще команде этой требуется аргумент - время, когда останов или рестарт должны произойти. Впрочем, есть способ и мгновенного останова или рестарта:

$ shutdown -h now

или

$ shutdown -r now

соответственно.

Во всех, насколько мне известно, POSIX-системах существуют также команды halt и reboot того же назначения. Однако самостоятельной роли они не играют, просто вызывая команду shutdown с опцией останова и перезагрузки, соответственно.

Останов системы происходит в порядке, обратном ее инициализации. Сначала делается попытка корректного завершения всех пользовательских процессов отправкой им сигнала TERM. По истечении некоторого промежутка времени всем еще "живым" процессам отправляется сигнал KILL - для гарантированного их убиения. Затем стопорятся все стартовые сервисы и демоны. Наконец, содержимое дисковых кэшей записывается на диск (посредством команды sync), и размонтируются файловые системы. После этого обычно появляется сообщение о возможности безопасного отключения питания машины или оно отключается автоматически. При рестарте все происходит точно также, но после останова системы автоматически начинается перезагрузка машины. Весь процесс останова и (или) рестарта определяется соответствующим сценарием (или сценариями), подобными сценариям инициализации.

Важно - и это одно из первых правил техники безопасности, - что Unix-машину крайне не рекомендуется останавливать простым отключением питания. Каковое чревато разными неприятностями. Это могут быть

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

В современных версиях POSIX-систем в той или иной мере реализована поддержка управления питанием стандарта ACPI (Advanced Configuration and Power Interface). При ее включении в принципе становится допустим останов системы простым отключением питания машины - на нажатие кнопки Power на корпусе компьютера система реагирует точно так же, как и на команду shutdown -h now. Однако прибегать к этому следует только в случае уверенности в правильности настройки и функционирования модулей acpi - и в Linux, и в BSD-системах эти опции экспериментальны, и их безошибочная работа не гарантируется.

Стили инициализации

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

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

Это - размежевание лишь в первом приближении. Потому что сценарии инициализации в стиле System V - это та сфера, в которой майнтайнеры отдельных дистрибутивов Linux в своем стремлении к оригинальности оттягиваются по полной программе. Инициация в BSD-стиле, что в одноименных системах, что в дистрибутивах Linux, подвержена этой тенденции существенно в меньшей степени. Опять перефразируем нашего великого автора: пользователи всех BSD-схем счастливы одинаково, пользователи схем загрузки SysV - несчастливы по своему. Впрочем, приверженцы последнего стиля инициации, скорее всего, поменяли бы мои определения местами...

Особенности BSD-стиля

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

В однопользовательском режиме загрузка происходит а) при выборе соответствующего пункта (Boot in single user mode) в меню начального загрузчика, б) при задании команды boot -s в командной строке загрузчика (после выбора пункта его меню Escape to loader prompt), и в) при обнаружении серьезных (неустранимых автоматически) нарушений целостности файловой системы в ходе ее проверки на первой стадии инициализации).

В любом случае при загрузке в однопользовательском режиме не монтируется ни одна файловая система из /etc/fstab, кроме корневой - да и та остается лишь в режиме read only, в котором она была смонтирована при старте системы, не отрабатывается ни один сценарий инициализации, и не активизируется ни один виртуальный терминал, кроме первого, исполняющего функции системной консоли, авторизация на которой по умолчанию - беспарольная, с автоматическим получением прерогатив суперпользователя (а зарегистрироваться от лица кого-либо другого, понятное дело, и невозможно). Очевидно, что никакая нормальная работа при этом невозможна, однопользовательский режим предназначен почти исключительно для аварийно-спасательных работ и потому подробнее будет рассмотрен в соответствующей интермедии.

При загрузке в многопользовательском режиме (а она осуществляется по умолчанию при нормальном включении машины или ее перезагрузке) все стадии инициации проходятся по полной программе: монтируются предназначенные к тому файловые системы из файла /etc/fstab (а корень ее ремонтируется в режиме чтения/записи), отрабатываются определённые стартовые скрипты (где и кем определенные - скоро увидим), и активизируются все описанные в файле /etc/ttys виртуальные терминалы (вплоть до графического приглашения к авторизации, если таковое определено). Авторизация возможна как для администратора, так и для любого пользователя, но о беспарольном входе придется забыть. Короче говоря, идет нормальная цивилизованная работа...

Между однопользовательским и многопользовательским режимами не лежит непреодолимой пропасти: переход из одного режима в другой возможен не только при рестарте машины, но и в ходе одного сеанса. Для немедленного перехода в однопользовательский режим служит команда

$ dhutdown now

Возврат обратно в многопользовательский режим происходит по команде

$ exit

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

Загрузка в многопользовательском режиме - и это отличительная особенность BSD-стиля, - потенциально влечет за собой доступность для запуска абсолютно всех системных служб и демонов: инициализирующие их сценарии (располагающиеся в каталоге /etc/rc.d) теоретически могут быть запущены из главного стартового сценария - файла /etc/rc. А вот какие из них будут запущены реально - определяется опциями его конфигурационного файла - /etc/rc.conf.

При установке системы, использующей BSD-стиль инициализации, в каталог /etc на диске записывается некий умолчальный /etc/rc.conf, строки имеют вид

servicename_enable="значение"

или

переменная="значение"

Значение строк первого вида = "YES" или "NO". Легко догадаться, что они разрешают (или запрещают) запуск поименованного сервиса посредством соответствующего ему (и, как правило, одноименного) сценария из каталога /etc/rc.d (для определенности я рассматриваю случай FreeBSD и DragonFlyBSD - стартовые схемы их практически идентичны, - но нечто подобное будет и в NetBSD, и в OpenBSD). Например, строка

moused_enable="YES"

разрешает запуск службы консольной мыши посредством скрипта /etc/rc.d/moused.

Значения же строк второго вида - это параметры, передаваемые командам, входящим в скрипты инициализации. Так, строки

moused_type="auto"
moused_port="/dev/ums0"

определяют что значения опций -t (автоматическое определение протокола) и -p (имя файла мышиного устройства - в данном случае с USB-интерфейсом) для команды /usr/sbin/moused, запускаемой из сценария /etc/rc.d/moused.

Как правило - и это тоже традиция BSD-систем, - по умолчанию в файле /etc/rc.conf разрешен запуск лишь минимально необходимого для начала работы количества системных служб. Большая же их часть обычно запрещена - или явным образом, указанием значения "NO", или по умолчанию а откуда они берутся - мы скоро увидим). Так что включение необходимых пользователю демонов (например, той же консольной мыши) - дело рук самого пользователя.

Откуда берутся стартовые умолчания? А берутся они из файла /etc/defaults/rc.conf, в котором описаны всевозможные (и все возможные) стартовые сервисы и их параметры. Файл этот не предназначен для прямого редактирования (хотя оно и не запрещено атрибутами его доступа). Вместо этого полагается отыскать в нем строки, относящиеся к нужным сервисам, перенести их в /etc/rc.conf и разрешить их запуск (или, напротив, запретить, если оный разрешен по умолчанию, но в данном случае не нужен). Уточняющие опции сервисов также берутся из /etc/defaults/rc.conf, переносятся в /etc/rc.conf и им приписываются нужные значения.

В общем виде это делается, например, так: в одной виртуальной консоли (на которой нужно зарегистрироваться как root или получить его права командой su) в текстовом редакторе открывается файл /etc/rc.conf, в другой (на ней можно авторизоваться и обычным пользователем) дается команда

$ less /etc/defaults/rc.conf

И нужные строки из последнего просто переносятся в первый, где и модифицируются должным образом. Не вредно при этом задействовать и третью пользовательскую консоль - для чтения man (5) rc.conf. Как все это выглядит на практике - мы увидим в ближайшей интермедии.

Что же касается заключительной стадии BSD-инициации - процесса получения терминала, - то она контролируется записями в файле /etc/ttys, о котором уже говорилось в интермедии 13. Наличие специального файла для конфигурирования виртуальных терминалов - одно из важных отличий BSD-систем: в Linux, вне зависимости от стиля сценариев инициализации, принятых в конкретном дистрибутиве, настройка виртуальных терминалов описывается в общем конфиге процесса init.

Как уже говорилось, сценарии, отвечающие за запуск стартовых сервисов, находятся в каталоге /etc/rc.d (по крайней мере в современных версиях FreeBSD, а также в DragonFlyBSD это именно так). Большинство запускаемых ими программ - это так называемые демоны (daemon - Disk And Execution MONitor), нечто вроде резидентных программ, работающих в фоновом режиме в ожидании запроса на исполнение их функции (печати, отправки почты, обращения к ftp- или http-серверу, и так далее). В соответствие с этим запускающие их сценарии устроены по принципу start - stop. И если при инициации системы выполняется первая функция, то при ее останове, как легко догадаться, вторая.

Ход процесса останова системы определяется сценарием /etc/rc.shutdown. Назначение его - выполнить функцию stop в сценариях всех сервисов, запущенных из скрипта /etc/rc в соответствие с описанием, данным в /etc/rc.conf и /etc/defaults/rc.conf.

Стили System V

Основу инициализации в стиле System V, в более или менее чистой форме принятой в Linux, составляет понятие runlevels. Это один из тех терминов, любой русский перевод которого способен только сбить с толку начинающего пользователя. Потому что часто используемые переводы типа уровни запуска или уровни загрузки создают впечатление, что система в процессе инициализации последовательно проходит некие, соответствующие им, стадии. На самом деле, как мы видели, стадии инициализации действительно имеют место быть - вот только к runlevels они имеют отношение весьма косвенное.

Понять, что же такое runlevels в System V проще всего в сравнении с BSD-инициализацией. В которой, как мы только что видели, существует два режима - однопользовательский, при котором не исполняются никакие стартовые сценарии, и многопользовательский, при котором исполняются все сценарии, разрешенные в главном конфиге /etc/rc.conf и умолчальном конфиге /etc/defaults/rc.conf. Так вот, runlevels - это нечто вроде таких же режимов, только их - несколько больше, и каждому поставлен в соответствие набор исполняемых при его вызове сценариев.

Вызов runlevels, то есть метасценария для группы сценариев, осуществляется при инициализации системы первым ее пользовательским процессом - процессом init. А сами эти метасценарии описаны в главном конфигурационном файле этого процесса - /etc/inittab. Конфиг этот описывает весь ход процесса init - от проверки файловых систем до получения терминала. И является непременным атрибутом всех (по крайней мере, известных мне) Linux-систем, отличающим их от систем BSD-клана (где, как мы видели, единого конфигурационного файла для процесса init нет).

Теоретически процесс init предусматривает вызов семи runlevels - от нулевого до шестого; за тремя из них зафиксированы метасценарии определенного назначения, использование остальных отдано на откуп создателям дистрибутивов (и, как я уже говорил, они используют это на всю катушку). зарезервированы следующие runlevels:

  • 0 - halt, то есть останов системы;
  • 1 - single user mode, сиречь однопользовательский режим;
  • 6 - reboot (перезагрузка системы).

Что в очередной раз показывает неадекватность из приведенных выше переводов: русскоязычному пользователю, не совсем лишенному элементов логического мышления, трудно понять, почему останов системы отнесен у ровням ее запуска (хотя я вполне допускаю, что у пользователя, родной язык которого - английский, слово runlevel вызывает совсем другие, "правильные" ассоциации). Хотя почему останов и перезагрузка системы вообще выступают в одном ряду с режимами ее запуска - понять вообще невозможно, даже отвлекаясь от перевода, - но это уже фирменный стиль System V.

Опять, однако, отвлекся - вернусь к прочим runlevels. Их использование - свободно. Как правило, один из свободных номеров (обычно 3 или 4) задействуется под нормальный многопользовательский режим работы, другой же (4 или 5) - под режим запуска Иксового сеанса (то есть графический). В некоторых дистрибутивах предусматривается еще и многопользовательский режим без поддержки сети. Вот как это выглядит в наиболее распространенном из дистрибутивов Linux - Red Hat (в замужестве - Fedora Core):

  • 0 - останов системы;
  • 1 - однопользовательский режим;
  • 2 - многопользовательский режим без поддержки сети;
  • 3 - полный многопользовательский режим ;
  • 4 - не используется;
  • 5 - полный многопользовательский режим X-сессии;
  • 6 - перезагрузка системы.

В других дистрибутивах Linux количество задействованных runlevels в интервале со 2-го по 5-й и их соответствие режимам может быть иным: для конкретного дистрибутива это можно посмотреть в файле /etc/inittab, в начале которого в виде комментария всегда содержится список, подобный приведенному.

А вообще описание действий по инициализации в файле /etc/inittab начинается с вызова первого исполняемого в ее ходе сценария. Имя его и расположение очень зависят от дистрибутива. В Red Hat, например, это будет /etc/rc.d/rc.sysinit. Функциональность также варьирует от системы к системе, но среди обязательных - такие функции, как проверка файловых систем, их монтирование, активизация swap-раздела (возможно, и многое другое, вплоть загрузки консольных шрифтов, клавиатурных раскладок и даже установки локали).

Следующее действие из предписанных /etc/inittab - определение умолчального режима, то есть все того же runlevels, что воплощается в строке вида

id:3:initdefault:

и автоматически влечет за собой исполнение набора скриптов, за ним закрепленных.

Скрипты эти сгруппированы в определенных (точнее, очень неопределенных - то есть своих в каждом дистрибутиве) подкаталогах каталога /etc. В Red Hat это будут /etc/rc.d/rc0.d, /etc/rc.d/rc1.d, ..., /etc/rc.d/rc6.d, в Debian - /etc/rc0.d, /etc/rc1.d, ..., /etc/rc6.d, в произвольном дистрибутиве Linux - даже и гадать не берусь. Однако общая закономерность в том, что цифра в имени подкаталога прямо соответствует номеру runlevels. И именно скрипты из подкаталога вида /etc*0* будут отрабатываться при останове системы, /etc*1* - при загрузке в однопользовательском режиме, и так далее.

Возникает вопрос - а не повторяются ли сценарии в подкаталогах разных runlevels? Ведь очевидно, что для запуска многопользовательского режима без поддержки сети, полного многопользовательского режима и режима графического нужно выполнить существенно пересекающееся множество действий. И различия лишь в том, что во втором случае добавляется запуск сетевых служб, а в третьем - еще и менеджера графического входа в систему (например, xdm).

Ответ, как ни странно, будет отрицательным. Потому что на самом деле реальных сценариев, соответствующих runlevels, в указанных каталогах нет. Все стартовые скрипты собраны в отдельном подкаталоге с именем вроде /etc/init.d (не поручусь, что оно будет одинаковым во всех дистрибутивах) без всякого разделения, а в подкаталоги вида /etc*#* помещаются лишь символические ссылки на них. Кстати, и упоминавшийся ранее первый инициализационный скрипт /etc/rc.d/rc.sysinit - тоже симлинк на /etc/init.d/rc.sysinit.

Более того, в каждом runlevels-каталоге ссылки эти имеются в двух экземплярах - одна ссылка маркированная буквой S в имени, отвечает за старт сервиса, другая же, имеющая в имени литеру K (от kill), за его остановку. Это достигается за счет того, что в первом случае скрипт вызывается с опцией start, во втором же - с опцией stop. Исключение - подкаталоги, соответствующие runlevels 0 и 6: из самой их сути очевидно, что стартовых ссылок в них быть не может, а есть только стоповые.

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

Осталось определить, откуда берутся значения опций и аргументов для команд, образующих сценарии инициализации. А берутся они из собственных конфигурационных файлов - ведь принцип разделения скриптов и конфигов неукоснительно проводится и в схеме SysV. Конфиги эти могут быть собраны в едином подкаталоге типа /etc/conf.d, или раскиданы по всему каталогу /etc - как это сделано в конкретном дистрибутиве, определить не берусь.

Наконец, с запуском сценариев инициализации покончено. Остается последнее из предписанных процессу init действий - получение терминалов. В схеме SysV оно также описывается в файле /etc/inittab и выглядит примерно следующим образом (дано на примере Red Hat/ASPLinux):

# Run gettys in standard runlevels                                                        
1:2345:respawn:/sbin/mingetty tty1                                                        
2:2345:respawn:/sbin/mingetty tty2                                                        
3:2345:respawn:/sbin/mingetty tty3                                                        
4:2345:respawn:/sbin/mingetty tty4                                                        
5:2345:respawn:/sbin/mingetty tty5                                                        
6:2345:respawn:/sbin/mingetty tty6

Впрочем, разговор на эту тему уже был - в Интермедии 13. Добавлю только, что в данном примере 6 виртуальных терминалов активизируются при всех runlevels (кроме однопользовательского режима, разумеется, останова и перезагрузки). А при вызове runlevels 5 (напомню, здесь это - X-сессия) на первой же свободной (то есть не активизированной) консоли запускается менеджер графического входа в систему, за что отвечает такая строка:

x:5:respawn:/etc/X11/prefdm -nodaemon

Я попытался дать максимально обобщенное описание процесса инициализации в стиле System V. Насколько получилось - судить не мне. Однако более ясное представление о ней можно получить, только рассматривая реализации в конкретных дистрибутивах, на что у меня нет ни желания, ни возможности. Так что заинтересованным читателям остается только обратиться к дополнительным источникам информации. Из которых я выделил бы Linux Startup Manual) - с той только оговоркой, что слово Linux в его заглавии следовало бы заменить на Red Hat: ибо в нем описана схема инициализации именно этого дистрибутива. А за более обобщенным описанием схемы SysV и принципов построения собственной схемы загрузки в этом стиле следует обратиться к LFS Book Герарда Бикманса (http://hints.linuxfromscratch.org/) или какому-либо из ее русских переводов: 4-й (http://multilinux.sakh.com/lfs/) или 5-й (http://linux.yaroslavl.ru/docs/book/lfsbook/) версии, номер здесь принципиального значения не имеет.

Схема инициализации в стиле System V может показаться излишне усложненной. Хотя, по словам лично мне знакомых администраторов сетей, позволяет очень гибко управлять различными сервисами. Однако для конечного пользователя такое усложнение неоправданно. И, как выяснилось, это мнение не только мое. Иначе чем объяснить стремление прикрутить сценарии инициализации в BSD-стиле в ряде современных дистрибутивов Linux, таких, как Gentoo, CRUX, Archlinux, не говоря уже о дедушке дистрибутивостроения - Slackware.

Разумеется, и в этом случае никуда не деваются ни runlevels, ни /etc/inittab. BSD-подобный облик схемы их загрузки приобретают за счет а) минимизации задействованных значений runlevels, и б) наличия главного конфигурационного сценария типа /etc/rc, конфигурируемого посредством единого "плоского" /etc/rc.conf. Наиболее последовательно эта схема претворяется в жизнь создателями дистрибутива Archlinux, в котором понятие runlevels практически не используется. Что на конкретно примере будет проиллюстрировано в следующей интермедии.

Назад Содержание Вперед

VPS/VDS серверы. 30 локаций на выбор

Серверы VPS/VDS с большим диском

Хорошие условия для реселлеров

4VPS.SU - VPS в 17-ти странах

2Gbit/s безлимит

Современное железо!

Бесплатный конструктор сайтов и Landing Page

Хостинг с DDoS защитой от 2.5$ + Бесплатный SSL и Домен

SSD VPS в Нидерландах под различные задачи от 2.6$

✅ Дешевый VPS-хостинг на AMD EPYC: 1vCore, 3GB DDR4, 15GB NVMe всего за €3,50!

🔥 Anti-DDoS защита 12 Тбит/с!

Новости мира IT:

Архив новостей

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 495 7861149
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2019 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...