Building a Unix Shell
Goal
- Develop a deep understanding of how a command-line shell works.
Credits
This lab was developed by Prof. L. Felipe Perrone. Permission to reuse this material in parts or in its entirety is granted provided that this credits note is not removed. Additional files associated with this lab, as well as any existing solutions can be provided upon request by e-mail to perrone[at]bucknell[dot]edu
Set Up
Create the directory for this lab ~/csci315/Labs/Lab9 in your CSCI 315 local repo. There is no skeleton code for this assignment. Everything you turn in will be of your authorship.
It goes without saying that you need to create a Makefile instrumented to build each and every one of the executables in this lab. Failing to do that will lose you 10 points for the lab.
You should consider using your wrappers.h and wrappers.c for your own benefit. Without the wrappers, you would have to write extra code to catch return values and deal with error conditions on your own.
Problem 1 (30 points)
Create a file called ishell.c in which you will build a program which will show the following user prompt, when executed:
ishell>
Upon seeing this prompt, the user should be able type a command line to be executed. For instance, it may be something like the following:
ishell> cp ishell.c otherfile.c
Your program will read this input from the keyboard and spawn off a child process to execute the command line, wait for the child to terminate and, when that happens, show the prompt again repeating the whole procedure. Effectively, this means that the parent process will run on an infinite loop of spawning a child to do the user’s bidding and waiting for the child process to terminate.
The general idea is that in your ishell.c, your code will spawn a new child and the child calls one of the exec functions to execute the command. In the mean time, the parent process will wait for the child to complete. When the parent knows that the child is done, it displays the shell’s prompt again and waits for the user to type another command. It is up to you to determine which type of exec function will work best for this scenario.
Reading the man page for exec functions, you will see that some of these functions expect to receive an array of pointers to C strings. The exec call has no way to know the length of the array data structure (remember, you’re programming in C, not in a language that would have an array data type which would have an instance field to indicate the number of elements stored). The man page will tell you that this array must be terminated by a NULL element, which serves as the sentinel that marks the end of the array.
Depending on the specific variant of exec you choose to use, you will need to deal with the command line string differently. For all of them, though, you will need to tease out the name of the executable file to run. For some of them, you will need to have pointers to each individual token, that is, the substring separated from others by blank spaces. (Using a robust tokenizer to get this done will be helpful.)
Constraint: your solution to the problems in this lab cannot use the system(3) library call.
Note: In Makefile, you will provide the complete instructions for gnu make to be able to compile your program ishell.c into an executable.
When you have finished debugging your program, you should do:
- cd ~/csci315/Lab9
- git pull
- git add ishell.c
- git add Makefile
- git commit -m “Lab 9.1 completed”
- git push
Problem 2 (15 points)
When you run a program through a shell, the program executes and sends back to the shell a termination code. Modify your ishell.c so that it captures the termination code from the program it executes and prints out one of two possible messages:
[ishell: program terminated successfully]
or
[ishell: program terminated abnormally][“return status”]
where “return status” is numeric termination code returned by the process.
When you have finished debugging your program, you should do:
- cd ~/csci315/Lab9
- git pull
- git add ishell.c
- git commit -m “Lab9.2 completed”
- git push
Problem 3 (15 points)
Modify your ishell.c so that it can execute two commands in sequence when they appear in the command line separated by a semi-colon character. For instance:
ishell> a; b
should execute command a, wait for its termination, and then execute command b. For this problem, all you have to do is enable your shell to execute two commands sequentially. (Enabling ishell to run any number of commands separated by semi-colon is a nice extension that you can develop on your own, but it’s not required for this specific problem.)
When you have finished debugging your program, you should do:
- cd ~/csci315/Lab9
- git pull
- git add ishell.c
- git commit -m “Lab 9.3 completed”
- git push
Problem 4 (15 points)
Modify your ishell.c so that when the user presses the “enter” key twice in a row, your shell displays the list of files in the current working directory. For instance:
ishell>[enter][enter]
will show the directory listing.
Extra Challenge: it would be more interesting to be able to replicate the behavior of bash, which offers the functionality above when the user presses the “tab” key twice, without having to press enter after hitting tab each time. If you are able to incorporate this feature into your ishell, modify the message in your commit to say “Lab 9.4 challenge completed”. Otherwise do:
- cd ~/csci315/Lab9
- git pull
- git add ishell.c
- git commit -m “Lab 9.4 completed”
- git push
Problem 5 (25 points)
Do a little bit of research to discover additional functionalities offered by bash or any other Unix shell you like. Pick one that you find feasible to incorporate into your ishell, code it up, test it (and, of course, debug it), and document what this feature is in a C comment block at the start of your ishell.c file. For full credit in this problem, your comments must give clear instructions on how to understand and to use your extra feature so that we can evaluate it. If you are unsure of whether your choice is a good enough feature to add, ask the instructor or the lab TA.
- cd ~/csci315/Lab9
- git pull
- git add ishell.c
- git commit -m “Lab 9.5 completed”
- git push
Hand In
Before turning in your work for grading, create a text file in your Lab 9 directory called submission.txt. In this file, provide a list to indicate to the grader, problem by problem, if you completed the problem and whether it works to specification. Wrap everything up by turning in this file:
- git pull
- git add ~/csci315/Lab9/submission.txt
- Be sure to also add any files needed for compilation.
- git commit -m “Lab 9 completed”
- git push
Grading Rubrics
Problem 1 [a total of 30 points]
- [10 points] The ishell program compiles, runs, and can execute some basic commands such as cp, ls, date.
- [5 points] The ishell program displays the proper prompt every time a command is executed.
- [10 points] The ishell program calls the proper exec calls.
- [5 points] The ishell program works correctly with repetitive, different, any shell commands.
Problem 2 [a total of 15 points]
- [8 points] The ishell program prints the correct message and code when the command is executed successfully.
- [7 points] The ishell program prints the correct message and code when the command execution fails.
Problem 3 [a total of 15 points]
- [15 points] The ishell program can execute two commands separated by a semi-colon on the same line.
Problem 4 [a total of 15 points]
- [15 points] The ishell program implements the feature of listing files with two consecutive <Enter> keys.
Problem 5 [a total of 25 points]
- [25 points] Any meaningful and reasonable extra feature is implemented and documented.