Основы написания rc.d скриптов в BSD

Yar Tikhiy

$FreeBSD: doc/en_US.ISO8859-1/articles/rc-scripting/article.sgml,v 1.13 2007/08/16 13:08:42 yar Exp $

$FreeBSDru: frdp/doc/ru_RU.KOI8-R/articles/rc-scripting/article.sgml,v 1.3 2008/06/19 15:28:28 dindin Exp $

Практическое применение знаний о подсистеме rc.d, полученных из официальной документации BSD далеко не всегда бывает простым делом для новичка. В этой статье мы рассмотрим несколько типичных вариантов скриптов запуска, покажем, как использовать возможности rc.d в каждом из этих случаев и обсудим как это работает. Этот обзор должен дать вам преставление о подсистеме rc.d для последующей эффективной разработки.


Table of Contents
1 Вступление
2 Обозначение задачи
3 Простейший скрипт
4 Настраиваемый простейший скрипт
5 Запуск и остановка простого демона
6 Запуск более сложного демона
7 Присоединение rc.d скрипта к инфраструктуре
8 Создание более гибких rc.d скриптов
9 Литература для дальнейшего изучения

1 Вступление

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

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

Позже были предприняты попытки разделить /etc/rc на части, целью вынести некоторые наиболее важные элементы. Замечательный пример этого - скрипт /etc/netstart, инициализирующий работу сети. Этот скрипт позволял запустить сеть из однопользовательского режима, но его невозможно было полноценно интегрировать в систему автозапуска, поскольку части кода, имеющие отношение к сети нужно было чередовать с частями, к сети не относящимися. По этой причине скрипт /etc/netstart со временем мутировал в /etc/rc.network. Последний уже не является совершенно независимым скриптом, он состоит из больших, взаимозависимых функций, написанных на sh(1), которые, в свою очередь, вызываются из /etc/rc на разных этапах запуска системы. Тем временем, поскольку скрипты запуска стали больше, между ними появились сложные зависимости, ''квази-модульная'' система запуска стала еще запутаннее, чем монолитный скрипт /etc/rc.

Без простой и прозрачной подсистемы стартовые скрипты стали еще меньше удовлетворять потребности быстро развивающихся BSD-систем. Стало очевидно, что необходимы принципиальные шаги к достижению модульности и гибкости rc системы запуска. Исходя из этих соображений и была создана система запуска BSD rc.d. Ее признанными родителями стали Люк Мьюберн (Luke Mewburn) и сообщество NetBSD. Позже эта система была импортирована в FreeBSD. Ее название ссылается на расположение системных скриптов для отдельных сервисов, которые располагаются в /etc/rc.d. Немного позже мы рассмотрим отдельные компоненты системы rc.d и увидим, как запускаются отдельные скрипты.

Общая идея системы запуска BSD rc.d заключается в высокой степени модульности и повторном использовании кода. Высокая степень модульности значит, что каждый отдельный ''сервис'', такой как системный демон или простейшая задача, используют свой собственный скрипт, написанный на sh(1), который может запускать, останавливать, перезапускать этот сервис и проверять его статус. Стандартное действие выбирается из командной строки скрипта. /etc/rc так же как и раньше является основным загрузочным скриптом, но теперь он не выполняет весь процесс загрузки, а вызывает отдельные скрипты с параметром start. Так же легко выполняется остановка системы - для этого запускается этот же набор скриптов, но с аргументом stop. Это действие выполняется управляющим скриптом /etc/rc.shutdown. Обратите внимание, насколько точно эта система запуска соответствует традиционному в Unix принципу - использовать набор маленьких специализированных инструментов, каждый из которых призван решать конкретную задачу. Повторное использование кода это подход, который значит, что часто используемые операции реализованы в виде функций на языке sh(1) и объединены в файл/etc/rc.subr. Теперь типичный скрипт может состоять всего из нескольких строк кода на языке sh(1). И наконец, очень важная часть подсистемы rc.d - программа rcorder(8), которая которая помогает скрипту /etc/rc запускать отдельные скрипты в определенном порядке с учетом зависимостей между ними. В том числе, она так же помогает скрипту /etc/rc.shutdown, поскольку правильный порядок завершения работы системы противоположен порядку при запуске.

Система запуска BSD rc.d более подробно описана в статье Люка Мьюберна, а устройство отдельных компонентов - в документации к компонентам на соответствующих страницах справочника. Тем не менее, эта документация не дает однозначного описания того, как новичок может используя небольшое количество простых элементов создать полноценный rc.d для специфической задачи. Поэтому, основная цель этой статьи - показать несколько примеров использования системы запуска rc.d. Мы разберем несколько наиболее часто встречающихся случаев и покажем как можно в этих случаях использовать rc.d. Обратите внимание, что этот документ не является пошаговым описанием (''HOWTO''), поскольку мы не ставим задачу дать готовые рецепты на все случаи жизни. Нашей задачей является дать вам точку входа для самостоятельного творчества в системе запуска rc.d. Так же, эта статья не в коей мере не является заменой страницам справочника. Не ленитесь заглядывать в них для более точной и полной информации во время чтения этой статьи.

Есть несколько требований для полного понимания изложенного материала. Во первых, вы должны быть знакомы с программированием на скриптовом языке sh(1). Во вторых, вы должны понимать как система осуществляет стартовые и завершающие действия пространства пользователя, которые описаны в rc(8).

Эта статья делает основной упор на FreeBSD версию rc.d. Тем не менее, она так же может быть полезна разработчикам NetBSD. Не смотря на то, что системы запуска FreeBSD и NetBSD реализованы по разному, пользовательские интерфейсы предоставляемые ими практически идентичны.

Этот, и другие документы, могут быть скачаны с ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.
По вопросам, связанным с этой документацией, пишите <doc@FreeBSD.org>.
По вопросам, связанным с русским переводом документации, пишите в рассылку <frdp@FreeBSD.org.ua>.
Информация по подписке на эту рассылку находится на сайте проекта перевода.