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_<i>XXX</i>
(см. раздел Г.4), и ее ненулевое значение сообщает этим функциям, что нужно вызвать функцию
syslog
вместо функции
fprintf
(которая выводит сообщение об ошибке в стандартный поток сообщений об ошибках). Это спасает нас от необходимости проходить через весь наш код и вызывать одну из наших функций ошибок, если сервер не работает как демон (то есть когда мы проверяем сервер), а при работе в режиме демона заменять все вызовы на вызовы
syslog
.
Изменение рабочего каталога и сброс всех битов в маске режима создания файла
24
Мы изменяем рабочий каталог на корневой каталог, хотя у некоторых демонов могут быть причины изменить рабочий каталог на какой-либо другой. Например, демон печати может изменить его на каталог, в котором накапливается содержимое заданий для принтера и происходит вся работа по выводу данных на печать. Если демоном сбрасывается дамп (файл
core
), он появляется в текущем рабочем каталоге. Другой причиной для изменения рабочего каталога является то, что демон мог быть запущен в любой файловой системе, и если он там останется, эту систему нельзя будет размонтировать, во всяком случае, без жестких мер.
Закрытие всех открытых дескрипторов
25-27
Мы закрываем все открытые дескрипторы, которые наследуются от процесса, запустившего демон (обычно этим процессом бывает интерпретатор команд). Проблема состоит в определении наибольшего используемого дескриптора: в Unix нет ни одной функции, предоставляющей это значение. Есть способы определения максимального числа дескрипторов, которое может открыть процесс, но даже это достаточно сложно [110, с. 43], поскольку предел может быть бесконечным. Наше решение — закрыть первые 64 дескриптора, даже если большинство из них, возможно, не было открыто.
ПРИМЕЧАНИЕ
Solaris предоставляет функцию closefrom, позволяющую демонам решать эту проблему.
Перенаправление stdin, stdout и stderr в /dev/null
29-31
Некоторые демоны открывают
/dev/null
для чтения и записи и подключают к нему дескрипторы стандартных потоков ввода, вывода и сообщений об ошибках. Это гарантирует, что наиболее типичные дескрипторы открыты и операция чтения из любого из них возвращает 0 (конец файла), а ядро игнорирует все, что записано в любой из этих трех дескрипторов. Причина, по которой требуется открыть эти дескрипторы, заключается в том, что любая библиотечная функция, вызываемая демоном и считающая, что она может читать из стандартного потока ввода или записывать либо в стандартный поток вывода, либо в стандартный поток сообщений об ошибках, не должна завершиться с ошибкой. Отказ был бы потенциально опасен: если демон открывает сокет для связи с клиентом, дескриптор сокета воспринимается как стандартный поток вывода, поэтому ошибочный вызов какой-нибудь функции типа
perror
может привести к отправке клиенту нежелательных данных.
Использование демона syslogd для вывода сообщений об ошибках
32
Вызывается функция
openlog
. Первый ее аргумент берется из вызывающего процесса и обычно является именем программы (например,
argv[0]
). Мы указываем, что идентификатор процесса должен добавляться к каждому сообщению. Аргумент
facility
также задается вызывающим процессом, и его значением может быть константа из табл. 13.2 либо, если приемлемо значение по умолчанию
LOG_USER
, нулевое значение.
Отметим, что поскольку демон выполняется без управляющего терминала, он никогда не должен получать сигнал
SIGHUP
от ядра. Следовательно, многие демоны используют этот сигнал в качестве уведомления от администратора, что файл конфигурации демона изменился и демон должен еще раз считать файл. Два других сигнала, которые демон никогда не должен получать, — это сигналы
SIGINT
и
SIGWINCH
, и они также могут использоваться для уведомления демона о некоторых изменениях.