Implementing `ls -la | sort`.
// Heavily modified from https://brandonwamboldt.ca/how-linux-pipes-work-under-the-hood-1518/. | |
#include <stdio.h> | |
#include <unistd.h> // STDOUT_FILENO | |
#include <sys/types.h> // wait() | |
#include <sys/wait.h> // wait() | |
#define READ_END 0 | |
#define WRITE_END 1 | |
#define FORK_CHILD 0 | |
#define FORK_PARENT 1 | |
// ls -la | sort | |
int main(int argc, char **argv) { | |
// Create a pipe in parent | |
int pipefd[2]; | |
if (pipe(pipefd) == -1) { | |
printf("parent: failed to create pipe\n"); | |
return 1; | |
} | |
// We need to fork two processes, one for ls, and another one for sort | |
int pid_ls = fork(); | |
if (pid_ls == -1) { | |
printf("parent: could not fork process to run ls\n"); | |
return 1; | |
} | |
if (pid_ls == FORK_CHILD) { // Child | |
printf("child: running ls\n"); | |
// http://man7.org/linux/man-pages/man3/stdin.3.html | |
// Merge stdout of ls to write end of pipe. | |
if (dup2(pipefd[WRITE_END], STDOUT_FILENO) == -1) { | |
printf("child: failed to call dup2 for ls\n"); | |
return 1; | |
} | |
close(pipefd[READ_END]); | |
close(pipefd[WRITE_END]); | |
// Replace the current process with ls. | |
// execve() does not return on success, and the text, data, bss, and stack | |
// of the calling process are overwritten by that of the program loaded. | |
// Ref: https://linux.die.net/man/2/execve | |
char *ls_argv[] = {"/bin/ls", "-la", NULL}; | |
execve("/bin/ls", ls_argv, NULL); | |
// We will only return here if execve failed. | |
printf("child: ls failed\n"); | |
return -1; | |
} | |
// Parent (FORK_PARENT) | |
// Continue forking | |
int pid_sort = fork(); | |
if (pid_sort == -1) { | |
printf("parent: could not fork process to run sort\n"); | |
return 1; | |
} | |
if (pid_sort == FORK_CHILD) { // Child | |
printf("child: running sort\n"); | |
// http://man7.org/linux/man-pages/man3/stdin.3.html | |
// Merge stdin of sort to read end of pipe. | |
if (dup2(pipefd[READ_END], STDIN_FILENO) == -1) { | |
printf("child: failed to call dup2 for sort\n"); | |
return 1; | |
} | |
close(pipefd[READ_END]); | |
close(pipefd[WRITE_END]); | |
// Replace the current process with sort. | |
// execve() does not return on success, and the text, data, bss, and stack | |
// of the calling process are overwritten by that of the program loaded. | |
// Ref: https://linux.die.net/man/2/execve | |
char *sort_argv[] = {"/usr/bin/sort", NULL}; | |
execve("/usr/bin/sort", sort_argv, NULL); | |
// We will only return here if execve failed. | |
printf("child: sort failed\n"); | |
return -1; | |
} | |
close(pipefd[READ_END]); | |
close(pipefd[WRITE_END]); | |
printf("parent: wait for children\n"); | |
while (wait(NULL) > 0); | |
printf("parent: done!\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment