Homework 3: Write your own shell
The command line is a flexible, powerful tool that takes advantage of Unix-style OS’s “everything is a file” and “compose lots of little programs to do complicated tasks” strategies.
In this assignment, you will build a shell that can compose multiple programs, manage jobs, and best
of all, it will use the modern
posix_spawn interface rather than the sad old
The programming part
For this assignment you are to write a simple program that will act as a shell. The program should:
- Display a command prompt and read in a command line from the user (the prompt must be
CS361 >, otherwise it cannot be detected by the test script)
- Your shell must support basic piping like the unix shell.
$ command arg1 arg2 ...Run command, with stdin and stdout connected to their usual files.
$ command args < input_redirectionRun the command, but connect
stdinto the contents of the file
$ command args > output_redirectionRun the command, but connect
stdoutto the contents of the file
$ command args < input_redirection > output_redirectionDo both of the previous tasks at the same time.
$ command1 | command2Run command1 as in #1, but redirect the output of
command1as input to
$ command1 ; command2Run command1 as in #1, wait for it to finish, and then run command 2 as in #1.
- When any non-background
commandfinishes, the parent should output the prompt again as normal. However, if the user executes the special command
?, the shell should output
\npid:%d status:%d\n(with the proper relevant values inserted into the format string), and then print the prompt again and wait for more input. For composed commands, the output should only be shown for the final command in the sequence.
- Your shell should handle the following signals:
- SIGINT - Generated by
Ctrl-C. This signal allows a user to terminate a running program. Your shell should not exit when user presses
Ctrl-Cor the process receives SIGINT but simply report that the SIGINT signal has been received by the shell. If the process receives SIGINT, you must print the string “caught sigint” on a line by itself, and then show the prompt again.
- SIGTSTP - Generated by
Ctrl-Z. This signal allows a user to pause a running program. Your shell should not exit when user presses
Ctrl-Zor the process receives SIGTSTP but simply report that the SIGTSTP signal has been received by the shell. If your shell receives SIGTSTP, you must print the string “caught sigtstp” on a line by itself, and then show the prompt again.
- SIGINT - Generated by
- The shell does NOT need to support restoring stopped background processes or handling multiple
chained pipes (e.g.
command1 | command2 | command3). Essentially, if anything not matching the use cases/requirements above is in question, you probably do not have to do it. Due to the breadth of this assignment, it is difficult to clarify every case in writing. Please ask in office hours or on Piazza if you have questions or need clarification.
A word on academic integrity
Previous solutions, or other students’ work, are off limits and any cheating will be prosecuted to the fullest extent of university rules. There are many pre-written shells on the Internet. If we find you using them, we will give you an F in the class. Don’t look at them, don’t use them. It is not worth it. Remember that the assignments in this course are meant to provide structure for your own learning, not just a seal of approval that will get you your next job.
It is highly recommended you develop and test your code on systems1 or the Ubuntu 18.04 devcontainer we’ve provided. We streamlined the build process so getting started in a devcontainer should be much faster than it was before.
When you turn in the assignment, the TA should be able to compile your program by running’
gcc -Wall -Werror -o spawnshell spawnshell.c in the
hw3 directory (case sensitive). You are free
to include any files e.g.
hw3.h, it just has to compile using the above command.
One very important component of all software engineering is testing. Rather than doing our testing for this assignment via the autograder right away, we will be showing you how you can test the full functionality of your shell. You’re encouraged to write your own test cases to determine whether your code is working correctly.
Using input redirection to test a shell
One important concept we’ll go over this week is file redirection. In short, file redirection allows you to read your program’s input from a file, rather than from the keyboard.
For instance, if you have a file
input that has the lines:
pwd ls date +%Y%m%d
You can feed it to a new instance of a shell program by redirecting the input from that file by
< character as an argument, then the name of the file:
ckanich@home-desktop:~/repos/shell-skel$ sh < input
In addition to using
sh, you can also run the skeleton code for the assignment in the same way,
and see that it works properly. If you would like to automate the process of comparing the output of
a real shell with your shell, you can use the
diff program. Running
man diff at the command line
diff command linux can give you a good introduction to how it works.
Grading will happen using an autograder on Gradescope. Note that we will not be releasing the autograder early on during the assignment: learning how to test your own code is an important aspect of this assignment.