UMBC CSEE |
Computer Science & Electrical Engineering
University of Maryland Baltimore County
Baltimore Maryland 21250 USA
voice: 410-455-3500 fax: -3969 |
UMBC|
CSEE|
CSEE help |
Project 1: Implementing a Simple Shell
(c) 1997, Howard E. Motteler; Modified by Gary L. Burt, 1998, 1999, 2000, 2001
Assigned: 3 April 2001
Due:8 May 2001
New New Date 10 May: Resubmit it necessary
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) 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 */
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 */
}
}
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-socket and server-socket.
You will have to log into both systems and designed which machine is which.
On the server side, you will start the program server-socket which
will monitor the socket, waiting for commands.
On the client side, mysh will create a pipe and execute the program
client-server. The client-server will wait until it receives a
command on the pipe. 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 using a semaphore, so that the data being
sent does not overrun any buffers.
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 arguments.
- There will no wildcards, no in-line command evaluation, no macro
substitutions, and commands and filenames which does not 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 -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. For the -i option, you are to list
the filename(s) and the inode number from the directory:
1267 foo
For the -l option, you are to display the filename(s) and the
permissions of the file(s) in the format that is used on UNIX:
-rwxrw-r--
-rwxrw-r-- foo
The combined version would be:
-rwxrw-r-- 1267 foo
You will find this 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. (You can let Linux message print out, so you don't have
to do things!) 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 man 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).
- 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.
- 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).
- 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.
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. You should describe your design
and implementation at the beginning of the project; this initial
description is worth 15% of your grade. Describe any non-trivial
data structures you have used, and briefly say how each relevant
routine acts on those data structures. Do not simply echo the
specifications given here.
Do not use the system() system call or invoke the UNIX shell to
implement your shell!
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.
You must have a makefile and a README file. 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.
What to turn in
When your project is absolutely finished and you have completely and
totally tested your work, you are to submit the project using the
submit command given to you by the TA.
If your code is
in more than one file, you will have to a makefile. For help with a makefile,
see the TA.
Hints and Tips
UMBC
|
CSEE