Programming Assignment 3 Command Pipelines Due Date: by 6:00 PM on Friday, May 29, 1998 For this assignment only, you are permitted to work in teams of not more than two people. You must register your team using the groupcon pro- gram in the cs2430 workon environment. Both members of the team must be registered by not later than 6:00 PM on Friday, May 22, 1998. If you do not register yourself as part of a team, then it will be assumed that you are working alone. No extra points will be given for people who choose to work alone. EACH MEMBER OF A PROJECT TEAM IS INDIVIDUALLY RESPONSIBLE FOR SEEING THAT A COPY OF THE ASSIGNMENT IS TURNED IN. must use the groupcon program to register your team. EACH MEMBER OF A PROJECT TEAM MUST INDIVIDUALLY TURN IN A COPY OF THE ASSIGNMENT. Readings: Review the material on pages 390-398 of the Weiss book. In particular, study the implementation of the RunCommand() function, shown on page 397. Stub Code: Use your defs.h, options.c, token.c, builtin.c, and any other files that were needed for Assignment 2. You will be making modifications to builtin.c for this assignment. Modifications: One of the drawbacks of the Foo shell is that it does not permit redirection or piping from builtin commands. For part 3, you must modify your builtin.c file so that piping from builtin commands is allowed. To sim- plify things a little, we will restrict the builtins to appearing only at the head (i.e. left-most end) of a pipeline. The procedure for adding these commands will be outlined below. You must follow this procedure exactly to get full credit on this part. You must create two new functions for your builtin.c file. One must be called OpenPipes(), and the other must be called ClosePipes(). The functions must each take a single FullCommand *Buf parameter, and must appear in the code just before and just after (respec- tively) the call to your ComFunc function: OpenPipes( Buf ); BuiltinCmds[ i ].ComFunc( Argc, Argv ); ClosePipes( Buf ); or perhaps: OpenPipes( Buf ); sp->ComFunc( Argc, Argv ); ClosePipes( Buf ); The OpenPipes() function must perform the following actions: 1. Save the file descriptor associated with STDOUT_FILENO. 2. Set up a pipeline by fork()-ing and exec()- ing each process in the Buf->Command struc- ture, with appropriate connections (via pipe()) between each pair of processes. You may use the source code for RunCommand() (found on page 397 in the Weiss book) as a guide for how to do this. In particular, the primary for() loop of this function is very similar to what your OpenPipes() function will need to do. You may use the UsePipe() function if you wish (shown on page 396, and already pre-compiled into the ~cs2430/pub/fsh/objects/command.o object file), but do not use the SetFiles() function - it has several problems that make it unsuitable for this assignment. Also, don't worry about running builtin pipelines in the background - it doesn't make much sense to do this for the builtin functions that we have implemented. The ClosePipes() function must do the following: 1. Restore the original file descriptor for STDOUT_FILENO that was saved from within OpenPipes(). 2. Wait for all child processes that were created by OpenPipes() to finish. For a "C" (70%) - 1. Add the functions OpenPipes() and ClosePipes() as described above. For a "B" (80%) - 1. Do everything required for a "C". 2. Modify OpenPipes() and ClosePipes() so that output re-direction is performed into the file specified by Buf->OutFile. To do this, you will need to open() the file for writing, and re-arrange the file descriptors so that STDOUT_FILENO points to the newly open()-ed file. After your pipeline runs, you will then need to re-arrange the file descriptors again so that the original STDOUT_FILENO is restored. Do not use freopen() for this part. It will cause you unimaginable pain and suffering. For an "A" (90%) - 1. Do everything required for a "B". 2. Install a signal handler in the shell to catch SIGPIPE if it occurs. The handler must be installed in OpenPipes() and then removed in ClosePipes(). For an "A+" (100%) - 1. Do everything required for an "A". 2. Modify OpenPipes() and ClosePipes() so that the status returned by the tail process (i.e. right-most end) in the pipeline is saved as the value of the environment variable ${?}.