CS 241: MP3: Shell

CS 241

Due: February 26th, 11:59pm


  1. If your code fork bombs during grading, the autograder will not be able to continue. This often results in the grader unable to record meaningful output from your program and will be a 0 if the autograder does not record output!
  2. Please make doubly sure that your fork() code is correct before committing your code for the nightly autograder.

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. You can find details on this data structure in the source code or the generated documentation.

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: Printing the PID of the Process Executing the Command

Shell must use the following format:
Command executed by pid=x
You can use printf("Command executed by pid=%d\n", pid) to print out this process information. Here pid is the PID of the process that executes the command.

Depending on the type of the command, shell may either execute the command by itself or may require to spawn a child process to execute the command.  Hence, for the built-in commands, this pid would be the same as the shell pid. However, for the non built-in commands, this pid would be the PID of the child process that executes the command.

Task 4: 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.

For the purpose of simplicity, all commands we will test will contain no extra whitespace anywhere in the command (or extra junk that doesn't make sense like the " abc" in "!# abc"). This includes before the command, after the command, or between different arguments. We also will not test a blank line (though your program should not crash on a blank line).

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. There are two ways to execute these commands in your shell: you can either use system(), or you can use fork(), exec(), wait().

While using system() does not have the risk of creating a fork bomb, your shell would fail to print out the correct PID (in Task 3) when executing a non built-in command.  Hence, with system(), you can receive only upto 75% of the total program execution score. In order to receive full credit, you must use fork(), exec(), wait().

When implementing the second option, your shell must  fork() a child process. The child process must execute the command with exec(), while the parent must wait() for the child to terminate before printing the next prompt. It is important to note that, upon a successful execution of the command, exec() never returns to the child process. exec() only returns to the child process when the command fails to execute successfully. In that case, shell should print (without the quotes):  "xxx: not found\n", where xxx is the command.

Failure to terminate the child process after an invalid command may result in a fork bomb. You can find information about cleaning a system after a fork bomb hereIf your code fork bombs during grading, the autograder will not be able to continue. This often results in the grader unable to record meaningful output from your program and will be a 0 if the autograder does not record output!

Some non built-in commands that you may try to see whether your Shell works as it should are: ls, /bin/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

Type "exit" to exit from Shell (or if this has not yet been implemented, Ctrl+C will work).

Grading, Submission and Other Details

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


Generated on 23 Sep 2013 for MP3: Shell by  doxygen 1.6.1