rendered paste body#include <stdio.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <sys/types.h>#include <sys/wait.h>extern char ** environ;/* Errexit prints the supplied error message via perror, then exits the program, returning 1. */void errexit (const char * message) { perror (message); fprintf (stderr, "I BLAME KARJALA FOR THIS!\n"); _exit (1);}/* Dupclose duplicates the fd "in" to "out" if "out" is different from -1, and closes "in" afterwards. If "out" is -1, "in" is just closed. */void dupclose (int in, int out) { if (out != -1 && (dup2 (in, out) == -1)) errexit ("dup2()"); if (close (in)) errexit ("close()");}/* Myfork parses the command line, forks the process, performs stdin/stdout redirection and closes unneccessary FDs. */pid_t myfork (char * program, int * in, int * out) { char * args [256]; int i; pid_t childpid; /* Tokenize command line */ for (i=0; i < 256 && (args[i] = strtok (i ? NULL : program, " ")); i++) ; /* Fork */ switch (childpid = fork ()) { case -1: errexit ("fork()"); /* child: duplicate & close FDs, exec program */ case 0: if (in) dupclose (in[0], 0); if (out) dupclose (out[1], 1); execve (args[0], args, environ); /* never returns (unless...) */ fprintf (stderr, "can't execve %s\n", program); errexit ("execve()"); /* parent: just close FDs */ default: if (in) dupclose (in[0], -1); if (out) dupclose (out[1], -1); } return childpid;}int main (int argc, char ** argv) { FILE * file; int fdin[2], fdout[2]; char line[255], * commands [256]; pid_t pids [256]; int retvals [256]; int count, cmdcount = 0; if (argc != 2) { fprintf (stderr, "need one argument: file containing commands to chain\n"); return 1; } if (!(file = fopen (argv[1], "r"))) errexit("fopen()"); /* Read commands */ while (cmdcount < 256 && fgets (line, sizeof(line), file)) { line[strlen(line)-1] = 0; // remove cariage return if (line[0]) commands[cmdcount++] = strdup (line); } /* Execute commands, piped into each other */ for (count = 0; count < cmdcount; count++) { if (count < (cmdcount-1) && pipe (fdout)) /* No new output pipe for last command */ errexit ("pipe()"); pids[count] = myfork (commands[count], count ? fdin : (int *) NULL, /* First command will only have stdout redirected */ count < (cmdcount-1) ? fdout : (int *) NULL); /* Last command will only have stdin redirected */ memcpy (fdin, fdout, sizeof(fdout)); /* Current output pipe will be next command's input pipe */ } /* Wait for commands to terminate, in order */ for (count = 0; count < cmdcount; count++) waitpid (pids [count], &retvals[count], 0); /* Print return values */ for (count = 0; count < cmdcount; count++) printf ("Process %d (%s) exited with status %d\n", count, commands[count], WEXITSTATUS(retvals [count])); return 0;}