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

       

Стили 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 практически не используется. Что на конкретно примере будет проиллюстрировано в следующей интермедии.


    Содержание раздела