KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

Уильям Стивенс - UNIX: разработка сетевых приложений

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

Например, демон может сделать следующий вызов, когда вызов функции rename неожиданно оказывается неудачным:

syslog(LOG_INFO|LOG_LOCAL2, "rename(%s, %s): %m", file1, file2);

Назначение аргументов facility и level в том, чтобы все сообщения, которые посылаются процессами определенного типа (то есть с одним значением аргумента facility), могли обрабатываться одинаково в файле /etc/syslog.conf или чтобы все сообщения одного уровня (с одинаковым значением аргумента level) обрабатывались одинаково. Например, файл конфигурации может содержать строки

kern.* /dev/console

local7.debug /var/log/cisco.log

для указания, что все сообщения ядра направляются на консоль, а сообщения относительно отладки со значением аргумента facility, равным local7, добавляются в файл /var/log/cisco.log.

Когда приложение впервые вызывает функцию syslog, она создает дейтаграммный доменный сокет Unix и затем вызывает функцию connect для сокета с заранее известным полным именем, которое создано демоном syslogd (например, /var/run/log). Этот сокет остается открытым, пока процесс не завершится. Другим вариантом является вызов процессом функций openlog и closelog.

#include <syslog.h>


void openlog(const char *ident, int options, int facility);

void closelog(void);

Функция openlog может быть вызвана перед первым вызовом функции syslog, а функция closelog — когда приложение закончит отправлять сообщения в журнал.

Аргумент ident — это строка, которая будет добавлена в начало каждого журнального сообщения функцией syslog. Часто это имя программы.

Обычно аргумент options формируется путем применения операции логического ИЛИ к константам из табл. 13.3.


Таблица 13.3. Аргумент options (параметр) для функции openlog

Параметр Описание LOG_CONS Выводить журнал на консоль, если невозможно послать сообщение демону syslogd LOG_NDELAY Не откладывать создание сокета, открыть его сейчас LOG_PERROR Записывать сообщение в stderr, а также посылать его демону syslogd LOG_PID Включать идентификатор процесса (PID) в каждую запись журнала

Обычно доменный сокет Unix не создается при вызове функции openlog. Вместо этого сокет открывается при первом вызове функции syslog. Параметр LOG_NDELAY указывает, что сокет должен создаваться при вызове функции openlog.

Аргумент facility функции openlog задает значение facility, используемое по умолчанию для любого последующего вызова функции syslog, при котором не задается аргумент facility. Некоторые демоны вызывают функцию openlog и задают значение аргумента facility (которое обычно не изменяется для данного демона) и затем в каждом вызове функции syslog задают только аргумент level (поскольку level может изменяться в зависимости от ошибки).

Сообщения для записи в журнал могут также генерироваться командой logger. Это может использоваться в сценариях интерпретатора команд, например для отправки сообщений демону syslogd.

13.4. Функция daemon_init

В листинге 13.1[1] показана функция, называемая daemon_init, которую мы можем вызвать (обычно с сервера), чтобы придать процессу свойства демона.

Листинг 13.1. Функция daemon_init: придание процессу свойств демона

//daemon _init.с

 1 #include "unp.h"

 2 #include <syslog.h>


 3 #define MAXFD 64


 4 extern int daemon_proc; /* определен в error.с */


 5 int

 6 daemon_init(const char *pname, int facility)

 7 {

 8  int i;

 9  pid_t pid;


10  if ((pid = Fork()) < 0)

11   return (-1);

12  else if (pid)

13   _exit(0); /* родитель завершается */


14  /* 1-й дочерний процесс продолжает работу... */


15  if (setsid() < 0) /* становится главным процессом сеанса */

16   return (-1);


17  Signal(SIGHUP, SIG_IGN);

18  if ((pid = Fork()) < 0)

19   return (-1);

20  else if (pid)

21   _exit(0); /* 1-й дочерний процесс завершается */


22  /* 2-й дочерний процесс продолжает работу */


23  daemon_proc = 1; /* для функций err_XXX() */


24  chdir("/"); /* смена текущего каталога */


25  /* закрытие дескрипторов файлов*/

26  for (i = 0; i < MAXFD; i++)

27   close(i);


28  /* перенаправление stdin, stdout и stderr в /dev/null */

29  open("/dev/null", O_RDONLY);

30  open("/dev/null", O_RDWR);

31  open("/dev/null", O_RDWR);


32  openlog(pname, LOG_PID, facility);


33  return (0); /* успешное завершение */

34 }

Вызов функции fork

10-13 Сначала мы вызываем функцию fork, после чего родительский процесс завершается, а дочерний продолжается. Если процесс был запущен из интерпретатора команд в фоновом режиме, то, когда родительский процесс завершается, оболочка считает, что команда выполнена. Это автоматически запускает дочерний процесс в фоновом режиме. Дочерний процесс наследует идентификатор группы процессов от родительского процесса, но получает свой собственный идентификатор процесса. Это гарантирует, что дочерний процесс не является главным в группе процессов, что требуется для следующего вызова функции setsid.

Вызов функции setsid

15-16 Функция setsid — это функция POSIX, создающая новый сеанс. (В главе 9 [110] подробно рассказывается о взаимоотношениях процессов.) Процесс становится главным в новом сеансе, становится главным в новой группе процессов и не имеет управляющего терминала.

Игнорирование сигнала SIGHUP и новый вызов функции fork

17-21 Мы игнорируем сигнал SIGHUP и снова вызываем функцию fork. Когда эта функция завершается, родительский процесс на самом деле является первым дочерним процессом, и он завершается, оставляя выполняться второй дочерний процесс. Назначение второй функции fork — гарантировать, что демон не сможет автоматически получить управляющий терминал, если потом он откроет устройство терминала. В SVR4, когда главный процесс сеанса без управляющего терминала открывает устройство терминала (которое в этот момент не является управляющим терминалом для другого сеанса), терминал становится управляющим терминалом главного процесса сеанса. Но вызывая второй раз функцию fork, мы гарантируем, что второй дочерний процесс больше не является главным в сеансе, поэтому он не может получить управляющий терминал. Сигнал SIGHUP приходится игнорировать, поскольку, когда главный процесс сеанса завершает работу (первый дочерний процесс), всем процессам в сеансе (нашему второму дочернему процессу) посылается сигнал SIGHUP.

Установка флага для функций ошибок

23 Мы присваиваем глобальной переменной daemon_proc ненулевое значение. Эта внешняя переменная задается нашими функциями err_XXX (см. раздел Г.4), и ее ненулевое значение сообщает этим функциям, что нужно вызвать функцию syslog вместо функции fprintf (которая выводит сообщение об ошибке в стандартный поток сообщений об ошибках). Это спасает нас от необходимости проходить через весь наш код и вызывать одну из наших функций ошибок, если сервер не работает как демон (то есть когда мы проверяем сервер), а при работе в режиме демона заменять все вызовы на вызовы syslog.

Изменение рабочего каталога и сброс всех битов в маске режима создания файла

24 Мы изменяем рабочий каталог на корневой каталог, хотя у некоторых демонов могут быть причины изменить рабочий каталог на какой-либо другой. Например, демон печати может изменить его на каталог, в котором накапливается содержимое заданий для принтера и происходит вся работа по выводу данных на печать. Если демоном сбрасывается дамп (файл core), он появляется в текущем рабочем каталоге. Другой причиной для изменения рабочего каталога является то, что демон мог быть запущен в любой файловой системе, и если он там останется, эту систему нельзя будет размонтировать, во всяком случае, без жестких мер.

Закрытие всех открытых дескрипторов

25-27 Мы закрываем все открытые дескрипторы, которые наследуются от процесса, запустившего демон (обычно этим процессом бывает интерпретатор команд). Проблема состоит в определении наибольшего используемого дескриптора: в Unix нет ни одной функции, предоставляющей это значение. Есть способы определения максимального числа дескрипторов, которое может открыть процесс, но даже это достаточно сложно [110, с. 43], поскольку предел может быть бесконечным. Наше решение — закрыть первые 64 дескриптора, даже если большинство из них, возможно, не было открыто.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*