SHELL: Introduction
Have you used a shell in a system? Yes, but probably you are unaware of. When? When you use a linux terminal or Windows cmd window.
Shell is a user interface between user and the internal of OS. So a shell's job is to intercept user's command and then trigger system calls to ask OS to accomplish the user's tasks. Here is a list of available system calls in linux. A shell mainly consists of two parts: parsing user requests and accomplishing user request with system calls' help.
In this assignment, you will write your own command shell to gain experience with some advanced programming techniques like process creation and control, file descriptors, signals and possibly pipes. We have provided a simple parser for you to use and you need to implement certain features in your shell.
You have to implement all the required features. Remember to include a README file to describe your assignment's status, which feature does not work yet, who you have discussed with, what extra features or work you have done. Anything helpful for grading is welcome.
SHELL: Objectives
- Understand how a command shell works
- Understand Linux system insight, like IO stream, process etc.
- Get familiar with Linux system calls
- Get familiar with C Language and its syntax, particuliarly the concept of pointers and dynamical memory allocation
SHELL Skeleton Code
The first thing you will need is a parser. We are giving you a complete parser and the skeleton code of a shell here. The parser and shell skeleton code is a tar file that contains a Makefile that will get you started compiling on a UNIX/Linux platform.
- Download the file on your local machine;
-
Execute the command
tar -xf shellWithParser.tar.gz
to uncompress the contents; -
Simply
cd shellWithParser
to get into the shellWithParser directory; -
Type
make
to compile shell.c into the executable shell; -
Execute shell by typing
./shell
on the command line; -
You can remove the executable by typing
make clean
.
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);
}
}
}
}
If you cannot get your code compiled, probably you are missing some library packages. If you are in Ubuntu, try to type the two commands below to install the packages.
1.sudo apt-get install build-essential
2.sudo apt-get install lib64readline-gplv2-dev(For 64 Bit)
OR
sudo apt-get install libreadline-gplv2-dev(For 32 bit)
SHELL: Required Features
Between this simple pseudocode and full featured shells, there are many optional features. Here are the features you should support in your shell. (Note: These are not necessarily in order of easy to hard, don't feel that you have to implement them in the order as they are.):
- The prompt you print should indicate the current working directory. For example:
The directory: /usr/foo/bar%
It may also indicate other things like machine name or username or any other information you would like.
Try
getcwd(char * buf, size_t size)
. - You should allow the user to specify commands either by
relative or absolute pathnames. To read in the command line,
you may want to consider the readline function from the GNU
readline library as it supports user editing of the command
line.
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 - You do not need to support setting of environment
variables. However, you may find it useful to know about these
variables especially PATH which is the list of
directories in which to look for a specified executable. You may
use execvp to have the system search the
PATH inherited by your own shell from its parent.
Linux TIP! Use
printenv $PATH
to see what's in your executable path - You should be able to redirect STDIN and STDOUT for the new
processes by using < and >. For
example,
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.)! You 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
- You should be able to place commands in the background with
an & at the end of the command line. (You do not
need to support moving processes between the foreground and the
background (ex.
bg
andfg
). You also do not need to support putting built-in commands in the background.) - You should maintain a history of commands previously
issued. The number of previous commands recorded can be a
compile time constant of at least 10.
This could be a FIFO list.
For example, if storing 10 commands,
the latest issued 10 commands will be displayed.
The oldest command is numbered as 1 and the latest command is 10.
Linux TIP! The
history
command can show you the remembered commands by linux bash shell. - A user should be able to repeat a previously issued command
by typing
!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
- A built-in
command is one for which no new process is
created but instead the functionality is build directly into the
shell itself. You should support the following built-in
commands:
jobs
,cd
,history
,exit
,kill
, andhelp
.- jobs provide a numbered list of processes currently executing in the background.
- cd should change the working directory.
- history should print the list of previously executed commands. The list of commands should be numbered such that the numbers can be used with ! to indicate a command to repeat.
- exit should terminate your shell process.
- kill %num should terminate the process numbered in the list of background processes returned by jobs (by sending it a SIGKILL signal).
- help 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 understand.)
Try
waitpid
with WNOHANG option to check without blocking. You can either check when jobs called or each time through the main while loop.Try
kill (pid, SIGKILL)
.Note: Usually
kill num
refers to the process with ProcessIdnum
; whilekill %num
refers to the process in the jobs list with numbernum
- If the user chooses to
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. - You may assume that each item in the command string is
seperated on either side by at least on space (e.g.
prog > outfile
rather thanprog>outfile
).
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].
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))
Try waitpid(pid, status, options)
.
Optional Features
If you enjoy this assignment and would like to add more advanced features to your shell, you can earn extra credits for them. Here are some sugguestions:
- You could port the code to run on Windows as well using the CreateProcess/WaitForSingleObject. (count as two features)
- You could support optional parameters to some of the built-in
commands. For example,
history -s num
could set the size of the history buffer andhistory 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 recommendhelp command
to return more detailed information on a single command. - You could support | , a pipe, between two processes. For
example,
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. - You could implement more advanced I/O redirection as described
above (
>&
,>!
, etc.). - You could implement the built-in shell functions,
fg
andbg
, to move processes between the background and the foreground. - You could support the editing of shell variables with built-in
shell functions like
printenv
andsetenv
. - I wouldn't recommend it :-), but you could even write support
for shell programming (e.g.
if
/then
,while
,for
constructs). - Tab completion and command prompt editing. The GNU readline library makes this easy.
- Up and down errors to scroll through the history list. The GNU history library makes easy.
- Adding the builtin function
ls
on Windows. - You could relax the parsing constraints on the command line
itself (e.g. correctly recognize the space free command
prog>outfile
). - Terminal support (messy!)(You may notice that some programs like more or pine are aware of the screen real estate they need - that requires terminal emulation support.
- You could also try porting it to yet another OS. (PalmOS?)
Any advanced shell feature is likely to earn you some extra credit, but you can earn it only after you've finished the required functions.
SHELL: Available Materials
-
Gradesheet: Here is the grading criteria for this assignment. Remember a good CS programmer always maintains good documentation. It also matters to your grade.
-
Source Code: Here is the skeleton code where you can start for this assignment. Following the skeleton code can save you a lot of time. But you can also do from the scratch on your own if you feel confident in your programming skills, we would love to give extra credit for your effort.
-
Shell Command Sample:Here is an example of how your shell behaves alike to user's commands. It doesn't have to be 100% exactly the same but the userability and functionality should be better.
-
C Prime Code:Here demos serveral C-style programming code.
-
System Call Usage:Here demos how to use system calls in C programs. Those system calls are provided by OS and will be helpful in this assignment for sure.
Note: These are just examples to show you basic concepts, the code that you should start with the skeleton code above, given in the shellWithParser.tar.gz file)
SHELL: Submitting Your Assignment
What to submit:
- Source Code
- Codes need to be commented and have necessary error-checkings
- Make sure your code can be compiled and run on ITL machines unless you particuliarly mention in README
- Remove all object file or excutables by the command make clean before submission.(Directory space is limited)
-
README
- State your code status and bugs you have found
- List the features you have implemented, especially any additional features
- Acknowledge the helpers or the Internet resources if you have
NOTE:After submission, ssh into polaris again to verify your files do exist inside the assignment folder
Where to submit:
- Server: polaris.clarkson.edu
- Assignment directory: /afs/cu/class/cs444/sp14/shell/your_clarksonID
-
To copy your files from your local linux to polaris, you can use the command on linux terminal
scp your_assignment_folder/* your_clarksonID@polaris.clarkson.edu:/afs/cu/class/cs444/sp14/shell/your_clarksonID
-
you can also use some ftp GUI application to upload your files into the assignment folder with the following parameters:
-
Hostname:
polaris.clarkson.edu
-
Port:
22
-
Protocol:
SFTP
-
User name:
Your_clarksonID
-
Password:
Your_clarksonEmail_password
-
Directory:
/afs/clarkson.edu/class/cs444/sp14/shell/your_clarksonID
-
Hostname:
-
If your asignment files are already in your polaris home directory, then you can use the following command in polaris
cp ~/your_assignment_folder/* /afs/cu/class/cs444/sp14/shell/your_clarksonID
Tips:
When to submit:
Due on Friday Midnight 2/07/2014
Helpful Resources
Here are a list of resources you may find helpful. Feel free to send mail suggesting others.
Linux/UNIX
GNU history library (for the required functionality might be easier without it?)
MANPAGE
The following system 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