The object of this assignment is to gain experience with some advanced programming techniques like process creation and contol, file descriptors, signals and possibly pipes. To do this, you will be writing your own command shell - much like csh, bsh or the DOS command shell.
Wait! Have you written your parser already? Do that first.
From experience using a command shell, you should be able to write basic pseudocode for a shell (Note: The pseducode below uses the UNIX style fork/exec not the Windows style CreateProcess/WaitForSingleObject.):
int
main (int argc, char **argv)
{
while (1){
int childPid;
char * cmdLine;
printPrompt();
cmdLine= readCommandLine(); //or GNU readline("");
cmd = parseCommand(cmdLine);
record command in history list (GNU readline history ?)
if ( isBuiltInCommand(cmd)){
executeBuiltInCommand(cmd);
} else {
childPid = fork();
if (childPid == 0){
executeCommand(cmd); //calls execvp
} else {
if (isBackgroundJob(cmd)){
record in list of background jobs
} else {
waitpid (childPid);
}
}
}
}
Between this simple pseudocode and full featured shells, there are many optional features. Here are the features you should support in your shell:
The directory: /usr/foo/bar%
Try getcwd(char * buf, size_t size)
.
Linux
TIP! Example of a
relative command df
, same command
with absolute path: /bin/df
. To find the absolute path of a
command use which, which ls
gives
/bin/ls
Try execvp
it will search the path automatically for you. First argument should be pointer to command string and the second arguments should be a pointer to an array which contains the command string as arg[0] and the other arguments as arg[1] through arg[n].
Linux TIP! Use printenv
$PATH
to see what's in your executable path
Windows TIP! Right Click on 'My Computer', go to Properties and find the Environment Variables
foo < infile > outfile
would create a new
process to run foo and assign STDIN for the new
process to infile and STDOUT for the new process to
outfile. In many real shells it gets much more complicated than
this (e.g. >> to append, > to
overwrite, >& redirect STDERR and
STDOUT, etc.)! (WARNING: I am told
that I/O redirection may be quite tricky on Windows. We may
substitute a different feature here for Windows) You also
do not have to support I/O redirection for built-in commands (it
shouldn't be too hard but you don't have to do it.) Note: one redirect in each direction is fine,
not ls > foo < foo2
First open the file (use open or creat, open read only for infiles and creat writable for outfiles ) and then use dup2
. 0 is the filedescriptor for STDIN and 1 is the file descriptor for STDOUT.
Examples:
dup2 (fdFileYouOpened, fileno(stdin))
dup2 (fdFileYouOpened, fileno(stdout))
bg
and fg
). You also
do not need to support putting
built-in commands in the background.
Try waitpid(pid, status, options)
.
Linux TIP! The
history
command can show you the remembered
commands by the linux shell, available with the up and down
arrows
Windows TIP! Use the up and down arrows to access the history from the cmd app.
!number
where number indicates which command to
repeat. !-1
would mean to repeat the last
command. !1
would mean repeat the command numbered
1 in the list of command returned by history. Note: You can probably think of better syntax for this, but I thought it was good to stay as close as possible to syntax used by real shells
jobs
, cd
,
history
, exit
and
kill
.
Try waitpid
with WNOHANG option to check without blocking. You can either check when jobs called or each time through the main while loop.
kill %num
should terminate the process numbered,
num in the list of background processes returned by
jobs (by sending it a SIGKILL signal).
Note: Usually kill num
refers to
the process with ProcessId, num; while kill %num
refers to the process in the jobs list with number, num
help
that lists the available built-in commands and
their syntax. (If you don't follow the syntax expected, then a
help
function would let the graders proceed anyway.)
Try kill (pid, SIGKILL)
.
exit
while there are background
processes, notify the user that these background processes
exist, do not exit and return to the command prompt. The user
must kill the background processes before exiting.prog >
outfile
rather than prog>outfile
).
Here is a text file that I wrote (not computer output so beware) to show an example of the shell in operation.
Here is a tar file that contains a
Makefile that will get you started compiling on a UNIX/Linux
platform. Copy the file and then execute the command tar -xf
exampleShell.tar
to unzip the contents. Then simply
cd exampleShell
into the exampleShell
directory and type make
. This will compile shell.c into
the executable shell. You can execute shell by typing
./shell
at the command prompt. You can remove the
executable by typing make clean
.
Here is a tar file that contains a Makefile and two programs that illustrate the use of the dup system call to support I/O redirection. Note that the file f1 is present in the directory and is needed as the input file for the forkDupExec program. That program when run will produce f2 an identical copy of f1 by forking off a new process, reassigning its stdout and stdin and execing cat.
If you are enjoying this project and would like to add more advanced features to your shell, here are some sugguestions:
history -s num
could set the
size of the history buffer and history num
could
return the last num commands. You could also support additional
built-in commands like which, pushd/popd or alias. If you make
modifcations of this type, I would recommend help
command
to return more detailed information on a single
command.foo | bar
would send the STDOUT of
foo to the STDIN of bar using a pipe. You may want to
start by supporting pipes only between two processes before
considering longer chains. Longer chains will probably require
something like handle process n and then recursively handle the
other n-1.>&
, >!
, etc.).fg
and bg
, to move processes between the
background and the foreground. printenv
and setenv
.if
/then
,
while
, for
constructs).ls
on Windows.prog>outfile
). Any advanced shell feature is likely to earn you some extra credit, but you should do it only if you've finished the required functions, are having fun and would like to learn more. In particular, we will *not* say how much extra credit each feature or sub feature may be worth.
Instructions will be given on how to submit your assignment
Here are a list of resources you may find helpful. Feel free to send mail suggesting others.
GNU history library (for the required functionality might be easier without it?)
The following functions are likely to be helpful (consult the man pages for details):
fork, exec, execvp, wait, waitpid, kill, dup, pipe, strncmp, strlen, malloc, free, getcwd, chdir , open, close, readline, gets, fgets, getchar, signal (*not* system!)