-
-
Save imjching/61b4f07abaf3a079d704a24c4a7406b8 to your computer and use it in GitHub Desktop.
Implementing `ls -la | sort`.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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