Я работаю над серверным приложением, которое будет работать на Linux и Mac OS X. Это происходит следующим образом:
- начать основное приложение
- вилка процесса контроллера
- вызов lock_down() в процессе контроллера
- завершить основное приложение
- процесс контроллера затем разворачивается снова, создавая рабочий процесс
- В конечном итоге контроллер продолжает разворачивать рабочие процессы
Я могу зарегистрировать несколько методов (например, syslog или файл), но сейчас я обдумываю syslog. "Смешно" заключается в том, что ни один вывод syslog не наблюдается в процессе контроллера, если я не включу ниже раздел #ifdef.
Рабочий обрабатывает журналы безупречно в Mac OS X и Linux с или без раздела ifdef'ed ниже. Контроллер также безукоризненно работает в 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() было идеей, которая сделала трюк, чтобы честь пошла в jilles. Что-то еще, кроме закрытия файлового дескриптора из-под syslogs, ноги должны продолжаться. Чтобы сделать работу с кодом, я добавил вызов closelog() непосредственно перед циклом:
closelog();
for (n = 0; n < rl.rlim_max; n++) {
if (close(n) && (EBADF != errno))
return EXIT_FAILURE;
}
Я полагался на дословное понимание страницы руководства, говоря:
Использование openlog() необязательно; он будет автоматически вызываться syslog() при необходимости...
Я интерпретировал это как сказать, что syslog обнаружит, был ли дескриптор файла закрыт под ним. Видимо, этого не случилось. Явный closelog() для linux был необходим, чтобы сообщить syslog, что дескриптор был закрыт.
Еще одна вещь, которая все еще озадачивает меня, заключается в том, что не использование функции closelog() не позволило первому разветвленному процессу (контроллеру) даже открыть и использовать файл журнала. Следующие разветвленные процессы могут без проблем использовать syslog или файл журнала. Возможно, в файловой системе есть некоторый эффект кеширования, который делает первый разветвленный процесс ненадежной "идеей", в котором имеются дескрипторы файлов, в то время как следующий набор разветвленных процессов достаточно задерживается, чтобы не повлиять на это?