A simple command shell
Upload via Moodle as: shell.tar or shell208.c
As usual, you are welcome to work with a partner if you wish.
Goals
- Practice manipulating Linux processes in C
- Demystify command shells like bash, zsh, etc.
Rubric
Background
When you interact with a Unix (or other similar) command prompt, you are interacting with a program known as a command shell. This might be bash in a WSL or Linux terminal, bash in the terminal in VS Code, zsh in a macOS Terminal, PowerShell in Windows, MS-DOS in a Windows cmd window, etc.
Though command shells are typically sophisticated programs with many features, and they often implement their own full-fledged programming languages (e.g., "bash scripting"), their flow of control is, at heart, conceptually very simple:
- print a prompt for the user
- read the user's command
- execute the command
- wait for the command to finish
- go to step 1
Your assignment
You will write a simple command shell, named shell208, that performs the most common operations that shells perform. Specifically, you will want your shell to be able to handle the styles of operation listed in the rubric above.
For a score of 23/25 (an excellent score), your shell should be able to handle commands involving single-word commands, commands with command-line arguments, pairs of command connected by a | ("pipe"), and redirection of standard output to a file. For example:
For an additional challenge and up to 2 extra points, your shell can support redirecting stdin from a using < and letting commands execute in the background using &.
This scoring system is designed specifically to weight the most straightforward features most highly, since one of the key goals of the assignment is to make clear to you that process-manipulation programs can be quite simply structured.
I'm also offering a few extra credit points. These will be applied to your point total at the very end of the term, after I have assigned course grades. That is, there's no chance of your extra credit points affecting the grade boundaries for the class as a whole, but extra credit points offer a small chance of improving your course grade. But really, all this talk of grades is kind of beside the point—the "extra credit" features are mainly for fun, and to give you a chance to try to implement something more difficult if you have the time and inclination.
With that excessively wordy preamble, the extra credit features are: using up/down arrow keys to cycle through recent commands and re-execute them; implementing multi-command pipelines ("command1 | command2 | command3 |..."); and responding to a SIGINT signal by terminating the currently running child processes.
Submitting your work
Submit your program via Moodle in one of two forms.
Option 1: a single C source file named shell208.c. This program should compile without warnings on mantis using:
gcc -Wall -Werror -g -O0 -o shell208 shell208.cOption 2: a shell208.tar file containing a folder named shell208, which in turn contains any files your shell needs. This tar file must include a Makefile that enables us to compile and run your shell on mantis like so:
tar xvf shell208.tar cd shell208 make shell208 ./shell208
Help
I have posted a collection of sample programs that demonstrate all of the essential techniques you will need to complete this assignment. You'll mostly be repurposing the sample programs and making sure the logic fits together.
I have posted:
- Process-related samples on the samples page
- A video to get you started on this assignment: Getting Started on the Command Shell, Part 1
- [NOT READY UNTIL THURSDAY AFTERNOON] A second video (to help with pipes and redirection) Getting Started on the Command Shell, Part 2
- signaltest.c
A note about the Ctrl-C feature
Dealing with Ctrl-C in a shell is tricky. If you are running a process A in the foreground (i.e. without &), then the Ctrl-C will cause a SIGINT signal to be sent to process A. Unless A has registered a SIGINT handler, the signal will terminate A (and if A's parent process has called "wait", then wait will return in the parent, etc.).
But what if you are running a pipeline (e.g. "A | B")? Do both A and B receive a SIGINT signal? Do they both terminate? How might you find out? (You could, for example, write a couple simple programs of your own, include in them SIGINT handlers that print a message? That way you could experiment with the conditions under which the child and parent processes receive a SIGINT signal.)
An additional tricky part of this feature is that there is no standard way to iterate over the child processes of a Unix process. So even if you figured out a way to forward a SIGINT signal received by a child process to the parent process, the parent wouldn't be able to just walk through its children terminating each one in turn.
On the other hand, there are ways to examine the termination status of a child process when wait or waitpid returns information about a child to the parent. You can try to search for information on the internet for this.
So, I have moved this feature from the Advanced section of the rubric to the Extra Credit section, and I have left its specification relatively vague. If you want to explore your options for handling Ctrl-C, go ahead and implement something interesting. If you want to explain your choices, you can do so either in a readme file or in the comments in your source code.
Have fun!
This program is pretty cool once you get it working.