6.23. Запуск и остановка служб (сценарии rc)

Сценарии rc.d используются для запуска служб при запуске системы и дают администратору стандартный способ остановки, запуска и перезапуска службы. Порты интегрируются в системную инфраструктуру rc.d. Подробности по её использованию можно найти в главе rc.d Руководства. Подробное объяснение доступных команд находится в rc(8) и rc.subr(8). Наконец, есть статьяо практических аспектах написания сценариев rc.d.

Установить можно один или более сценариев rc.d:

USE_RC_SUBR=	doormand

Сценарии обязаны размещаться в подкаталоге files с обязательным добавлением суффикса .in к имени файла. Для этого файла будут использоваться стандартные расширения SUB_LIST. Также особенно приветствуется использование расширений %%PREFIX%% и %%LOCALBASE%%. Подробнее о SUB_LIST в соответствующей главе.

До FreeBSD 6.1-RELEASE интеграция с rcorder(8) доступна через использование USE_RCORDER вместо USE_RC_SUBR. Однако, использовать этот метод не нужно, если ваш порт не включает опцию по своей установке в основную систему или службе не нужно запускаться до выполнения сценария FILESYSTEMS из rc.d основной системы.

Начиная с FreeBSD 6.1-RELEASE локальные сценарии rc.d (включая установленные из портов) включены в общий rcorder(8) основной системы.

Пример простого сценария rc.d:

#!/bin/sh

# $FreeBSD$
#
# PROVIDE: doormand
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf to enable doorman:
# doorman_enable (bool):      Set to "NO" by default.
#                             Set it to "YES" to enable doorman
# doorman_config (path):      Set to "%%PREFIX%%/etc/doormand/doormand.cf" by default.
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# doormand_enable (bool):	Set to NO by default.
#				Set it to YES to enable doormand.
# doormand_config (path):	Set to %%PREFIX%%/etc/doormand/doormand.cf
#				by default.
#

. /etc/rc.subr

name=doormand
rcvar=doormand_enable

load_rc_config $name

: ${doormand_enable:="NO"}
: ${doormand_config="%%PREFIX%%/etc/doormand/doormand.cf"}

command=%%PREFIX%%/sbin/${name}
pidfile=/var/run/${name}.pid

command_args="-p $pidfile -f $doormand_config"

run_rc_command "$1"

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

REQUIRE: LOGIN

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

KEYWORD: shutdown

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

Для необязательных элементов конфигурации присвоение переменной по умолчанию в стиле "=" является более предпочтительным по сравнению со стилем ":=", используемым здесь, поскольку первый устанавливает значение по умолчанию только если переменная не установлена, а последний устанавливает её, если переменная не установлена или обнулена. Пользователь вполне может написать в своем файле rc.conf.local что-нибудь типа

doormand_flags=""

и тогда произойдет неуместная подстановка переменной с использованием ":=", что переопределит намерения пользователя.

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

6.23.1. Остановка служб при удалении

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

В pkg-plist добавляются примерно такие строки:

@stopdaemon doormand

Параметр обязательно должен совпадать с содержимым переменной USE_RC_SUBR.

6.23.2. Контрольный список перед внесением изменений

Перед тем, как отсылать порт со сценарием rc.d, и тем более перед его коммитом, сверьтесь со следующим контрольным списком, чтобы убедиться, что порт для этого готов.

  1. Если это новый файл, заканчивается ли он на .sh? Если это так, то имя файла должно быть изменено на file.in, поскольку новые файлы rc.d не могут оканчиваться на такое расширение.

  2. Присутствует ли в файле тег $FreeBSD$?

  3. Соответствуют ли друг другу имя файла (без .in), строка PROVIDE и $name? Имя файла, совпадающее с PROVIDE, упрощает отладку, особенно для проблем, связанных с rcorder(8). Соответствие имени файла и $name также упрощает понимание, какие переменные имеют отношение к сценарию в rc.conf[.local]. Последнее также является тем, что вы могли бы назвать "политикой" для всех новых сценариев, включая те, что входят в базовую систему.

  4. Содержит ли строка REQUIRE значение LOGIN? Это условие обязательно для сценариев, работающих не из под суперпользователя. Если сценарий запускается из-под суперпользователя, то стоит ли его запускать до LOGIN? Если нет, то его следует запускать после, так чтобы мы могли свободно сгруппировать локальные сценарии в той точке rcorder(8), когда почти все сценарии в базовой системе уже стартовали.

  5. Запускает ли сценарий постоянную службу? Если да, то он должен иметь KEYWORD: shutdown.

  6. Убедитесь в том, что в сценарии отсутствует KEYWORD: FreeBSD. Это перестало быть нужным и нежелательно уже много лет. Это также служит индикатором того, что новый сценарий был скопирован со старого, поэтому особое внимание должно быть уделено при проверке.

  7. Если сценарий использует интерпретируемый язык, такой как perl, python или ruby, то убедитесь, что значение command_interpreter установлено должным образом. В противном случае

    # service name stop
    

    возможно будет работать неправильно. Смотрите service(8) для получения дополнительной информации.

  8. Все ли вхождения /usr/local были заменены на %%PREFIX%%?

  9. Идет ли присвоение переменным значений по умолчанию после load_rc_config?

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

  11. Действительно ли в сценариях используются значения, присвоенные переменным?

  12. Являются ли параметры по умолчанию, перечисленные в name_flags, обязательными? Если это так, то их следует поместить в command_args. Параметр -d здесь - это как красный флаг (прошу прощения за каламбур), поскольку обычно он применяется для “демонизации“ процесса и поэтому на самом деле обязательный.

  13. Никогда не включайте переменную name_flags в command_args (и наоборот; в прочем, такая ошибка встречается реже).

  14. Запускает ли сценарий какой-либо код безусловно? Это нехорошо. Обычно такие вещи могут/должны помещаться в start_precmd.

  15. Все логические условия должны использовать функцию checkyesno. Не пишите самописных проверок для [Yy][Ee][Ss], и так далее.

  16. Если в сценарии выполняется цикл (например, ожидание чего-либо перед стартом), используется ли счетчик для завершения цикла? Мы не хотим бесконечного ожидания загрузки в случае возникновения ошибки.

  17. Создает ли сценарий файлы или каталоги, которым нужны особые права доступа? Например, файл pid, который должен принадлежать пользователю, из-под которого запускается процесс. Вместо традиционных команд touch(1)/chown(8)/chmod(1) подумайте об использовании install(1) с подходящими аргументами командной строки, для того чтобы выполнить всю процедуру за один шаг.

По вопросам связанным с системой портов для FreeBSD, пишите по адресу <ports@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите по адресу <doc@FreeBSD.org>.