Lab 7: Basic UNIX Shell

Due Date: Sunday April 12th 2009 by 23:59

Background:

Many programs need the assistance of the operating system in order to produce a desired output. The operating system handles many tasks, such as file/Directory manipulation and I/O, and process and thread scheduling and execution. Functions that allow you to communicate with the operating system are called "Syscalls". As you will eventually learn in 15-213, there are many programs written that take advantage of syscalls, such as multi-threaded web servers and proxy servers, and of course, the UNIX shell that you use whenever you login to a UNIX machine.

 

The Assignment:

In this assignment, you will write your own UNIX shell. Many shells that are offered have a lot of fancy features added to increase it's usability such as tab completion, history and piping, but they all have the same basic functionality of being able to execute programs in the background or foreground. In later classes such as 15-213 and 15-395 you might be required to implement some of these more complex features, but for now we only want you to understand how to make and manage new processes in UNIX. So your shell only need to be able to handle 2 basic type of commands:

 

yourshell> <COMMAND> <ARGUMENTS>

yourshell> <COMMAND> <ARGUMENTS> &

 

In addition to those commands, your shell will accept 2 shell specific commands. They are:

 

yourshell> quit

yourshell> jobs

 

It is pretty obvious what each command should do. If your shell is supplied with just "<COMMAND> <ARGUMENTS>", then you must execute the command and wait for it to finish before you continue execution of your shell. However, if your shell is supplied with "<COMMAND> <ARGUMENTS> &" then you need to fork of a new process and without waiting for the new process to terminate, and be ready to accept a new command. The operating system will handle all of the process scheduling so there's nothing to worry about in this case.

 

Finally, you will need to recognize the "quit" and "jobs" commands. Quit will terminate your shell. Jobs will print out all current active processes and their respective PID. This means that you will need to implement some sort of data structure to hold all active processes and when processes exit remove them correctly. Note that you do not want this to affect your shell's ability to execute processes in the background. You may want to read the man page for waitpid and pay close attention to the WNOHANG option.

NOTE: When calling exec, you need to provide it with the absolute system path to the command you wish to execute. Therefore, if you try calling "ls" it will not work. Instead, you would have to call ls using it's entire path name, "/bin/ls". Although making your shell append a path is not very hard, you only have a week for this assignment and so such functionality is not required. We will supply command to your shell with their absolute path in the command.

 

The first step you will need to do is to write a parser/grammar checker. A parser simply takes a command line as one long string and splits it up into tokens. This can be done easily using the strtok() function. A grammar checker just makes sure that the command you supplied conforms to what we expect input to look like. For our simplified shell, we have very few grammatical rules. You need only check that "&" comes after a command and it's arguments, and not before. If your shell is given the quit command, anything after this command would not make sense, so you can define how your shell acts if this happens. (By either quitting or giving a parse error.)

 

After you have tokenized the command line and made sure that it's in the correct format, you need to "execute" the command. If you were given the quit command, you simply exit the program. If you are given any other command, you need to spawn a child process which can then become the new process which you are executing. Lastly, if the "&" is not given, your shell must wait for it's child to exit before continuing execution.

 

Examples:

yourshell> /bin/ls -laF                   % Executes "/bin/ls" with the arguments "-laF" in the foreground.

yourshell> /somepath/SortHugeDatabase &   % Executes "/somepath/SortHugeDatabase" in the background.

yourshell> & /bin/ls                      % Throws a parse error.

yourshell> quit                           % Exits the shell.

 

You can name your shell whatever you like. You can hardcode the name in your shell, or use argv[0]. Either way, actually print out your shell's name with a "> " after it. Your parse error does not have to be very elaborative. Just something simple like this:

 

yourshell> & /bin/ls

yourshell: Parse error! Invalid command line.

 

Commenting your code: Please comment your code to show what you are doing. The least amount of comments is a short description at the beginning of each function that explains what it does, what parameters it takes, and what the expected output or return value is.

 

Starter Code

Here is the starter code for this assignment. PLEASE READ THROUGH THE CODE AND UNDERSTAND IT BEFORE STARTING WRITING THE PROGRAM.

 

Handing in your Solution

Your solution should be in the form of a .c file. Don't hand in input, obj or exe files.