Серверная (www.it-simple.ru)

Как создать свою службу в Linux


Рецепт простой.

  1. Создаём скрипт для управления сервисом, в специальном формате.
  2. Помещаем его в хранилище сервисных скриптов. Это каталог /etc/init.d
  3. Обрабатываем скрипт специальной утилитой update-rc.d (или insserv)

Шаг 1. Создание скрипта

Вот шаблон, чтобы не запутаться:

#!/bin/sh

### BEGIN INIT INFO
# Provides:          scriptName
# Required-Start:    $all
# Required-Stop:     $all
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example my init script
# Description:       This file should be used to construct scripts to be placed in /etc/init.d
### END INIT INFO

# Здесь должен находиться основной код.
# Этот код должен обрабатывать команды start, stop и restart, переданные скрипту.
# Использование других команд не возбраняется.
# Для наглядного примера можно посмотреть любой файл из /etc/init.d/

Шаблон от разработчиков находится по адресу /etc/init.d/skeleton

Обратите внимание на блок, ограниченный метками [### BEGIN INIT INFO] и [### END INIT INFO]. Он выделен жирным.

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

Подробнее про процессы, службы, уровни запуска и устройство каталогов запуска можно прочитать здесь (http://www.it-simple.ru/?p=1376).

Этот блок обязателен для скрипта, управляющего сервисом. Остановимся на нём подробнее.

### BEGIN INIT INFO - метка начала списка инструкций
### END INIT INFO - метка конца списка инструкций

Все строки между ними должны быть в формате:

# Инструкция: арг1 [арг2...]

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

Список инструкций
Данный список взят по одной из ссылок в конце записи, описания нуждаются в доработке

ProvidesОписывает предоставляемые этим скриптом объекты (арг1, агр2, ...) таким способом, что, когда скрипт запускается с аругментом start, данные объекты считаются существующими, и, следовательно, другие скрипты в init, которые требуют существование этих объектов, смогут запуститься на более поздней стадии. Обычно, можно использовать имя скрипта в качестве объекта, но так же можно использовать имя сервиса, которую он заменяет. Виртуальные объекты тут не указываются. Они определены вне скриптов init.d
Required-StartЗадаёт объекты, которые должны существовать, чтобы запустить скрипт. Можно использовать при необходимости виртуальные объекты, как описано ниже. Если объекты не указаны, то этот скрипт может быть запущен сразу после старта, не требуя подключенных локальных файловых систем, запущенного системного журнала и т.д.
Required-StopЗадаёт объекты, используемые сервисом, предоставляемой скриптом. Объект, предоставляемый этим скриптом должен завершиться до завершения перечисленных здесь объектов, чтобы избежать конфликтов. Обычно, здесь указывают те же объекты, что и в Required-Start
Should-StartЗадаёт объекты, которые, если существуют, должны должны быть запущены перед сервисом, предоставляемым данным скриптом. Это допускает слабые зависимости, которые не приводят сервис к ошибке, если объекты не доступны. Можно использовать при необходимости виртуальные объекты, как описано ниже.
Should-StopЗадаёт объекты, если существуют должны быть остановлены уже после данного сервиса. Обычно, здесь указывают те же объекты, что и в Should-Start
Default-Start
Default-Stop
Задаёт уровни запуска, на которых скрипт должен быть запущен (остановлен) по умолчанию. Например, если сервис должен быть запущен на только уровнях 3, 4 и 5, укажите "Default-Start: 3 4 5" и "Default-Stop: 0 1 2 6".
Short-DescriptionЗадаёт короткое описание действия скрипта. Ограничено одной строкой.
DescriptionЗадаёт более подробное описание действия скрипта. Может быть в несколько строк, в этом случае, каждая строка описания должна начинаться с символа # с последующим знаком табуляции или как минимум 2-мя символами пробела. Описание заканчивается перед линией, не совпадающим с этим условием.
X-Start-Before
X-Stop-After
Задаёт обратные зависимости, которые значат то же, как если бы они были указаны в should-start и should-stop в пакетах, указанных тут.

Уровни запуска определяют, в какие из каталогов /etc/rcX.d будут помещены ссылки на текущий скрипт.

Для отслеживания зависимостей важны инструкции Provides, Required- и Should-. Остальные не используются. На основе зависимостей утилита update-rc.d (или insserv) упорядочивает скрипты в каталоге определённого уровня запуска (/etc/rcX.d).

Список виртуальных объектов
Та же хрень, что и с предыдущим списком

$local_fsВсе локальные фаловые системы подключены. Все скрипты, которые производят запись в /var/ должны зависеть от этого, если они уже не зависят от $remote_fs
$networkнизкоуровневая сеть, т.е. сетевые карты, может подразумеваться PCMCIA запущеной
$namedДемоны, которые могут предоставлять разрешение доменных имён предполагаются запущенными. Например, DNS, NIS+ или LDAP
$portmapДемоны, предоставляющие сервис SunRPC/ONCRPC portmapping как указано в 1833 (если они есть)
$remote_fsВсе файловые системы подключены. Скрипты, которые должны быть запущены во время остановки системы до того, как всем процессам будет отправлен сигнал уничтожения, должны зависеть от $remote_fs.
$syslogсистемный журнал функционирует
$timeустановленно корректное системное время, например, ntp или rdate, или RTC
$allЗапускает скрипт как можно последним

Шаг 2+3. Оформление скрипта в качестве службы

Допустим, имя нашего самописного скрипта somestuff. Именно так, somestuff, без всяких расширений.
Делаем его исполняемым:

chmod +x ./somestuff

Копируем в хранилище сервисных скриптов:

cp ./somestuff /etc/init.d

И делаем прописку в каталогах уровней запуска:

update-rc.d somestuff defaults

Полный путь давать не надо, только имя в /etc/init.d/

Для выписки (удаления всех симлинков на этот скрипт из всех каталогов уровней запуска) делаем:

update-rc.d -f somestuff remove

Исходный скрипт /etc/init.d/somestuff при этом не удаляется.