a. Modify the C program ex.9 so that it simulates the Unix pipe command: ls | grep .c | tail -4 b.. Implement following programs to exhibit UNIX Process Control: A program where parent process sorts array elements in descending order and prints them out and child process sorts array elements in ascending order and prints them out. A program where parent process counts number of vowels in the given sentence and child process will count number of words in the same sentence. The above programs should use system calls like fork, exec and wait. ex.9: /* simulates unix pipe ls | grep .c */ #include #include #include #define RD 0 #define WT 1 int main() { int fd[2]; pipe(fd); switch(fork()) { // parent forks case -1: perror(\"Fork error\"); break; case 0: // child does the ls close(fileno(stdout)); // no need for stdout here dup(fd[WT]); // duplicate the descriptor for writing close(fd[WT]); close(fd[RD]); execlp(\"ls\", \"ls\", NULL); break; default: // parent does the grep close(fileno(stdin)); // no need for stdin here dup(fd[RD]); // duplicate the descriptor for reading close(fd[WT]); close(fd[RD]); execlp(\"grep\", \"grep\", \".c\", NULL); break; } return 0; } Solution #include #include #include #define RD 0 #define WT 1 int main() { int fd1[2]; int fd2[2]; pipe(fd1); switch(fork()) { case -1: perror(\"Fork error\"); break; case 0: // child does the ls close(fileno(stdout)); dup(fd[WT]); close(fd1[WT]); close(fd1[RD]); execlp(\"ls\", \"ls\", NULL); break; default: pipe(fd2); switch(fork()) { case -1: perror(\"Fork error\"); break; case 0: close(fileno(stdin)); dup(fd1[RD]); dup(fd2[RD]; close(fd1[WT]); close(fd1[RD]); close(fd2[WT]); close(fd2[RD]); execlp(\"grep\", \"grep\", \".c\", NULL); break; default: dup(fd2[RD]); close(fd2[WT]); close(fd2[RD]); execlp(\"tail\", \"tail\", \"-4\", NULL); break; } return 0; }.