Assignment 1: Shell

Please submit a single tar file.

What is a Shell?

A shell is a command interpreter. It uses system calls to start and stop programs and to direct their output into files. A single OS can have any number of shells; each user that can log into a system via telnet or ssh generally has one default shell. In Linux, FreeBSD and MacOSX, common examples are bash, csh and ksh. The DOS prompt and the Windows command-line interface are other examples.

Assignment Overview

Your assignment is to write your own shell to replace the standard shell in your host system. This assignment will let you get familiar with C programming in Unix-like system, as well as the basic concepts and structure of this important user interface of Unix-like systems.

This is a regular C program, not a kernel modification. It should be runnable and testable in a Unix-like system, i.e., Linux in this class.

The shell consists of a main() function that continuously reads lines from stdin, parses the line into space-separated words and executes the command, giving user feedback. The parser may use scanf(), strtok() or other suitable C library functions.

The shell or Command Line Interpreter (CLI) that is your environment when you logon to Unix-like system, a completely compatible version and subset of the Berkeley UNIX C shell, csh. It is a command language interpreter usable both as an interactive login shell and a shell script command processor.

Your shell should be able to accept commands, analyze them, interpret and execute a set of shell-defined commands, as described below.

Your shell should give reasonable output and feedback to the user, such as producing an error message when an executable cannot be found or cannot be accessed.

For all programs except ls and cd, use the exec() system call, or one of its variants, such as execve(). Use of a function that executes a shell process, such as system() or popen(), is not permitted for this assignment, including for cd and ls. You cannot use a shell process such as exec("/bin/sh -c command").

Useful system calls include exec(), fork(), readdir(), setenv(), getenv(). For details, see the unix man pages of these function calls.

You should use the getopt library call to process command line arguments.

cd

The cd command in standard shell in to change the directory. Your shell should be able to accept the command and the following arguments:

cd Back to the home directory of current user
cd .. Back to the parent directory
cd path change to the specified path directory

The getcwd and chdir() functions are relevant here.

ls

The ls command in a standard shell lists files in the current working directory. You only have to implement the following subset of its functionality. You should model the output on that of the standard Linux shell commands. (Note that Linux uses /bin/ls, rather than a shell built-in function.)

ls list all regular files
ls -a list all files in this directory, including hidden files (those starting with a .) and system files (devices, links)
ls -l list files with details

Your shell should be able to interprete the compound parameters, like ls -al.

Use readdir() for implementing ls. You do not have to support putting ls in the background.

Prompt

In your shell, the prompt should tell the user where they are, i.e., the current working directory, as in
/home/foo/bar $

Redirecting output

There are three file descriptors, stdin, stdout and stderr (std = standard). For this assignment, you will only implement output redirection, using the > symbol, so that stdout and stderr are redirected to a file instead of the terminal.

Here, a file called 'ls-l.txt' will be created and it will contain what you would see on the screen if you type the command ls -l and execute it.

  ls -l > ls-l.txt 

You will find the dup2() system call of interest. The basic outline is

  fd = open new descriptor for output file
  new descriptor = dup2(fd, 1);
  close(fd);

Running an executable file

An important function of the shell is running executable files. Your shell should be able to run the executable file in the current working directory as well as those in the system working path ($PATH).

The fork() system call allows you to create another process and the run, using exec(), the command entered by the user on the command line. Depending on whether you wait for the completion, the process either runs in the foreground or background.

Foreground

Normally, the user runs the program in the foreground, which means it will block the shell to run the program. The shell will not be able to accept another command until the running program has finished.

./program [parameters]

Unix allows you to wait for a process using the wait() and waitpid() system calls.

Background

If a user wants to execute a second command while another program is running, the first program needs to run in the background.

You may have to create data structures like an array or linked list to store information about the processes started by your shell, so that the jobs and fg commands can obtain the correct process number.

On your shell command line, a trailing & indicates that the shell will be running this program in the background and assign a numeric job ID as feedback to user.

./program [parameters] &

List the background jobs and bring them to foreground (jobs, fg)

Your shell should be able to carry out the command jobs, which will list the jobs that is running in the background, and give the information of the program including its name and assigned id when you run them in background. The output should be similar to the following:
[1] program1 
[2] pragram2  

Your shell should also be able to bring background jobs to the foreground status by fg [id]. The command will bring the background job with id to the foreground, and at meantime, your shell should be block and cannot take another command.

To be Handed In


Last updated by Henning Schulzrinne