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.