2010-08-20 5 views
18

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.

+3

+1 para 'profunda magia ... //' :-) ¿Quién necesita Harry Potter cuando se tiene el núcleo de Linux? –

+0

entonces, ¿qué hay en la fd 3 en ese punto? – Gilles

+0

@David. Nada que ver con el kernel. Ni siquiera fd 0, 1 y 2 son especiales para el kernel. – camh

Respuesta

6

syslog (3) puede mantener un descriptor de archivo en el socket de syslogd abierto; cerrar esto debajo de sus pies es probable que cause problemas. Una llamada closelog (3) puede ayudar.

13

El aspecto especial del descriptor de archivo 3 es que generalmente será el primer descriptor de archivo devuelto por una llamada al sistema que asigna un nuevo descriptor de archivo, dado que 0, 1 y 2 generalmente están configurados para stdin, stdout y stderr .

Esto significa que si cualquier función de biblioteca que haya llamado asigna un descriptor de archivo para sus propios fines internos con el fin de realizar sus funciones, será más fd 3.

El openlog (3) llamada a la librería necesitará abra /dev/log para comunicarse con el daemon syslog. Si posteriormente cierra todos los descriptores de archivos, puede interrumpir las funciones de la biblioteca syslog si no están escritas de una manera que lo maneje.

1

Syslog se une a un descriptor dado al inicio. La mayoría del tiempo descriptor 3. Si lo cierra no hay registros.

syslog-ng -d -v 

Le brinda más información acerca de lo que está haciendo detrás de escena.

La salida debe ser similar a algo como esto:

binding fd 3, inetaddr: 0.0.0.0, port: 514 
io.c: Preparing fd 3 for reading 
io.c: Preparing fd 4 for reading 
binding fd 5, unixaddr: /dev/log 
io.c: listening on fd 5 
+0

Esto es bueno para depurar syslog-ng ... pero no hace nada para ningún otro programa. fd3 en syslog-ng se puede conectar fácilmente a fd9 en algún otro proceso. –

+1

Es cierto, pero explica por qué no obtuvo nada en su registro después de ejecutar su código, lo que parecía ser lo que no estaba claro para él (que syslog se comunica utilizando un descriptor de archivo dado) – jdehaan

8

La forma de depurar esto en Linux es utilizar strace para rastrear las llamadas del sistema reales que se están realizando; el uso de un descriptor de archivo para syslog a continuación, se hace evidente:

$ cat syslog_test.c 
#include <stdio.h> 
#include <syslog.h> 

int main(void) 
{ 
    openlog("test", LOG_PID, LOG_LOCAL0); 
    syslog(LOG_ERR, "waaaaaah"); 
    closelog(); 
    return 0; 
} 
$ gcc -W -Wall -o syslog_test syslog_test.c 
$ strace ./syslog_test 
... 
socket(PF_FILE, SOCK_DGRAM, 0)   = 3 
fcntl64(3, F_SETFD, FD_CLOEXEC)   = 0 
connect(3, {sa_family=AF_FILE, path="/dev/log"}, 16) = 0 
send(3, "<131>Aug 21 00:47:52 test[24264]"..., 42, MSG_NOSIGNAL) = 42 
close(3)        = 0 
exit_group(0)       = ? 
Process 24264 detached 
Cuestiones relacionadas