pipex est un projet systèmes en C où je recrée le comportement d’un pipe UNIX entre deux commandes. L’idée est de comprendre “ce qui se passe vraiment” derrière une ligne de shell, en manipulant directement les appels système : processus, redirections, pipes et exécution de commandes.

L’objectif est double :

  • Comprendre comment le shell connecte l’output d’une commande à l’input d’une autre via pipe().
  • Maîtriser la gestion de processus avec fork() + execve() et les redirections avec dup2().

Principe

Le programme est lancé ainsi :

./pipex file1 cmd1 cmd2 file2

Il doit se comporter comme la commande shell suivante :

< file1 cmd1 | cmd2 > file2

Concrètement :

  1. Ouvrir file1 en lecture et file2 en écriture.
  2. Créer un pipe (pipe(fd)) pour relier deux processus.
  3. fork #1 :
  • rediriger stdin vers file1
  • rediriger stdout vers l’entrée du pipe
  • exécuter cmd1
    4. fork #2 :

  • rediriger stdin vers la sortie du pipe

  • rediriger stdout vers file2
  • exécuter cmd2
    5. Fermer les bons descripteurs et wait() les enfants.

Points importants

  • Parsing des commandes : gérer cmd + arguments (ex. "ls -l") et construire argv pour execve().
  • Résolution du binaire : retrouver le chemin de la commande via PATH (ou gérer un chemin absolu/relatif).
  • Redirections propres : fermer systématiquement les fd inutiles pour éviter les deadlocks et fuites de descripteurs.
  • Gestion d’erreurs : messages clairs (permissions, fichier absent, commande introuvable, etc.) et exit codes cohérents.

Contraintes respectées

  • Appels système typiques : open/close, dup/dup2, pipe, fork, execve, wait/waitpid, access, etc.
  • Gestion mémoire : malloc/free (zéro leak)
  • Makefile standard (pas de relink)
  • Libft autorisée (si intégrée)

Ce que ça m’a apporté

pipex m’a fait passer un cap sur la programmation UNIX : compréhension des flux (stdin/stdout), maîtrise des processus et du cycle fork → exec, et rigueur sur la gestion des ressources (fd/mémoire). C’est une base très concrète pour la suite (minishell, webserv, etc.).

Bonus

  • Chaînage de plusieurs commandes :

bash ./pipex file1 cmd1 cmd2 cmd3 ... cmdn file2

équivalent à :

bash < file1 cmd1 | cmd2 | cmd3 ... | cmdn > file2

  • Support here_doc :

bash ./pipex here_doc LIMITER cmd cmd1 file

équivalent à :

bash cmd << LIMITER | cmd1 >> file

Syntaxe

./pipex file1 cmd1 cmd2 file2

Équivalent shell

< file1 cmd1 | cmd2 > file2

Ce que doit faire le programme

  • Lire depuis file1 et écrire le résultat final dans file2.
  • Exécuter cmd1 puis envoyer sa sortie dans un pipe.
  • Exécuter cmd2 en lisant depuis ce pipe.
  • Gérer correctement les erreurs :

  • fichiers (absent, permissions)

  • commandes (introuvable)
  • appels système (pipe, fork, dup2, execve)

Notes importantes

  • Le parsing doit produire un argv exploitable par execve().
  • La recherche des binaires doit utiliser PATH (sauf si un chemin est fourni).
  • Les fd inutiles doivent être fermés dans chaque processus.

Schéma mental

  • Parent : crée le pipe + fork les deux enfants + wait
  • Enfant 1 (cmd1) :

  • stdin <- file1

  • stdout -> pipe_write
  • Enfant 2 (cmd2) :

  • stdin <- pipe_read

  • stdout -> file2

Pseudo-flux (simplifié)

  1. pipe(p)p[0] read, p[1] write
  2. pid1 = fork()
  • dup2(infile, STDIN_FILENO)
  • dup2(p[1], STDOUT_FILENO)
  • fermer : p[0], p[1], infile, outfile
  • execve(cmd1_path, cmd1_argv, envp)
    3. pid2 = fork()

  • dup2(p[0], STDIN_FILENO)

  • dup2(outfile, STDOUT_FILENO)
  • fermer : p[0], p[1], infile, outfile
  • execve(cmd2_path, cmd2_argv, envp)
    4. Parent :

  • fermer : p[0], p[1], infile, outfile

  • waitpid(pid1, ...), waitpid(pid2, ...)

Points d’attention

  • Fermer les bons fd évite les blocages : si le parent garde p[1] ouvert, cmd2 peut attendre un EOF qui n’arrive jamais.
  • Codes de sortie et messages d’erreur : rester cohérent (ex. “command not found”, permissions…).
  • PATH : split + join + access(X_OK) pour résoudre le binaire.

Multi-pipe

./pipex file1 cmd1 cmd2 cmd3 ... cmdn file2

Équivalent :

< file1 cmd1 | cmd2 | cmd3 ... | cmdn > file2

here_doc

./pipex here_doc LIMITER cmd1 cmd2 file

Équivalent :

cmd1 << LIMITER | cmd2 >> file

Implémentation typique : lire depuis stdin jusqu’à LIMITER, écrire dans un pipe, puis chaîner comme d’habitude.