{"id":20350453,"url":"https://github.com/ekkoz897/42cursus_pipex","last_synced_at":"2025-09-01T12:33:31.004Z","repository":{"id":117604523,"uuid":"607220649","full_name":"Ekkoz897/42cursus_Pipex","owner":"Ekkoz897","description":"Pipex is a project that re-creates in C the way two commands are piped together via | in the shell ","archived":false,"fork":false,"pushed_at":"2024-03-21T18:16:18.000Z","size":44,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-14T23:52:59.503Z","etag":null,"topics":["42born2code","42cursus","42projects","42school","pipe","pipex","pipex42","unix"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ekkoz897.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-27T15:03:48.000Z","updated_at":"2024-03-21T18:13:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"4430ae98-c76e-4bcd-a29b-3511f82c2444","html_url":"https://github.com/Ekkoz897/42cursus_Pipex","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ekkoz897%2F42cursus_Pipex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ekkoz897%2F42cursus_Pipex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ekkoz897%2F42cursus_Pipex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ekkoz897%2F42cursus_Pipex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ekkoz897","download_url":"https://codeload.github.com/Ekkoz897/42cursus_Pipex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241880051,"owners_count":20035887,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["42born2code","42cursus","42projects","42school","pipe","pipex","pipex42","unix"],"created_at":"2024-11-14T22:30:23.503Z","updated_at":"2025-03-04T16:29:35.340Z","avatar_url":"https://github.com/Ekkoz897.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n\t42cursus_Pipex\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003cb\u003e\u003ci\u003eReproduction of shell pipes\u003c/i\u003e\u003c/b\u003e\u003cbr\u003e\n\u003c/p\u003e\n\n\nPipex is a project that re-creates in C the way two commands are piped together via `|` in the shell\n\n````\n# ./pipex infile cmd1 cmd2 outfile\npipe()\n |\n |-- fork()\n      |\n      |-- child // cmd1\n      :     |--dup2()\n      :     |--close end[0]\n      :     |--execve(cmd1)\n      :\n      |-- parent // cmd2\n            |--dup2()\n            |--close end[1]\n            |--execve(cmd2)\n \n# pipe() sends the output of the first execve() as input to the second execve()\n# fork() runs two processes (i.e. two commands) in one single program\n# dup2() swaps our files with stdin and stdout\n ````\n## Setting the pipe\n\n````\nvoid    pipex(int f1, int f2)\n{\n    int end[2];    pipe(end);\n}\n\n# pipe() takes an array of two int, and links them together\n# what is done in end[0] is visible to end[1], and vice versa\n# pipe() assigns an fd to each end\n# Fds are file descriptors\n# since files can be read and written to, by getting an fd each, the two ends can communicate\n# end[1] will write to the its own fd, and end[0] will read end[1]’s fd and write to its own\n\n````\n## Forking the processes\n\n````\nvoid    pipex(int f1, int f2)\n{\n    int   end[2];\n    pid_t parent;    pipe(end);\n    parent = fork();\n    if (parent \u003c 0)\n         return (perror(\"Fork: \"));\n    if (!parent) // if fork() returns 0, we are in the child process\n        child_process(f1, cmd1);\n    else\n        parent_process(f2, cmd2);\n}\n\n# fork() splits the process in two sub-processes -\u003e parallel, simultaneous, happen at the same time\n# it returns 0 for the child process, a non-zero for the parent process, -1 in case of error\n````\nend[1] is the child process, end[0] the parent process; the child writes, the parent reads  \nSince for something to be read, it must be written first, so cmd1 will be executed by the child, and cmd2 by the parent.  \n\n## FDs\npipex is run like this ./pipex infile cmd1 cmd2 outfile  \nFDs 0, 1 and 2 are by default assigned to stdin, stdout and stderr  \n`infile`, `outfile`, the pipe, the `stdin` and `stdout` are all FDs  \nOn linux, you can check your fds currently open with the command ls -la /proc/$$/fd  \n\nOur fd table right now looks like this:\n````\n                           -----------------    \n                 0         |     stdin     |  \n                           -----------------    \n                 1         |     stdout    |    \n                           -----------------    \n                 2         |     stderr    |  \n                           -----------------\n                 3         |     infile    |  // open()\n                           -----------------\n                 4         |     outfile   |  // open()\n                           -----------------\n                 5         |     end[0]    | \n                           -----------------\n                 6         |     end[1]    |  \n                           -----------------\n````\n## Swapping fds with dup2()\n\nFor the child process, we want infile to be our stdin (as input), and end[1] to be our stdout (we write to end[1] the output of cmd1)  \nIn the parent process, we want end[0] to be our stdin (end[0] reads from end[1] the output of cmd1), and outfile to be our stdout (we write to it the output of cmd2)  \nVisually,\n````\n// each cmd needs a stdin (input) and returns an output (to stdout)\n   \n    infile                                             outfile\nas stdin for cmd1                                 as stdout for cmd2            \n       |                        PIPE                        ↑\n       |           |---------------------------|            |\n       ↓             |                       |              |\n      cmd1   --\u003e    end[1]       ↔       end[0]   --\u003e     cmd2           \n                     |                       |\n            cmd1   |---------------------------|  end[0]\n           output                             reads end[1]\n         is written                          and sends cmd1\n          to end[1]                          output to cmd2\n       (end[1] becomes                      (end[0] becomes \n        cmd1 stdout)                           cmd2 stdin)\n\n````\n\n## Executing with execve()\n\nFrom the MAN,\n````\nint execve(const char *path, char *const argv[], char *envp[]);\n\n# path: the path to our command\n# type `which ls` and `which wc` in your terminal\n# you'll see the exact path to the commands' binaries\n\n# argv[]: the args the command needs, for ex. `ls -la`\n# you can use your ft_split to obtain a char **\n# like this { \"ls\", \"-la\", NULL }\n# it must be null terminated\n\n# envp: environmental variable -\u003e retrieved from main (see below)\n# in envp the line PATH contains all possible paths to the commands' binaries\n# type env in the terminal to have a look\n# split on : to retrieve all possible PATHs \n\nint main(int ac, char **ag, char **envp)\n{\n     int f1;\n     int f2;\n     f1 = open(ag[1], O_RDONLY);\n     f2 = open(ag[4], O_CREAT | O_RDWR | O_TRUNC, 0644);\n     if (f1 \u003c 0 || f2 \u003c 0)\n          return (-1);\n     pipex(f1, f2, ag, envp);\n     return (0);\n}\n````\n`execve()` will try every possible path to the cmd until it finds the good one  \nIf the command does not exist, `execve()` will do nothing and return -1;  \nelse, it will execute the cmd and delete all ongoing processes (so no leaks)  \n\n## Creating a pipe with two child processes\n\n````\nvoid    pipex(int f1, int f2, char *cmd1, char *cmd 2)\n{\n    int   end[2];\n    int   status;\n    pid_t child1;\n    pid_t child2;    pipe(end);\n    child1 = fork();\n    if (child1 \u003c 0)\n         return (perror(\"Fork: \"));\n    if (child1 == 0)\n        child_one(f1, cmd1);\n    child2 = fork();\n    if (child2 \u003c 0)\n         return (perror(\"Fork: \"));\n    if (child2 == 0)\n        child_two(f2, cmd2);\n    close(end[0]);         // this is the parent\n    close(end[1]);         // doing nothing\n    waitpid(child1, \u0026status, 0);  // supervising the children\n    waitpid(child2, \u0026status, 0);  // while they finish their tasks\n}\n````\n## Using access()\n\nIf the command that does not exist, execve() will execute nothing without error messages  \nYou need to check if the command exists before its execution with `access()`, else send an error `pipex: weirdcmd: weirdcmd not found`  \n\n## Debugging\n\n[0] When splitting the env, print out the result of split. Add a `/` at the end for the path to work correctly.\n\n[1] If the program gets stuck without executing anything, most probably the pipe ends are not closed correctly.\nUntil one end is open, the other will be waiting for input and its process will not finish.\n\n[2] Place `perror(\"Error\")` in your code, especially right after fork() or execve() , to see what is going on in the pipe.\nInside the pipe, everything we do will go to one of its ends.\n`printf` for ex. won’t print to the terminal, it will print to your outfile (because we swapped the stdout)\n`perror(\"Error\")` will work because it prints to stderr.\n\n[3] Handle file rights when `open()`ing them.\nReturn error if the file cannot be opened, read or written. \nCheck how the shell treats infile and outfile when they do not exist, are not readable, writable etc. (chmod is your best friend).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fekkoz897%2F42cursus_pipex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fekkoz897%2F42cursus_pipex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fekkoz897%2F42cursus_pipex/lists"}