Я работаю над серверным приложением, которое будет работать на Linux и Mac OS X. Это выглядит так:
- запуск основного приложения
- форк контроллера процесса
- вызов lock_down () в процессе контроллера
- прекратить основное приложение
- процесс контроллера снова разветвляется, создавая рабочий процесс
- со временем контроллер продолжает разветвлять больше рабочих процессов
Я могу войти, используя несколько методов (например, syslog или файл), но сейчас я размышляю о syslog. Самое смешное, что в процессе контроллера не выводится никакой вывод системного журнала, если я не включу раздел #ifdef ниже.
Рабочий безошибочно обрабатывает журналы в Mac OS X и linux с разделом ifdef ниже или без него. Контроллер также безупречно ведет журнал в Mac OS X без раздела # ifdef, но в linux необходим ifdef, если я хочу увидеть какие-либо выходные данные в syslog (или файл журнала в этом отношении) из процесса контроллера.
Итак, почему это так?
static int
lock_down(void)
{
struct rlimit rl;
unsigned int n;
int fd0;
int fd1;
int fd2;
// Reset file mode mask
umask(0);
// change the working directory
if ((chdir("/")) < 0)
return EXIT_FAILURE;
// close any and all open file descriptors
if (getrlimit(RLIMIT_NOFILE, &rl))
return EXIT_FAILURE;
if (RLIM_INFINITY == rl.rlim_max)
rl.rlim_max = 1024;
for (n = 0; n < rl.rlim_max; n++) {
#ifdef __linux__
if (3 == n) // deep magic...
continue;
#endif
if (close(n) && (EBADF != errno))
return EXIT_FAILURE;
}
// attach file descriptors 0, 1 and 2 to /dev/null
fd0 = open("/dev/null", O_RDWR);
fd1 = dup2(fd0, 1);
fd2 = dup2(fd0, 2);
if (0 != fd0)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
camh был близок, но использование closelog () было идеей, которая добилась цели, поэтому честь досталась Джиллесу. Что-то еще, кроме закрытия файлового дескриптора из-под ног системного журнала, должно продолжаться. Чтобы код работал, я добавил вызов closelog () непосредственно перед циклом:
closelog();
for (n = 0; n < rl.rlim_max; n++) {
if (close(n) && (EBADF != errno))
return EXIT_FAILURE;
}
Я полагался на дословное понимание страницы руководства, говоря:
Использование openlog () необязательно; при необходимости он будет автоматически вызываться syslog () ...
Я интерпретировал это как высказывание, что syslog обнаружит, если дескриптор файла закрыт под ним. Видимо это не так. Явный closelog () в linux был необходим, чтобы сообщить системному журналу, что дескриптор закрыт.
Еще одна вещь, которая все еще вызывает недоумение, заключается в том, что не использование closelog () не позволяло первому разветвленному процессу (контроллеру) даже открывать и использовать файл журнала. Следующие разветвленные процессы могут без проблем использовать системный журнал или файл журнала. Может быть, в файловой системе есть какой-то эффект кэширования, который делает первый разветвленный процесс ненадежным «представлением» о том, какие файловые дескрипторы доступны, в то время как следующий набор разветвленных процессов достаточно задерживается, чтобы не зависеть от этого?