The Ouch Shell

Version 3.x

Introduction

In this assignment you will continue development of a Unix shell program you began in Assignments 3 and 4. This assignment gives you the opportunity to add features to the somewhat rudamentary shell specified in Assignment 4, and adds the requirement that you write a man page for your shell.

Project Management

All files for this assignment are to have version numbers in the range 3.1 through 3.x. Check out each file from Assignment 4 for editing and, without making any changes, check it in again as version 3.1 in a manner analogous to the way you started work on Assignment 4.

Requirements for Version 3.x

Each function description starts with the function prototype for the function.

getCommandLine()

    int getCommandLine( char *buf, int max );
This code should not need to be changed from what you wrote for Assignment 4.

getSubCommands()

    subcommand_t* getSubcommands( char *buf );
You might not need to change your code for Assignment 4 for this function. But whereas you were required only to handle simple command lines in the previous assignment, this assignment will test whether you actually can handle multiple commands separated by semicolons correctly. Handling an ampersand at the end of a command line will be tested if you mention it in your man page, but is not required. Be sure to test all kinds of quoting as mentioned in Assignment 4. If there are any limitations on what your code handles properly here, be sure to list them in the BUGS section of your man page.

tokenize()

  token_t *tokenize( const subcommand_t *cmd );
Your tokenize function should handle quotes and I/O redirection operators correctly for this assignment. (These features were not tested for Assignment 4.) There should be no need to surround redirection operators with spaces. Thus the strings ">out" and ">  out" are equivalent. Either one should both result in a single token_t node with the token member pointing to "out" and the tag member equal to T_redirect_out.

expandToken()

    char *expandToken( const char *token )
The $? token should be handled properly in this Assignment. In addition, you may optionally include support for $$ (the shell's process id).

executeCommand()

    int executeCommand( subcommand_t *cmd );
For this assignment, you are to handle builtin commands using a dispatch table as outlined in class.

Use this prototype for all builtin functions:

      typedef int builtin_t( int, char **, char ** );
Then you can use this struct for the dispatch table entries:
struct dispatch_t 
{
      const char  *const cmdName;
      builtin_t   *function;
      bool        canFork;
};
The purpose of the canFork member of the struct is to mark whether it is all right to fork a separate process to execute the builtin command or not. The cd and exit builtin commands must not execute in separate processes because they have to modify ouch's process. But other builtins can be executed in separate processes, and will have to if their input or output streams are redirected.

Builtin Commands

Set up your builtin command dispatch table so it associates the following command names and functions:

Command Name Function Can Fork?
exit doExit() No
quit doExit() No
print doPrint() Yes
cd doCd() No

(Thought question: What would be a better way to have two different names for the same command, as accomplished by the first two entries in the above table?)

exit and quit

Typing either of these commands should exit the shell.

Optional: Study Chapter 10 of the Stevens book and modify ouch so it does not exit if the user types Control-C. Be sure this feature works correctly whether the user has started typing a command line when s/he types Control-C or not.

print

This is ouch's version of other shells' echo command. It prints each of its command line arguments separated from each other by exactly one space. While the doPrint() function is simple to implement, what it prints out will tell whether your tokenize() function is implemented correctly. It also tests whether result codes and token expansion are working correctly.

Code this function so that it's own result code is equal to the number of command line arguments it prints.

Sample output:

      ouch> date; print The value of '$?' is $?
      Mon Dec 10 19:22:36 EST 2001
      The value of $? is 0
      ouch> print "Previous result code was:   " $?
      Previous result code was:    6
      ouch>

I/O Redirection

If your tokenize() function is working, this part is quite simple to implement. While building the argument vector to pass as the second argument to execve() or to a builtin_t function, pull out any redirection tokens, opening the specified file with the proper mode based on the type of redirection. After forking, use the dup2() system call to put the fd in its proper "slot" (0 for stdin, 1 for stdout). For example, you could declare an int named stdinRedirection_fd that is initialized to -1 for each command. If you find a token of type T_redirect_in, open the file named by the token for reading (O_RDONLY) and save the fd returned by open() in stdinRedirect_fd. Then after forking, you have the child process execute code like:
      if ( stdinRedir_fd != -1 )
      {
        dup2( stdinRedir_fd, 0 );
        close( stdinRedir_fd );
      }
Here are the flags to use for opening the three types of output redirection. In all cases, the mode value (the third argument passed to open()) should be 0666. (Remember that the 0 means octal.)

T_redirect_out O_WRONLY | O_CREAT | O_EXCL
T_redirect_append O_WRONLY | O_APPEND
T_redirect_clobber O_WRONLY | O_CREAT | O_TRUNC

ouch.1

Provide a man page for the project in a file named ouch.1, which is to be under RCS management (with a revision number of 3.x) just like the other files you wrote for this assignment. You may optinally have man and man/man1 subdirectories in your project directory, and you may include an "install" target for your man page that installs it there.

Your man page will be graded on grammatical correctness and meaningfulness of content in addition to proper formatting, as described in the man pages document listed in the course schedule.

Due Date

You may accept this assignment as late as midnight December 21, but no later.