Advanced OS Lab 1 - Unix shell

In this lab, you will build a simple Unix shell. The shell will print a simple $ prompt, and read a command line from its standard input. It will then interpret the line read as the name of a program to execute, followed by a list of zero or more arguments. For example, if your shell is called ash, it will behave like this:
% ./ash
$ ls -al
drwxr-xr-x  2 dm  classadm   512 Oct 27  2003 .
drwxr-xr-x  7 dm  classadm  2560 Sep 10 23:32 ..
-rw-r--r--  1 dm  classadm  2858 Oct 27  2003 .cshrc
-rw-r--r--  1 dm  classadm   212 Jan 12  2001 .login
-rw-r--r--  1 dm  classadm   105 May 13  2000 .mailrc
-rw-r--r--  1 dm  classadm   264 Jan 16  2001 .profile
-rw-r--r--  1 dm  classadm   126 Sep 17  2003 .rhosts
-rw-r--r--  1 dm  classadm  2110 Sep 11 00:01 ash.c
-rw-r--r--  1 dm  classadm  2110 Sep 11 00:02 ash
$ echo hello
hello
$ 
In addition to running simple commands, your shell must support the following features:
  1. Background jobs. If the command line contains a simple '&' character, this means the job should be run in the background. Your shell should print the process ID and then immediately print the prompt again and read another command.

    Before printing the prompt, however, your shell should check to see if any background processes have exited. If so, it should print the process ID and "Done" if the process exited with zero, or "Done (N)" if the process exited with value N, or "Killed (N)" if the process was terminated with signal N. You may find the sleep and kill commands useful for debugging this feature. For example:

    % ./ash
    $ sleep 20 &
    27717
    $ kill 27717
      27717  Killed (15)
    $ sleep 1 &
    19624
    $ [type return after one second]
      19624 Done
    $ false &
    31190
    $ [return]
      31190  Done (1)
    $ 
    
  2. Output redirection. If the command is followed by a an argument beginning '>', the rest of the argument is taken to be a file name into which the standard output (file descriptor 1) of the program should go. For example:
    % ./ash
    $ echo test >test-file
    $ cat test-file
    test
    $ 
    
  3. Input redirection. Similarly, if the command is followed by a an argument beginning '<', the rest of the argument is taken to be a file name from which the of standard input (file descriptor 1) of the program should go. For example:
    % ./ash
    $ echo test >test-file
    $ cat < test-file
    test
    $ cat < test-file > test-file-2
    $ cat < test-file2
    test
    $ 
    
  4. Pipes. If an argument appears that consists of a "|", it separates two commands. The first command should be run with its standard input connected to the second program's standard output. For example:
    % ./ash
    $ echo test | cat
    test
    $ echo test > test-file
    $ cat < test-file | cat
    test
    $ cat < test-file | cat | cat
    test
    $ 
    

Getting started

If you want, you can simply write the shell from scratch. To compile and run a C program, if you call your program ash.c, we recommand using the arguments:
% cc -ansi -Wall -o ash ash.c
% ./ash
$ 
The whole lab should only require about 250 lines of code to implement.

If you are stuck, and would like some help getting started, you can download and examine this partially implemented shell. This partially implemented shell supports executing programs and input and output redirection. However, it does not support pipes or background processes.

What to hand in

You must submit two things: To create a script file, use the script command. When you run script, everything you type gets saved in a file called typescript. Press CTRL-D to finish the script. The typescript should be copied to the same directory as the software. For example:
% script
Script started, output file is typescript
% ./ash
$ ...
$ ^D
% ^D Script done, output file is typescript
% cp ash.c typescript ~class/handin/lab1/`logname`/
% 
If you have any problems with submission, please contact the TA or instructor.

References

You may find it helpful to consult the system manual pages for various system calls and C library routines. You can do so with the man command (for instance man man describes the manual command itself).

In particular, you may find the following man pages helpful:

(The parenthesized number says which section of the manual contains the documentation; do not actually give that number to the man command.)