Estoy trabajando en una aplicación de servidor que va a trabajar en Linux y Mac OS X. Se dice así:¿Qué tiene de especial el descriptor de archivo 3 en Linux?
- iniciar la aplicación principal
- tenedor del proceso regulador
- llamada lock_down() en el proceso de controlador
- terminar la aplicación principal
- el proceso de controlador entonces horquillas de nuevo, la creación de un proceso de trabajo
- , finalmente, el controlador mantiene bifurcan más trabajo er procesos
Puedo iniciar sesión utilizando varios de los métodos (p. syslog o un archivo) pero ahora estoy reflexionando sobre syslog. Lo "gracioso" es que no se ve ninguna salida syslog en el proceso del controlador a menos que incluya la sección #ifdef a continuación.
El trabajador procesa registros de manera impecable en Mac OS X y Linux con o sin la siguiente sección ifdef'ed. El controlador también se registra sin problemas en Mac OS X sin la sección # ifdef'ed, pero en Linux se necesita ifdef si deseo ver cualquier salida en syslog (o el archivo de registro para el caso) desde el proceso del controlador.
Entonces, ¿por qué es eso?
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 estaba cerca, pero utilizando closelog() era la idea de que resolvieron el problema por lo que el honor le corresponde a Jilles. Algo más, aparte de cerrar un descriptor de archivo debajo de los syslogs, los pies deben continuar. Para que el código añadí una llamada a closelog() justo antes del bucle:
closelog();
for (n = 0; n < rl.rlim_max; n++) {
if (close(n) && (EBADF != errno))
return EXIT_FAILURE;
}
me baso en una comprensión literal de la página del manual, diciendo:
El uso de openlog () es opcional; automáticamente será llamado por syslog() si es necesario ...
Lo interpreté diciendo que syslog detectaría si el descriptor del archivo se cerró debajo de él. Aparentemente no fue así. Se necesitaba un closelog() explícito en Linux para decirle a syslog que el descriptor estaba cerrado.
Una cosa más que todavía me desconcierta es que el hecho de no usar closelog() impidió que el primer proceso bifurcado (el controlador) siquiera se abriera y utilizara un archivo de registro. Los siguientes procesos bifurcados podrían usar syslog o un archivo de registro sin problemas. Tal vez haya algún efecto de almacenamiento en caché en el sistema de archivos que haga que el primer proceso bifurcado tenga una "idea" no confiable de los descriptores de archivos disponibles, mientras que el siguiente conjunto de proceso bifurcado se demore lo suficiente como para no verse afectado por esto.
+1 para 'profunda magia ... //' :-) ¿Quién necesita Harry Potter cuando se tiene el núcleo de Linux? –
entonces, ¿qué hay en la fd 3 en ese punto? – Gilles
@David. Nada que ver con el kernel. Ni siquiera fd 0, 1 y 2 son especiales para el kernel. – camh