Наши партнеры

UnixForum






Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Тематический каталог -> Процесс начальной загрузки системы

Система инициализации Gentoo Linux 1.0

Авторы:
Martin Schlemmer
Seemant Kulleen

Перевод:
Кирилл Васильев

Настоящее руководство является введением в систему инициализации Gentoo Linux, а также освещает некоторые детали написания rc-сценариев.

1.0.2 Jan 12 2003

Введение

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

Уровни исполнения (runlevels)

В отличие от прочих систем инициализации, у уровней исполнения в 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-сценарии

RC-сценарии определяют как основные функции каждого сервиса, так и зависимости при загрузке. Расположены они в /etc/init.d/.

Базовая схема RC-сценария

#!/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.

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

Тип зависимости NEED

Используется, если зависимый сервис критичен для запуска текущего сервиса.

добавление logger и net в качестве NEED-зависимости

depend() {
    need net logger
}

Сервисы, упомянутые после NEED критичны для работы текущего сервиса. Следовательно, если не удастся запустить какой-либо из зависимых сервисов, текущий сервис также запущен не будет. Каждый сервис, упомянутый в строке NEED будет запущен даже в том случае, если он НЕ добавлен к текущему или "boot" уровню исполнения. То есть, NEED - это "строгая" зависимость.

Тип зависимости USE

Сервис не критичен для работы текущего сервиса, но, если он используется, то запуск его должен произойти до начала работы текущего сервиса.

добавление portmap в качестве USE-зависимости для netmount

depend() {
    use portmap
}

По умолчанию netmount может управлять точками монтирования NFS, но рассчитывать на portmap он будет только тогда, когда тот добавлен в текущий или загрузочный уровень исполнения. Каждому пользователю, имеющему в своем распоряжении точки монтирования NFS, следует добавить portmap на уровень исполнения по умолчанию, заставляя netmount опознать portmap как USE-зависимость и запустить его перед началом собственной работы.

Для того, чтобы считаться правильной USE-зависимостью, каждый сервис, упомянутый в строке USE, *должен* быть добавлен на текущий или загрузочный уровни исполнения. То есть,USE - это "слабая" зависимость.

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

Управление порядком загрузки без применения зависимостей

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

Также, оба они могут поддерживать шаблон "*" для включения всех остальных сервисов:

пример шаблона для AFTER

depend() {
    after *
}

Заставит текущий сервис запуститься *после* всех остальных.

Тип BEFORE

Текущий сервис начнет работу *перед* перечисленными в строке BEFORE.

запустим foo перед bar (отрывок из foo)

depend() {
   before bar
}

Тип AFTER

Текущий сервис начнет работу *после* перечисленных в строке AFTER.

запустим bar после foo (отрывок из bar)

depend() {
    after foo
}

Виртуальные сервисы

Как принято в современном мире unix, существует множество разновидностей сервисов. Выбор обычно определяется пользователем или администратором.

Один из примеров - это system loggers, которых в Gentoo Linux насчитывается четыре разновидности. Все сервисы, которым для работы требуется запущенный system logger, не могут использовать NEED-зависимость сразу для всех четырех. А USE-зависимость - слишком слабая.

Именно здесь и вступают в действие виртуальные сервисы и тип PROVIDE.

Тип PROVIDE

Тип PROVIDE определяет виртуальный сервис, который все остальные сервисы могут подключать с помощью NEED или USE зависимостей.

sysklogd предоставляет logger

depend() {
    provide logger
}

LOGGER - это предопределенный виртуальный сервис, предоставляемый всеми system loggers. Его можно использовать с помощью типов зависимости NEED или USE.

Виртуальный сервис NET

Сервис NET - это еще один виртуальный сервис, но, в отличие от LOGGER, не предоставляющий PROVIDE явно.

Для того, чтобы предоставлять виртуальный сервис-NET, сервис должен:

  • Быть добавленным к текущему или загрузочному уровню исполнения
  • Иметь в начале своего имени "net.".
  • Часть имени после "net." должна быть именем существующего сетевого интерфейса (например, net.eth0 или net.ppp1 for example).

Для каждого действительного сервиса net.* переменная $IFACE будет содержать имя сетевого интерфейса (например, "eth0" для net.eth0).

Опции командной строки по умолчанию

Каждый сервис может быть вызван с любым параметром по умолчанию. Все, упомянутые выше, уже определены, за исключением START и STOP, которые должны быть описаны пользователем в его rc-сценарии. Функция start() должна быть определена. Функция stop() менее важна и может быть опущена.

В принципе, пользователю потребуется объявить только функции start(), stop() и restart(). Все остальные - внутренние, их стоит оставить в покое.

запустить сервис httpd

# /etc/init.d/httpd start
Опции командной строки можно комбинировать.

приостановить, а затем запустить net.eth0

# /etc/init.d/net.eth0 pause start

Опции START и STOP

START запускает текущий сервис, включая все те, от которых он зависит.

STOP останавливает текущий сервис, включая все те, от которых он зависит.

Опция RESTART

Сервис должен начинать работу с помощью RESTART. В этом случае будет перезапущен текущий и все зависимые сервисы. Если определена пользовательская функция restart(), то для запуска и останова сервиса должны использоваться функции "svc_start()" и "svc_stop()". Это сделано для правильной обработки всех зависимых сервисов.

Опция PAUSE

Остановит текущий сервис, но, в отличие от STOP, ни один из зависимых сервисов остановлен не будет.

Опция ZAP

Помечает статус сервиса как остановленный.

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

Опция INEED

Опция INEED выводит список всех сервисов, указанных в разделе NEED запрашиваемого сервиса.

Опция NEEDSME

Опция NEEDSME выводит список всех сервисов, содержащих в разделе NEED имя запрашиваемого сервиса.

Опции IUSE и USESME

Опция IUSE выводит список всех сервисов, указанных в разделе USE запрашиваемого сервиса.

Опция USESME выводит список всех сервисов, содержащих в своем разделе USE имя запрашиваемого сервиса.

Опция BROKEN

Выводит список пропущенных сервисов (если таковые присутствуют), содержащихся в разделе NEED опрашиваемого сервиса.

Добавление собственных опций командной строки

Добавить собственные опции командной строки довольно просто. Для этого в rc-сценарии должна быть определена функция с именем нужной опции и, как показано ниже, добавлена к содержимому переменной $opts.

собственная опция foo

opts="${opts} foo"

foo() {
    ............
}

Настройка

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

Один из них относится к самому rc-сценарию, два остальных - ко всей системе:

Файлы настройки для rc-сценариев

/etc/conf.d/<имя сценария>
/etc/conf.d/basic
/etc/rc.conf

Все три файла читаются системой в указанном порядке Все NET-сервисы также читают и /etc/conf.d/net.

Утилиты и сценарии-помощники

Утилита rc-update

rc-update - основной инструмент для добавления и удаления сервисов из уровня исполнения. Помимо этого, для обновления кэша зависимостей он запускает сценарий "depscan.sh".

добавить metalog на уровень исполнения по умолчанию

# rc-update add metalog default

удалить metalog с уровня исполнения по умолчанию

# rc-update del metalog default

Дополнительную информацию поможет получить запуск rc-update без аргументов.

Сценарий-помощник depscan.sh

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

Этот сценарий следует запускать всякий раз, когда в /etc/init.d/ добавляется новый сервис, но, поскольку rc-update запускает его автоматически, то большинству пользователей делать этого не потребуется.