Решением обеих этих проблем является создание обработчика сигнала SIGHUP и выполнение внутри него всех необходимых шагов. В разделе 34.4 отмечалось, что сигнал SIGHUP генерируется для контролирующего процесса при отключении его от контролирующего терминала. Поскольку демоны лишены соединения с терминалом, они никогда не получают этот сигнал и могут использовать его в целях, описанных в данном разделе.

Для автоматической ротации журнальных файлов демона можно применить программу logrotate. Подробности ищите на справочной странице logrotate(8).

В листинге 37.3 приводится пример того, каким образом демон может использовать сигнал SIGHUP. Программа устанавливает обработчик SIGHUP , становится демоном , открывает журнальный файл и считывает файл конфигурации . Обработчик всего лишь присваивает значение глобальной переменной hupReceived, которое проверяется главной функцией. Главная функция выполняет цикл, записывая сообщение в журнальный файл каждые 15 секунд . Вызовы sleep() в этом цикле должны имитировать некие вычисления, которые могли бы проводиться настоящим приложением. После возвращения вызова sleep() программа проверяет, было ли установлено значение переменной hupReceived ; если ответ положительный, она заново открывает журнальный файл, повторно считывает конфигурацию и сбрасывает значение hupReceived.

Для лаконичности функции logOpen(), logClose(), logMessage() и readConfigFile() не вошли в листинг 37.3, но вы можете найти их в архиве с исходным кодом, который прилагается к этой книге. О назначении первых трех из них можно догадаться по их именам, а функция readConfigFile() просто считывает строчку из конфигурационного файла и записывает ее в журнал.

Некоторые демоны используют альтернативный метод повторной инициализации при получении сигнала SIGHUP, закрывая все файлы и перезапускаясь с помощью вызова exec().

Ниже представлен пример работы программы из листинга 37.3. Сначала мы создаем фиктивный конфигурационный файл, после чего запускается демон:

$ echo START > /tmp/ds.conf

$ ./daemon_SIGHUP

$ cat /tmp/ds.log Выводим журнальный файл

2011-01–17 11:18:34: Opened log file

2011-01–17 11:18:34: Read config file: START

Теперь, прежде чем отправить демону сигнал SIGHUP, изменим конфигурационный файл и переименуем журнал:

$ echo CHANGED > /tmp/ds.conf

$ date +'%F %X'; mv /tmp/ds.log /tmp/old_ds.log

2011-01–17 11:19:03 AM

$ date +'%F %X'; killall — HUP daemon_SIGHUP

2011-01–17 11:19:23 AM

$ ls /tmp/*ds.log Журнальный файл был повторно открыт

/tmp/ds.log /tmp/old_ds.log

$ cat /tmp/old_ds.log Выводим старый журнальный файл

2011-01–17 11:18:34: Opened log file

2011-01–17 11:18:34: Read config file: START

2011-01–17 11:18:49: Main: 1

2011-01–17 11:19:04: Main: 2

2011-01–17 11:19:19: Main: 3

2011-01–17 11:19:23: Closing log file

Вывод команды ls показывает наличие как старого, так и нового журнального файла. Просматривая старый журнал с помощью утилиты cat, мы можем увидеть, что даже после ввода команды mv для переименования файла демон продолжает записывать в него сообщения. На этом этапе старый журнальный файл можно удалить, если он нам больше не нужен. Содержимое нового журнала указывает на то, что конфигурационный файл был прочитан заново:

$ cat /tmp/ds.log

2011-01–17 11:19:23: Opened log file

2011-01–17 11:19:23: Read config file: CHANGED

2011-01–17 11:19:34: Main: 4

$ killall daemon_SIGHUP Завершаем работу демона

Обратите внимание на то, что журнальный и конфигурационный файлы демонов обычно размещаются в стандартных каталогах, а не в /tmp, как это сделано в программе из листинга 37.3. Конфигурацию принято хранить в каталоге /etc или в одном из его подкаталогов, а журнал часто находится в /var/log. Программы-демоны обычно предоставляют параметры командной строки, которые позволяют указать альтернативные пути вместо стандартных.

Листинг 37.3. Использование сигнала SIGHUP для повторной инициализации демона

daemons/daemon_SIGHUP.c

#include

#include

#include "become_daemon.h"

#include "tlpi_hdr.h"

static const char *LOG_FILE = "/tmp/ds.log";

static const char *CONFIG_FILE = "/tmp/ds.conf";

/* Определения функций logMessage(), logOpen(), logClose()

и readConfigFile() в этом листинге опущены */

static volatile sig_atomic_t hupReceived = 0;

/* При получении SIGHUP устанавливаем ненулевое значение */

static void

sighupHandler(int sig)

{

 hupReceived = 1;

}

int

main(int argc, char *argv[])

{

const int SLEEP_TIME = 15; /* Период бездействия между сообщениями */

int count = 0; /* Количество завершенных интервалов SLEEP_TIME */

int unslept; /* Время, оставшееся до завершения периода бездействия */

struct sigaction sa;

sigemptyset(&sa.sa_mask);

Перейти на страницу:

Похожие книги