Métodos

42 (V): pipex, tuberías de Unix

Dup2, fork y descriptores de fichero: recrear el funcionamiento de las tuberías de la shell y entenderlas de verdad.

42 (V): pipex, tuberías de Unix

Cada día usas tuberías en la terminal sin pensarlo: grep hello fichero | wc -l y listo. El proyecto pipex de 42 consiste en recrear ese mecanismo por dentro: un programa que ejecuta dos comandos conectados por una tubería, con redirección de entrada y salida a ficheros. Equivalente a un < infile cmd1 | cmd2 > outfile, pero escrito desde cero.

El problema

La tubería es muy fácil de usar y mucho menos intuitiva por dentro. Por dentro, es un par de descriptores de fichero: uno de lectura y otro de escritura que conecta dos procesos. La complicación real es orquestar todo a la vez: crear el pipe con pipe(), dividir el programa en dos procesos con fork(), redirigir la entrada y salida estándar de cada hijo con dup2() para que la salida del primer comando entre directamente al segundo, cerrar los descriptores que sobran —si no, el segundo nunca verá el final de la entrada— y ejecutar cada comando con execve(), encontrado previamente recorriendo el PATH del entorno. Y aún hay que llevar la cuenta de los errores: fichero de entrada inexistente, comando que no se encuentra, permisos que no están.

Cómo lo abordé

Aproveché la librería de la primera entrega, libft, para las partes genéricas: separar los comandos en argumentos y buscar las rutas. El resto lo organicé en una estructura con todo el estado del programa: los descriptores de los ficheros de entrada y salida, los extremos del pipe y las rutas resueltas de los dos comandos. Con el estado centralizado, el bucle de procesos quedó limpio: un hijo por comando, redirecciones con dup2, cierre de descriptores en orden y un padre que espera a los dos hijos con waitpid y devuelve el código de salida del segundo. Los detalles que más costaron fueron el cierre correcto de descriptores —un pipe no cerrado y el programa se cuelga— y reproducir el comportamiento de la shell ante errores: código 127 si el comando no existe, 126 si no es ejecutable. El repositorio, 42_pipex, incluye libft como subcarpeta y el código repartido en módulos pequeños: inicialización, ejecución y liberación de memoria, cada uno con su fichero.

Qué me llevé

Salí del proyecto con una sensación nueva: la terminal había dejado de ser una caja negra. Ahora sé qué pasa cuando pulso Enter y encadeno dos comandos: dos procesos, un pipe y unas cuantas redirecciones. También me quedó claro que fork y dup2 son la base de media internet: la shell, los servidores, los contenedores. Y una lección de método: cuando un programa tiene muchas piezas moviéndose, centralizar el estado en una estructura bien definida es la diferencia entre depurarlo y perderte en él.