Авторы:
Martin Schlemmer
Seemant Kulleen
Перевод:
Кирилл Васильев
Настоящее руководство является введением в систему инициализации Gentoo Linux, а также освещает некоторые детали написания rc-сценариев.
1.0.2 Jan 12 2003
Gentoo Linux использует систему инициализации, которая практически полностью управляется с помощью зависимостей. Она должна быть простой в поддержке, но в то же время достаточно мощной и гибкой для любого типа установки. Не стоит рассматривать данное руководство как введение в то, как все это работает; скорее, это краткое руководство по работе с системой инициализации Gentoo. Для тех же, кто озабочен деталями внутреннего устройства... читайте исходники ;-)
В отличие от прочих систем инициализации, у уровней исполнения в Gentoo нет строго определенных имен или номеров, но сходства с init есть. Существуют три уровня исполнения по умолчанию: "boot", "default" и "nonetwork".
Уровень исполнения "boot" должен быть стандартным для большинства установок и, как следует из его названия, это первый уровень исполнения, запускаемый на стадии загрузки. Следующий - "default" - это главный уровень исполнения, исполняющийся после загрузки - что и отражено в его названии. И последний уровень, "nonetwork", выступает исключительно в качестве примера.
Уровни исполнения расположены в /etc/runlevels, в поддиректории, названной по имени уровня исполнения; эта поддиректория заполняется символическими ссылками на сервисы, относящиеся к данному уровню исполнения.
Наиболее предпочтительный способ добавления или удаления сервисов обсуждается в разделе "О rc-update".
Как показано ранее, имя уровня исполнения можно изменить на более подходящее пользователю, поскольку для отражения нового имени также меняется и запись правила в /etc/inittab.
Однако, из этого правила есть исключение: уровень исполнения "boot". Пожалуйста, НЕ меняйте имя уровня исполнения "boot", так как это может привести к неприятным последствиям!
Всю работу (в том числе и переключение уровней исполнения на лету) выполняет сценарий /sbin/rc.
В силу того, что уровни исполнения Gentoo не имеют явного отображения на уровни исполнения init, первых может быть гораздо больше. А пользователь получает возможность по своему желанию создавать профили или виртуальные уровни исполнения.
Например, владелец ноутбука может иметь два уровня исполнения по умолчанию - "online" и "offline" - что позволяет активировать первый, когда подключена сетевая карта PCMCIA, и второй - когда карта отключена. Сценарии для PCMCIA можно настроить так, чтобы они вызывали "/sbin/rc online" или "/sbin/rc offline" в каждом соответствующем случае, запуская или останавливая сервисы, зависящие от статуса сетевой карты.
В соответствии со стратегией Gentoo, для X-сервера нет отдельного уровня исполнения, но есть сценарий для запуска, "xdm", который можно добавить на любой требуемый уровень исполнения. Это должен быть основной уровень исполнения пользователя. Добавление этого сценария на загрузочный уровень исполнения может вызывать побочные эффекты.
По умолчанию, если вы запускаете xdm, gdm или kdm перед тем, как будут запущены ваши getty, X-сервер будет работать на следующей доступной консоли. На медленных машинах, то, что менеджер рабочего стола запускается ближе к концу процесса инициализации, проблемой не является. getty запустятся перед X-сервером, а тот будет работать на 7-й консоли, как и должно быть. Однако на быстрых машинах все не совсем так - X-сервер запустится раньше getty, обычно обычно начинающего работу на 2-й консоли. Когда же запустится getty, он возьмет контроль над клавиатурой, а Desktop Manager его потеряет.
Проблема решается помещением сценария запуска менеджера рабочих столов на один из дополнительных уровней исполнения, а именно - на уровень исполнения 'a'. Этот уровень исполнения не настоящий: наш сценарий "xdm" просто вызывает "telinit a", что заставляет все сервисы на уровне исполнения 'a' начать работу после текущего уровня исполнения, то есть после того, как все getty будут запущены.
Дополнительную информацию об уровне исполнения 'a' можно получить, прочитав man init.
RC-сценарии определяют как основные функции каждого сервиса, так и зависимости при загрузке. Расположены они в /etc/init.d/.
#!/sbin/runscript depend() { need bar } start() { ebegin "Starting foo" /sbin/foo eend $? "Failed to start foo" } stop() { ebegin "Stopping foo" kill $(cat /var/run/foo.pid) eend $? "Failed to stop foo" }
Интерпретатор для RC-сценариев - "/sbin/runscript". Функция "depend" не обязательна. Каждый RC-сценарий должен иметь по крайней мере функцию "start".
Общепринятым порядком запуска сервисов на уровне исполнения является алфавитный - вследствие выходной информации, генерируемой /bin/ls.
Зависимости - основной способ уклониться от порядка исполнения по умолчанию. В других случаях (если между сервисами зависимости отсутствуют) можно использовать типы упорядочивания (order types).
Большинство сервисов имеют отношение или зависят от каких-либо других сервисов.
Например, для работы postfix необходима запущенная сеть и system logger.
С другой стороны, для samba также необходима работающая сеть. Однако, если для печати используется CUPS, то cupsd также должен быть запущен перед samba. Отметьте, что запуск cups не критичен для работы samba.
Таким образом, у нас есть два способа выразить отношения зависимости между различными сервисами. Эти зависимости имеют силу всегда, вне зависимости от того, целиком ли меняется уровень исполнения, или сервис был запущен или остановлен вручную после загрузки.
Используется, если зависимый сервис критичен для запуска текущего сервиса.
depend() { need net logger }
Сервисы, упомянутые после NEED критичны для работы текущего сервиса. Следовательно, если не удастся запустить какой-либо из зависимых сервисов, текущий сервис также запущен не будет. Каждый сервис, упомянутый в строке NEED будет запущен даже в том случае, если он НЕ добавлен к текущему или "boot" уровню исполнения. То есть, NEED - это "строгая" зависимость.
Сервис не критичен для работы текущего сервиса, но, если он используется, то запуск его должен произойти до начала работы текущего сервиса.
depend() { use portmap }
По умолчанию netmount может управлять точками монтирования NFS, но рассчитывать на portmap он будет только тогда, когда тот добавлен в текущий или загрузочный уровень исполнения. Каждому пользователю, имеющему в своем распоряжении точки монтирования NFS, следует добавить portmap на уровень исполнения по умолчанию, заставляя netmount опознать portmap как USE-зависимость и запустить его перед началом собственной работы.
Для того, чтобы считаться правильной USE-зависимостью, каждый сервис, упомянутый в строке USE, *должен* быть добавлен на текущий или загрузочный уровни исполнения. То есть,USE - это "слабая" зависимость.
Если какой-либо из сервисов, упомянутых в строке USE не сможет запуститься, текущий сервис все равно начнет свою работу, поскольку сервисы из строки USE не должны быть критичными для запуска.
Если между двумя сервисами нет отношений зависимости, но необходимо (или желательно) явно запустить один сервис после другого, можно использовать отношения AFTER и BEFORE. Оба типа действенны только во время смены уровня исполнения.
Также, оба они могут поддерживать шаблон "*" для включения всех остальных сервисов:
depend() { after * }
Заставит текущий сервис запуститься *после* всех остальных.
depend() { before bar }
Текущий сервис начнет работу *после* перечисленных в строке AFTER.
depend() { after foo }
Как принято в современном мире unix, существует множество разновидностей сервисов. Выбор обычно определяется пользователем или администратором.
Один из примеров - это system loggers, которых в Gentoo Linux насчитывается четыре разновидности. Все сервисы, которым для работы требуется запущенный system logger, не могут использовать NEED-зависимость сразу для всех четырех. А USE-зависимость - слишком слабая.
Именно здесь и вступают в действие виртуальные сервисы и тип PROVIDE.
Тип PROVIDE определяет виртуальный сервис, который все остальные сервисы могут подключать с помощью NEED или USE зависимостей.
depend() { provide logger }
LOGGER - это предопределенный виртуальный сервис, предоставляемый всеми system loggers. Его можно использовать с помощью типов зависимости NEED или USE.
Сервис NET - это еще один виртуальный сервис, но, в отличие от LOGGER, не предоставляющий PROVIDE явно.
Для того, чтобы предоставлять виртуальный сервис-NET, сервис должен:
Для каждого действительного сервиса net.* переменная $IFACE будет содержать имя сетевого интерфейса (например, "eth0" для net.eth0).
Каждый сервис может быть вызван с любым параметром по умолчанию. Все, упомянутые выше, уже определены, за исключением START и STOP, которые должны быть описаны пользователем в его rc-сценарии. Функция start() должна быть определена. Функция stop() менее важна и может быть опущена.
В принципе, пользователю потребуется объявить только функции start(), stop() и restart(). Все остальные - внутренние, их стоит оставить в покое.
# /etc/init.d/httpd startОпции командной строки можно комбинировать.
# /etc/init.d/net.eth0 pause start
START запускает текущий сервис, включая все те, от которых он зависит.
STOP останавливает текущий сервис, включая все те, от которых он зависит.
Сервис должен начинать работу с помощью RESTART. В этом случае будет перезапущен текущий и все зависимые сервисы. Если определена пользовательская функция restart(), то для запуска и останова сервиса должны использоваться функции "svc_start()" и "svc_stop()". Это сделано для правильной обработки всех зависимых сервисов.
Остановит текущий сервис, но, в отличие от STOP, ни один из зависимых сервисов остановлен не будет.
Помечает статус сервиса как остановленный.
Заметьте, что ни одна команда в функции stop() не выполняется. Следовательно, пользователь сам должен сделать все необходимые действия.
Опция INEED выводит список всех сервисов, указанных в разделе NEED запрашиваемого сервиса.
Опция NEEDSME выводит список всех сервисов, содержащих в разделе NEED имя запрашиваемого сервиса.
Опция IUSE выводит список всех сервисов, указанных в разделе USE запрашиваемого сервиса.
Опция USESME выводит список всех сервисов, содержащих в своем разделе USE имя запрашиваемого сервиса.
Выводит список пропущенных сервисов (если таковые присутствуют), содержащихся в разделе NEED опрашиваемого сервиса.
Добавить собственные опции командной строки довольно просто. Для этого в rc-сценарии должна быть определена функция с именем нужной опции и, как показано ниже, добавлена к содержимому переменной $opts.
opts="${opts} foo" foo() { ............ }
Настройка обычно производится с помощью переменных окружения. Однако эти переменные должны определяться не в самом rc-сценарии, а в одном из трех файлов настройки.
Один из них относится к самому rc-сценарию, два остальных - ко всей системе:
/etc/conf.d/<имя сценария> /etc/conf.d/basic /etc/rc.conf
Все три файла читаются системой в указанном порядке Все NET-сервисы также читают и /etc/conf.d/net.
rc-update - основной инструмент для добавления и удаления сервисов из уровня исполнения. Помимо этого, для обновления кэша зависимостей он запускает сценарий "depscan.sh".
# rc-update add metalog default
# rc-update del metalog default
Дополнительную информацию поможет получить запуск rc-update без аргументов.
depscan.sh упомянут здесь для полноты. Используется он для создания кэша зависимостей, который есть ни что иное, как таблица отображения зависимостей между сервисами.
Этот сценарий следует запускать всякий раз, когда в /etc/init.d/ добавляется новый сервис, но, поскольку rc-update запускает его автоматически, то большинству пользователей делать этого не потребуется.