Understand basic Unix system calls and use them for a basic shell implementation.
This basic shell is a command line interpreter that accepts input from the user and executes the commands. Similar to the well-known shells such as bash or tcsh, this shell can execute commands, redirect the standard input or standard output of commands to files, pipe the output of commands to other commands.
When the shell is ready to accept commands, it prints the
prompt "Shell:
" (without quotes). At this point, the user
can type commands. Commands are alphanumeric tokens (e.g., ls,
ps, cat) that represent programs that should be executed. This shell
should search for these programs in the directories determined
by the PATH environment variable.
Commands can have arguments. Thus, tokens that
follow a command (separated by white space) are treated as the
arguments to this command (e.g., cat x
).
In addition to execute commands with their arguments, your shell supports the standard Unix I/O redirection meta-characters with '<' and '>', command pipeline with '|' and a simple signal handling. More details are here.
In case of errors (e.g., invalid input, command not found, ...) your shell should display an error and wait for the next input.
To exit the shell, the user may type "exit" or Ctrl-D (pressing the D button while holding control).
Your shell is supposed to collect the exit codes of all processes that it spawns.
You may assume there is a white space separating all tokens. There are at most 3 commands connected by pipe '|'.
You may assume that the maximum length of individual tokens never exceeds 32 characters, and that the maximum length of an input line never exceeds 512 characters.
fork()
system call and the
execvp()
system call (or one of its variants) to execute
commands, and dup2()
for I/O pipes and redirection.
It should also use waitpid()
or wait()
to wait for a program to complete execution.
You might also find the
documentation for signals useful to be
able to collect the status of processes that exit when running in
the background.
You need to submit the following files under directory HW0/shell:
make
to compile your code.
make run
to run your code with our own test.
make test
to run your code with your test.
fgets(3)
.
fork
to create a new (child) process, and the
child process should exec
the command.
exec
to begin execution, the child
process may have to close stdin (file descriptor 0) or stdout
(file descriptor 1), open the corresponding file or pipe
(with open for files, and pipe for pipes), and
use dup2(2)
to make it the
appropriate file descriptor. After calling dup2
,
close the old file descriptor.
execvp
is to build the
argument list correctly. If you use execvp
, remember
that the first argument in the array is the name of the
command itself, and the last argument must be a null pointer.