12.5. Повторное открытие журнальных файлов
12.5. Повторное открытие журнальных файлов
Большинство системных демонов ведут журнальные файлы, записывая в них все, что они делают. Поскольку многие системы Unix месяцами работают без остановки, эти журнальные файлы могут стать достаточно большими. Простое периодическое удаление (или переименование) журнальных файлов — не самое хорошее решение, потому что демоны будут продолжать записывать в эти файлы, несмотря на их недоступность, а необходимость останавливать и запускать каждый демон для очистки журнальных файлов приводит к недоступности системы (хоть и на незначительное время). Общий способ для демонов справиться с упомянутой ситуацией — перехватывать SIGHUP и повторно открывать журнальные файлы. Это позволяет организовать ротацию журналов (периодическое открытие новых журнальных файлов при сохранении старых), используя простой сценарий вроде приведенного ниже.
dd /var/log
mv messages messages.old
killall -HUP syslogd
Logrotate (ftp://ftp.redhat.com/pub/redhat/code/logrotate/) — одна из программ, которая использует преимущество такого метода для выполнения безопасной ротации журналов.
Включение этой возможности у большинства демонов достаточно просто. Одним их наиболее легких подходов является использование глобальной переменной, которая индицирует необходимость повторного открытия журналов.
Затем обработчик сигнала SIGHUP в своем вызове устанавливает эту переменную, и главная часть программы проверяет эту переменную насколько можно часто. Ниже приведен пример соответствующей программы.
1: /*sighup.c*/
2:
3: #include <errno.h>
4: #include <signal.h>
5: #include <stdio.h>
6: #include <string.h>
7: #include <unistd.h>
8:
9: volatile int reopenLog = 0; /* volatile - поскольку модифицируется
10: обработчиком сигнала */
11:
12: /* записать строку в журнал */
13: void logstring(int logfd, char *str) {
14: write(logfd, str, strlen(str));
15: }
16:
17: /* когда приходит SIGHUP, сделать запись об этом и продолжить */
18: void hupHandler(int signum) {
19: reopenLog = 1;
20: }
21:
22: int main() {
23: int done = 0;
24: struct sigaction sa;
25: int rc;
26: int logfd;
27:
28: logfd = STDOUT_FILENO;
29:
30: /* Установить обработчик сигнала SIGHUP. Использовать memset() для
31: инициализации структуры sigaction чтобы обеспечить очистку
32: всего. */
33: memset(&sa, 0, sizeof(sa));
34: sa.sa_handler = hupHandler;
35:
36: if (sigaction(SIGHUP, &sa, NULL)) perror("sigaction");
37:
38: /* Записывать сообщение в журнал каждые две секунды, и
39: повторно открывать журнальный файл по требованию SIGHUP */
40: while (!done) {
41: /*sleep() возвращает не ноль, если не спит достаточно долго*/
42: rc = sleep(2);
43: if (rc) {
44: if (reopenLog) {
45: logstring(logfd,
46: "* повторное открытие журналов по запросу SIGHUP ");
47: reopenLog = 0;
48: } else {
49: logstring(logfd,
50: "* sleep прервано неизвестным сигналом "
51: "--dying ");
52: done=1;
53: }
54: } else {
55: logstring(logfd, "Периодическое сообщение ");
56: }
57: }
58:
59: return 0;
60: }
Чтобы протестировать эту программу, запустите ее в одном окне xterm и отправьте сигнал SIGHUP из другого. Для каждого сигнала SIGHUP, который принимает программа, она печатает сообщение, когда выполняет нормальную ротацию своих журналов. Помните, что если сигнал поступает в тот момент, когда работает другой экземпляр обработчика, доставляется только один экземпляр сигнала, поэтому не отправляйте их слишком часто.