|
CMSC421
Principals of Operating Systems
Sections 0101/0201/0301
|
CSEE
|
Programming Project #2
Assigned: 13 Nov 2002
Project Due: 5 Dec 2002 at 11:59 pm
27 Nov 2002 at 11:59 pm for ten percent extra credit
25 Nov
Updated: 18 Nov
Project 2: Implementing a Simple Shell
(c) 1997, Howard E. Motteler; Modified by Gary L. Burt, 2001
Project Goals
The goals of this project are to learn the basics of how a "shell" or
command interpreter works, how pipes are used, how sockets are used,
and to gain experience programming with UNIX
processes and system calls.
The Project
Shell
You are to design and implement a simple shell, "mysh".
Some of the commands of this shell are to be internal and some are to
external. The internal commands for project will be the command to
list the directory (the UNIX "ls" command), the change directory
command ("cd"), the user's date command ("date"), the history command ("history"),
command to restart
the client ("restartclient") and the "exit" command).
The following is a prototype of what your main might look like:
while ( TRUE ) /* repeat forever */
{
read_command( command, parameters); /* read input from terminal */
/* Here you would have to check to see if */
/* exit was entered and if it was, break out of the loop. */
if ( fork( ) != 0 ) /* fork off child process */
{
/* Parent Code */
waitpid( -1, &status, 0 ); /* wait for child to exit */
}
else
{
/* Child code */
execve( command, parameters, 0 ); /* execute the command */
exit( 0 ); /* when sucessful, there is */
/* no return from execve */
}
}
Check the documentation for the exec calls to see what is the int character
arrays command and parameters.
Pipe and Sockets
You are to design and implement file-transfer system that use two Linux
systems (such as Linux1, Linux2, and lab computer running under Linux).
There will be two independent programs client and server.
You will have to log into both systems and designed which machine is which.
On the server side, you will start the program server which
will monitor the socket, waiting for commands. It is important that you
start the server first and then the client. If the server terminates for
any reason, you must kill the client and then restart the server and then the
client.
There will be a 20% penatly if this part is not implemented!
On the client side, mysh will create a pipe and execute the program
client. The client will wait until it receives a
command on the pipe from mysh. Commands that it will be expected to handle are:
- remoteput
- remoteget
- remotels
Files of any size can be transferred, so you will have to coordinate the
flow of data across the pipe so that the data being
sent does not overrun any buffers.
You will need to run a unique port number, so use 4XXXX, where "XXXX" is the last
four digits of your SSN. If there are any programs, to 5XXXX instead, and
document the change!
Sample of the socket code:
Client side
Server side
Specifications
Your shell should be able to parse and execute command lines of the
following form
cmd
cmd > file
cmd < file
cmd < file > file
cmd | cmd
cmd ; cmd
!!
!nr
where:
- "file" is any valid UNIX filename.
- "cmd" is a program name followed by zero or more options and by zero or more arguments.
- There will no wildcards, no in-line command evaluation, no macro
substitutions, and commands and filenames include
the symbols ">", "<", ";" or "|".
- There can be any of commands separated by the "|" or ";" tokens.
- There are internal and external commands. The external commands will
by the ones you use fork and exec and get existing programs to execute.
Internal commands will be handled by the program mysh by code that
you must write:
- When "cmd" is exit, your shell should terminate.
- For the special case when "cmd" is "ls", ls -i, ls -a,ls -l,
or li -li your shell will list the files for the directory given
in the "file" argument. When there is no "file" specified, you are to use
all of the current working directory.
Your ouput will have the same appearance as the UNIX version of the same command.
You will find the necessary information in the directory entry and
the assocated inode struction.
- When the "cmd" is cd, your mysh must make the necessary
system call in order for the cd to work correctly.
- When the "cmd" is remoteput, it will be followed with a filename
(using either an absolute or relative pathname). mysh will send
the file's contents to the socket-client via a pipe. Then the socket-client
will transfer the contents to the socket-server. The socket-server will
will save the contents to a file with the same name.
- When the "cmd" is remoteget and a filename, mysh will send
the name to the socket-client, which will request the file from the
socket-server. The socket-client will save the file's contents in
the current working directory.
- When the "cmd" is remotels, mysh will request the a listing
of the directory on the other side of the socket. It will be assumed that
all work will be done in only one directory on the socket-server.
- When the "cmd" is "restartclient", mysh will execute the socket-client
software.
You must provide error-handling for all internal commands, similiar to how
Linux does it. (For external commands, you can let Linux message print out, so you don't have
to do any extra work for that!) Transfer to data must be coordinated using a semaphore!
- Your shell should also be able to parse and execute command lines
above ending with an "&" that puts the specified process or
processes into the background. (With multiple commands, only put
put the last command into the backgroud.)
- You can assume that all command lines are of the form described
here, and you do not have to check for any other sorts of input.
In particular, you do not have to expand filename wildcards.
- Use fork() and either execl(), execve() or execvp() to execute
the commands. The main difference is that execvp() will search
your PATH for the specified executable, and doesn't have an
explicit environment argument. Additional information about these
calls is available from the man pages.
- Your shell should prompt the user for each command line with the
string "mysh[n]>". The number n is the number
of the command )(for the history version). You must have a history
buffer for at least 50 commands and this history must be carryed
over to the next use of "mysh"
- Your date command must allow the user to format the date output in the same
way UNIX does. You must not attempt to set the date on the
system since this is a privileged command. You can limit
the formatting to only printing out the name of the day, the
number of the day in the month, the name of the month, full year and
the time as hour, minute and seconds. (Hint: look at the man
page for strftime( ).
- Your shell will allow two forms of the history command. The first
is the double explanation points ("bang-bang") which will
repeat the last line of input that was typed in. The second
version is the explanation point with a number ("bang-n") . The number
is a command from the history buffer. You will be required to
keep the last fifty commands in the buffer, and know the
history number of each command. If the user enters an invalid
number, output an appropriate error message and advance to the
next command.
- The final version you submit should not print
any test messages or other extraneous jabber. You should print
errors returned by execvp() or execve(); you can use
strerror(errno) to make your error reporting more informative;
errno is an external variable set to the most recent error, and
strerror() translates this to a human-readable string. You may
find the UNIX string manipulation library routines (such as strtok)
convenient for parsing the command line; do a "man string" to
learn more about these functions.
- To redirect input from a file to a program, so the file appears
as "standard input" to the program (e.g., as in the
command " wc < test.dat"), you will have:
- to manipulate file descriptors. To connect a file to the UNIX "standard
input" (by convention file descriptor 0), you can use the dup2()system
call, as in the following example.
if (( fd = open ( fname, O_RDONLY )) == -1 )
{
fprintf( stderr, "mysh error: can't open %s\n", fname);
exit(1);
}
dup2(fd, 0);
close(fd);
if(execvp(cmd, args == -1 )
{
fprintf(stderr, "mysh error: %s\n", strerror(errno) );
}
- OR you can use a real pipe (see system call for pipe).
When you have redirection, make sure to do it in the child and not the
partent!
- If we wanted to execute the command "wc -l", "cmd" in the above
example would be the string "wc", and the string array "args"
would have its first element pointing to "wc", its second element
pointing to "-l", and its third element the null pointer 0,
indicating the end of the arg array.
- The "&" function is easy to implement--without the "&",
the shell waits for the child process; with the "&" it does not
wait.
- The pipe function "|" is a little more difficult, and can be
implemented with either a temporary file, or preferably with a
real UNIX pipe.
- The ";" is used to separate commands on the command line. Process
the first part independently and when it is finished, then process
the second part.
Extra Credit Feature
UNIX has three different types of quotation marks:
Single Quote
Anything inside a single quote is to be taken as a constant that should not be modified.
'Hello'
Double Quote
Inside double quotes, variable names are replaced by the variable contents:
echo "$HOME"
/home/faculty1/burt
Single Back Quote
If a command contains something inside a single back quotes, it tells the
shell that it is to run the command that is inside the single back quotes and
replace the what is inside the double back quotes with the results of this
second command and use it to execute the first command:
Exampele:
burt[103]: echo `whoami`
burt
In this case, the command "whoami" returned the results of whoami (which is "burt"
and the command became
echo burt
Another example is:
burt[105]: echo "It is currently `date`"
It is currently Wed Nov 13 17:01:06 EST 2002
The date command returned the string "Wed Nov 13 17:01:06 EST 2002"
and turned the command into:
echo "It is currently Wed Nov 13 17:01:06 EST 2002"
The command
finger `whoami`
became
finger burt
and produced the results of:
burt[106]: finger `whoami`
Login: burt Name: Gary Burt
Directory: /home/faculty1/burt Shell: /bin/csh
Never logged in.
New mail received Wed Nov 13 16:37 2002 (EST)
Unread since Tue Nov 12 17:12 2002 (EST)
No Plan.
A final example is:
echo "You have `ls | wc -l` files in this directory."
produces the output of:
You have 55 files in this directory.
Your mission, Mr. Plelphs, is to implement the single backquote in your project for 5% extra credit.
Grading
Make sure you have read the general information on programming projects.
Approximately 20% of your grade is for documentation, and the remainder
is based on how well your project works. Describe any non-trivial
data structures you have used, and briefly say how each relevant
function acts on those data structures. Do not simply echo the
specifications given here.
The coding standard and indentation
standards must be following and compliance will be part of the 20% for documentation!
There are 40 commands that I have given to the TAs to be used
when grading the project that will make up the other 80%.
Do not use the system( ) system call or invoke the UNIX shell to
implement your shell!
Doing so will earn you a zero on the
project!
You must do the project described here. Doing some other similar or
dissimilar project, matter how difficult or clever, may be worth 0
points. This is not a group project; please do your own work, and
be careful about sharing your code. It is OK to discuss design issues,
but in your documentation, you should give credit to your sources.
You will be provided with a copy of the test plan that the TAs will use
when the grade this project, so that you will know exactly how they will
test this project. However, you must make sure that you can meet all
the requirement in any of the prescribed forms! The TA will be allowed
to run any commands necessary to give the proper grade. You can not limit
you programs to just those commands on the webpage, either!
What to turn in
You must have a makefile, design document, all source code and a README file.
If your code is
in more than one file, you will have to a makefile. For help with a makefile,
see the TA.
You are to provide all
necessary instructions on how to build and execute your programs in
the README file, so that the TAs can do the best job of building and
testing your system. Anything that you feel will help the TA should
be included. Do not turn in any executables or binaries!.
Put all of the required files into a tar file and
When your project is absolutely finished and you have completely and
totally tested your work, you are to submit the project tar file for grading
using the digital dropbox in Blackboard.
It is important that your tar file be named with
the last four digits of your SSN and "prj2". If the last four
of your SSN were 6789, then the file name would bd:
6789prj2.tar
The TA's will deduct points if you do not correctly name your file.
Hints and Tips
UMBC
|
CSEE