MP3: Shell

CS 241

Due: Tuesday, Feb. 21, 2012 at 11:59pm


Introduction

In this MP, you will implement a simple Unix shell interpreter (e.g., bash, csh etc.) called Shell. The basic function of a shell is to accept commands as inputs and execute the corresponding programs in response.

The purpose of this MP is to help you learn the basics of system calls for creating and managing processes as you implement your Shell program. You will write the code for your Shell program in shell.c inside your mp3 directory. The two other files you will write inside your mp3 directory: log.c and log.h will provide the implementation of a generic data structure log_t that you will use to implement the history feature of your Shell.

Part 1: Log

You will implement the data structure: log_t. The structure is defined inside log.h and the functions supported should be implemented inside log.c. You should use log_t to store the command history of your Shell. To use log_t, just include the header file "log.h" inside your Shell program shell.c. The API for the data structure as well as function descriptions can be found at log.html

To help with testing the log_t data structure, we provide you with the shell of a test program in testlog.c. Feel free to modify this tester file. To make and run the tester for the data structure testlog.c, use:

%> make            # make/compile your program
%> ./testlog       # run the testlog program

Part 2: Shell

To execute multiple commands, your shell should run in a loop where each iteration performs the following actions:

Task 1: Printing the Command Prompt

Your shell prompt MUST use the following format:

(pid=x)/path/to/cwd$
You can use printf("(pid=%d)%s$ ", pid, cwd) to print out this prompt. Here pid is the current process ID and cwd is the current working directory. Use getpid() to determine the process ID of the current process and getcwd() to lookup the current working directory.

Task 2: Reading the Command from stdin

Read a line from standard input. This line will be your command. The function getline() can be used to accomplish this easily. Beware that getline() may allocate memory that the user must free.

Task 3: Decipher the Command

Shell supports two types of commands: built-in and non built-in. While built-in commands are executed without creating a new process, a non built-in command MUST create a new process to execute the program for that particular command.

In order to decipher the command it will be necessary to tokenize the input on spaces. A token is any non-space character surrounded by the start or end of the line or spaces. The first token is considered the command and all subsequent tokens are referred to as the arguments. The strtok() function will help tokenize the command for you. Make sure to read the strtok()'s man pages to understand its nuances.

BUILT-IN COMMANDS

Your Shell will support four built-in commands: cd, exit and two commands (!# and !) based on a history feature. You should use the log from Part 1 to implement the history functionality.

NON BUILT-IN COMMANDS

If the command is not a Shell built-in (i.e., any command other than cd, exit, !# and !query), Shell should consider the command name to be the name of a file that contains executable binary code. Such a code must be executed in a process different from the one executing the shell.

Follow the following steps to execute a non built-in command:

Some non built-in UNIX commands that you may try to see whether your Shell works as it should are: ls, pwd, ps, echo hello.

Compiling and Running

To compile and run your shell, run the following commands from a Terminal on a Linux machine:

%> make
%> ./shell
%> ./gdb-shell
%> ./valgrind-shell

Type "exit" to exit from Shell or if this has not yet been implemented Ctrl-C to send a SIGINT signal. In order to run with gdb or valgrind use ./gdb-shell and valgrind-shell respectively.

Example

An example session of Shell can be found here to help illustrate the built-in functions. Example

IMPORTANT: Fork Bomb Warning!

If your code fork()s inside a loop that runs forever and without any sort of a pause, you will end up creating a fork bomb. You can read more about them here: http://en.wikipedia.org/wiki/Fork_bomb. We have provided a setup for you which uses the setrusage function to prevent this from happening.

If you work around the script we have provided AND fork bomb your machine, you will be shown no pity.

Grading, Submission and Other Details

Please fully read mp_grading.html for more details on grading, submission, and other topics that are shared between all MPs in CS 241.