EE 209: Programming Structures for EE
Assignment 5: A Unix Shell
(Acknowledgment: This assignment is borrowed and slightly modified from Princeton COS 217)
The purpose of this assignment is to help you learn about Unix processes, low-level input/output, and signals. It will also give you ample opportunity to define software modules; in that sense the assignment is a capstone for the course.
Signal handling (as described below) is the “on your own” part of this assignment. “On your own” means you should NOT discuss with other students (other than your teammate).
[Note] You will get an extra credit of 10% of the full score if you implement file redirection and pipe. If you implement both, you’ll get 20% of the full score.
A Unix shell is a program that makes the facilities of the operating system available to interactive users. There are several popular Unix shells:
sh (the Bourne shell),
csh (the C shell), and
bash (the Bourne Again shell) are a few.
Your task in this assignment is to create a program named ish(if your program name isn’t ish it will be automatically zero score.). Your program should be a minimal but realistic interactive Unix shell. A Supplementary Information page lists detailed implementation requirements and recommendations.
You can work on this assignment with a partner in your class. A team should be no more than 2 people in the same class. Submit just one copy to KLMS if you work in a team.
If you choose to work alone (e.g., without a partner) on this assignment, you will receive extra credit as described below.
Building a Program
-D_GNU_SOURCE options when building your program.
Initialization and Termination
When first started, your program should read and interpret lines from the file
.ishrc in the user’s HOME directory, provided that the file exists and is readable. Note that the file name is
ishrc), and that it resides in the user’s HOME directory, not the current (alias working) directory.
To facilitate your debugging and our testing, your program should print each line that it reads from
.ishrc immediately after reading it. Your program should print a percent sign and a space (% ) before each such line.
Your program should terminate when the user types Ctrl-d or issues the
exit command. (See also the section below entitled “Signal Handling.”)
Important : In supplementary information : (Required) Your program should work properly if the
.ishrc file does not exist or is not readable. It is not an error for the
.ishrc file to not exist or to be unreadable.
After start-up processing, your program repeatedly should perform these actions:
- Print to the standard output stream a prompt consisting of a percent sign followed by a space.
- Read a line from the standard input stream.
- Lexically analyze the line to form an array of tokens.
- Syntactically analyze (i.e. parse) the token array to form a command.
- Execute the command.
Informally, a token should be a word. More formally, a token should consist of a sequence of non-white-space characters that is separated from other tokens by white-space characters. There should be two exceptions:
- The special character ‘|’ should form separate token.
- Strings enclosed in double quotes (“) should form part or all of a single token. Special characters inside of strings should not form separate tokens.
Your program should assume that no line of the standard input stream contains more than 1023 characters; the terminating newline character is included in that count. In other words, your program should assume that a string composed from a line of input can fit in an array of characters of length 1024. If a line of the standard input stream is longer than 1023 characters, then your program need not handle it properly; but it should not corrupt memory.
You may use dfa.c as reference. Note, however, it does not have the full functionality required by ish.
A command should be a sequence of tokens, the first of which specifies the command name.
Your program should interpret four shell built-in commands:
setenv var [value]
|If environment variable
|Your program should destroy the environment variable
|Your program should change its working directory to
|Your program should exit with exit status 0.|
|‘fg’ command brings a command that has been running in the background to the foreground. When there are multiple programs running in the background, ‘fg’ command should bring the most recently launched program to the foreground.|
- Note that those built-in commands should neither read from the standard input stream nor write to the standard output stream. Your program should print an error message if there is any piped commmand or file redirection with those built-in commands.
- If the command is not a built-in command, then your program should consider the command name to be the name of a file that contains code to be executed. Your program should fork a child process and pass the file name, along with its arguments, to the
execvpsystem call. If the attempt to execute the file fails, then your program should print an error message indicating the reason for the failure.
It is required to call wait for every child that has been created.
Background / Foreground Processes
You are going to implement your shell to apply ‘&’ and ‘fg’ command. Implementing ‘&’ and ‘fg’ command is essential.
- A command is executed in the background when ‘&’ is appended at the end of the command line.
- ‘fg’ command brings a command that has been running in the background to the foreground.
- When there are multiple programs running in the background, ‘fg’ command should bring the most recently launched program to the foreground.
- [Note] The case that uses pipe (‘|’) command and background (‘&’) together does not occur.
[NOTE] Ctrl-d represents EOF, not a signal. Do NOT make a signal handler for Ctrl-d.
When the user types Ctrl-c, Linux sends a SIGINT signal to the parent process and its children. Upon receiving a SIGINT signal:
- The parent process should ignore the SIGINT signal.
- A child process should not necessarily ignore the SIGINT signal. That is, unless the child process itself (beyond the control of parent process) has installed a handler for SIGINT signals, the child process should terminate.
When the user types Ctrl-\, Linux sends a SIGQUIT signal to the parent process and its children. Upon receiving a SIGQUIT signal:
- The parent process should print the message “Type Ctrl-\ again within 5 seconds to exit.” to the standard output stream. If and only if the user indeed types Ctrl-\ again within 5 seconds of wall-clock time, then the parent process should terminate.
- A child process should not necessarily ignore the SIGQUIT signal. That is, unless the child process itself (beyond the control of the parent process) has installed a handler for SIGQUIT signals, the child process should terminate.
- Your program should handle an erroneous line gracefully by rejecting the line and writing a descriptive error message to the standard error stream.
- Your program should handle all user errors. It should be impossible for the user’s input to cause your program to crash.
Your program should contain no memory leaks. For every call of
calloc, eventually there should be a corresponding call of
Extra Credit 1 (extra 10% of the full score of this assignment)
You are going to implement redirection of standard input and standard output as an extra credit.
- The special character ‘<‘ and ‘>’ should form separate token in lexical analysis.
- The ‘<‘ token should indicate that the following token is a name of a file. Your program should redirect the command’s standard input to that file. It should be an error to redirect a command’s standard input stream more than once. It should also be an error to redirect a command’s standard input stream after a pipe token (See Redirection section in supplementary information page).
- The ‘>’ token should indicate that the following token is a name of a file. Your program should redirect the command’s standard output to that file. It should be an error to redirect a command’s standard output stream more than once. It should also be an error to redirect a command’s standard output stream before a pipe token (See Redirection section in supplementary information page).
- If the standard input stream is redirected to a file that does not exist, then your program should print an appropriate error message.
- If the standard output stream is redirected to a file that does not exist, then your program should create it. If the standard output stream is redirected to a file that already exists, then your program should destroy the file’s contents and rewrite the file from scratch. Your program should set the permissions of the file to 0600.
Extra Credit 2 (extra 10% of the full score of this assignment)
You are going to implement pipe so that you can run command piplelines such as:
% ls | sort | grep | wc
- The ‘|’ token should indicate that the immediate token after the ‘|’ is another command.
- You might find the man pages for pipe, fork, close, and dup.
- Your program should redirect the standard output of the command on the left to the standard input of the command on the right.
- If there’s no following token after ‘|’, your program should print out an appropriate error message.
- There can be multiple pipe operators in a single command.
Extra Credit 3 (extra 20% of your earned score including the extra credit)
If you do this assignment on your own without a partner, you will receive extra credit which is worth 20% of (your basic score + extra credit1). Here is an example. If your score is 60 and you got extra credit 1, your earned score is 60 + 20 = 80. If you worked alone, you will receive 20% x 80 = 16 additional points as extra credit 2. So, your total score will be 86.(maximum score: 144=((100+20)*1.2))
This assignment’s Extra credit will be caculated over 100.
Test your program by creating multiple files containing lines which your program should interpret, repeatedly copying each to the .ishrc file in your HOME directory, and restarting your program. The file
ishrc.txt contains a sequence of commands that can serve as a minimal test case. You should develop many more test files.
Of course you also should test your program manually by typing commands at its prompt.
Develop on lab machines. Use
emacs to create source code. Use
make to automate the build process. Use
gdb to debug.
An executable version of the assignment solution is available in
sampleish . Use it to resolve any issues concerning the desired functionality of your program. We also provide the interface and implementation of the
DynArray ADT that we discussed in precepts. You are welcome to use that ADT in your program.
readme file should contain:
- Your name and the name and the student ID of your partner.(you should register at Team Registration If you worked alone, only your name is needed.
- Description of work division between you and your partner.)
- A description of whatever help (if any) you received from others while doing the assignment, and the names of any individuals with whom you collaborated, as prescribed by the course “Policies” web page.
- (Optionally) An indication of how much time you spent doing the assignment.
- (Optionally) Your assessment of the assignment.
- (Optionally) Any information that will help us to grade your work in the most favorable light. In particular you should describe all known bugs.
Use KAIST KLMS to submit your assignments. Your submission should be one gzipped tar file whose name is
For example, if your student ID is 20201234, please name the file as
Create a local directory named ‘
YourStudentID_assign5‘ and place all your files in it. Then,
tar your submission file. Please refer here for how to archive your assignment.
Your submission need to include the following files:
- Your source code files. (If you used
DynArrayADT from precepts, then submit the
dynarray.cfiles as well. If you do not submit the files together, your score will be deducted.)
- Your source code files. (If you used
IMPORTANT: Your code should be compiled only with the submitted tar.gz file.
makefile. The first dependency rule should build your entire program. The
makefileshould maintain object (.o) files to allow for partial builds, and encode the dependencies among the files that comprise your program. As always, use the
gcc209command to build.
Please do not submit
emacs backup files, that is, files that end with ‘~’.
Your submission file should look like this:
[Note] If your code cannot be compiled at
gcc209, we cannot give you any points. Please double check before you submit.
We will grade your work on quality from the user’s point of view and from the programmer’s point of view. From the user’s point of view, your program has quality if it behaves as it should. The correct behavior of your program is defined by the previous sections of this assignment specification and by the given
sampleish program. From the programmer’s point of view, your program has quality if it is well styled and thereby simple to maintain. See the specifications of previous assignments for guidelines concerning style. Proper function-level and file-level modularity will be a prominent part of your grade. To encourage good coding practices, we will deduct points if
gcc209 generates warning messages. Remember that the Supplementary Information page lists detailed implementation requirements and recommendations.