cómo configurar close-on-exec por defecto

3 minutos de lectura

Estoy implementando una biblioteca para ejecutar comandos. La biblioteca es C, en Linux.

Actualmente realiza una llamada popen() para ejecutar un comando y obtener resultados. El problema es que el comando hereda todos los controladores de archivos abiertos actualmente.

Si hiciera un fork/exec, podría cerrar los controladores en child explícitamente. Pero eso significa volver a implementar popen().

¿Puedo configurar close-on-exec en todos los controladores sin recorrerlos uno por uno?

¿Puedo configurar close-on-exec como predeterminado para el proceso?

¡Gracias!

  • Si recorre los descriptores de archivo, lea el directorio /proc/self/fd/ para procesar solo los que están en uso en lugar de todos los descriptores de archivo posibles.

    – marca4o

    31 de octubre de 2009 a las 22:10

No y no.

Simplemente debe tener cuidado y configurar close-on-exec en todos los descriptores de archivos que le interesen.

Sin embargo, configurarlo es fácil:

#include <fcntl.h>
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);

#include <unistd.h>
/* please don't do this */
for (i = getdtablesize(); i --> 3;) {
    if ((flags = fcntl(i, F_GETFD)) != -1)
        fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
}

Si está ejecutando el kernel de Linux ≥2.6.23 y glibc ≥2.7, open (junto con otras llamadas al sistema similares) acepta una nueva bandera O_CLOEXEC:

#include <unistd.h>
fd = open("...", ... | O_CLOEXEC);

Si está ejecutando kernel de Linux ≥2.6.24 y glibc ≥2.7, fcntl acepta un nuevo argumento F_DUPFD_CLOEXEC:

#include <fcntl.h>
newfd = fcntl(oldfd, F_DUPFD_CLOEXEC);

Si está ejecutando Linux kernel ≥2.6.27 y glibc ≥2.9, hay nuevas llamadas al sistema pipe2, dup3etc., y muchas más llamadas al sistema obtienen nuevos *_CLOEXEC banderas:

#define _GNU_SOURCE
#include <unistd.h>
pipe2(pipefds, O_CLOEXEC);
dup3(oldfd, newfd, O_CLOEXEC);

Tenga en cuenta que POSIX especifica que

los popen() La función garantizará que cualquier flujo de datos anteriores popen() las llamadas que permanecen abiertas en el proceso principal se cierran en el nuevo proceso secundario.

así que si estás preocupado por que fuga, no seas.

  • al ser una biblioteca, no controlo cómo mis usuarios abren archivos, por lo que usar banderas en open() no es una opción

    – n-alejandro

    30 de octubre de 2009 a las 15:18

  • Lástima, no tiene suerte: UNIX (y Linux) no le permitirán cambiar la semántica subyacente de open et al. Tendrás que vivir con eso, como todos los demás.

    – efímero

    30 de octubre de 2009 a las 19:44

  • Ver lkml.org/lkml/2004/3/29/191 para ver un ejemplo de una propuesta de cloexec-by-default-switch siendo derribada. Esto se ha propuesto muchas veces y se ha rechazado tantas veces.

    – efímero

    30 de octubre de 2009 a las 19:48

  • solo compatibilidad con versiones anteriores de nuevo. Lástima que he visto muchos casos en los que los archivos heredados se atascaron porque un niño suelto no salió, y dado que está suelto, no hay mucho que puedas hacer al respecto. Ni siquiera matar fácilmente. ¿Es la bifurcación/ejecutivo manual con close realmente la única forma de construir algo confiable?

    – n-alejandro

    2 de noviembre de 2009 a las 11:14

  • @lothar socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0)

    – efímero

    24 de marzo de 2014 a las 1:16

avatar de usuario
jaroslav smid

Una pregunta un poco vieja, pero ¿qué hay del uso? getpid() en niño después fork()luego mira en /proc/PID/fd/ directorio y simplemente cierre todos los descriptores que encuentre allí (excepto 0, 1, 2 y el que obtiene de opendir()) y luego execve()?

  • Puede que me esté perdiendo algo, pero suena como una solución válida en Linux: mail.gnome.org/archives/gtk-devel-list/2015-March/msg00044.html. Levántate.

    – Víctor Sergio

    2 de julio de 2018 a las 18:47

  • Es un enfoque totalmente válido, es lo que generalmente se hace de hecho. yo usaría /proc/self/fd aunque para fds, ya que es un paso menos

    – raíz de dragón

    23 de noviembre de 2018 a las 19:53

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad