#include #include #include #include /* * C program that implements the pipeline * * ls -l /tmp/ | wc -l * * to count the number of files under the /tmp/ directory. * * The parent process declares a pipe, and then forks twice to create two * childs processes for the ls and wc commands. The process doesn't send or * receive any output from its children, it simply forks them and then waits * for them to finish execution. * * The first child process represents the ls command, and reassigns its STDOUT * to the pipe's write end so the output from the process doesn't go to the * console and instead goes to the pipe's write end. * * The second child process represents the wc command, and reassign its STDIN * to the pipe's read end so the input to the process comes from the pipe, and * not from the keyboard. * * NOTE: It might benefit from more error handling. */ int main(int argc, char *argv[]) { pid_t ls_pid, wc_pid; int pipefd[2]; pipe(pipefd); if ((ls_pid = fork()) == 0) { // we assign this process's output to the pipe's write end, i.e., // instead of sending output to the screen, it sends it to the pipe's // write end. dup2(pipefd[1], STDOUT_FILENO); // now this process's stdout refers to the pipe's write end too so we // can close this descriptor. close(pipefd[1]); // this process doesn't use the pipe's read end, and thus we close this // file descriptor. close(pipefd[0]); // replace process's current image with this new process image, i.e., the ls command. if (execlp("ls", "ls", "-l", "/tmp/", (char *) NULL) < 0) { fprintf(stderr, "failed trying to execute the ls command"); exit(0); }; } else if (ls_pid < 0) { fprintf(stderr, "failed forking ls process"); } if ((wc_pid = fork()) == 0) { // we assign this process's input to the pipe's read end, i.e., instead // of taking input from the keyboard, it takes it from the pipe's read end. dup2(pipefd[0], STDIN_FILENO); // now this process's stdin refers to the pipe's read end too so we // can close this descriptor. close(pipefd[0]); // this process doesn't use the pipe's write end, and thus we close this // file descriptor. close(pipefd[1]); // replace process's current image with this new process image, i.e., the wc command. if (execlp("wc", "wc", "-l", (char *) NULL) < 0) { fprintf(stderr, "failed trying to execute the wc command"); exit(0); }; } else if (wc_pid < 0) { fprintf(stderr, "failed forking wc process"); exit(0); } // the parent process doesn't use the pipe so we close both ends. Also // needed to send EOF so the children can continue (children blocks until // all input has been processed). close(pipefd[0]); close(pipefd[1]); // the parent process waits for both child process to finish their execution. int ls_status, wc_status; pid_t ls_wpid = waitpid(ls_pid, &ls_status, 0); pid_t wc_wpid = waitpid(wc_pid, &wc_status, 0); return 0; }