Purpose of Assignment

The goal of this assignment is to get everyone up to speed on system programming and to become familiar with the system call interface. A secondary goal is to use some of the programming tools provided in the Unix/Linux environment. In this assignment you are to implement a Unix/Linux shell program. A shell is simply a program that conveniently allows you to run other programs. Read up on your favorite shell to see what it does. You may work by yourself or with one partner.

The Details

Your shell must support the following:

1. The internal shell command "exit" which terminates the shell.
Concepts: shell commands, exiting the shell
System calls: exit()

2. A command with no arguments
Example: ls
Details: Your shell must block until the command completes and, if the return code is abnormal, print out a message to that effect.
Concepts: Forking a child process, waiting for it to complete, synchronous execution
System calls: fork(), execvp(), exit(), wait()

Your solution must also support the following:

1. A command with arguments
Example: ls -l
Details: Argument 0 is the name of the command
Concepts: Command-line parameters

2. A command, with or without arguments, executed in the background using &.
For simplicity, assume that if present the & is always the last thing on the line.
Example: xemacs &
Details: In this case, your shell must execute the command and return immediately, not blocking until the command finishes.
Concepts: Background execution, signals, signal handlers, processes, asynchronous execution
System calls: sigset()

3. A command, with or without arguments, whose output is redirected to a file
Example: ls -l > foo
Details: This takes the output of the command and put it in the named file
Concepts: File operations, output redirection
System calls: freopen()

4. A command, with or without arguments, whose input is redirected from a file
Example: sort < testfile
Details: This takes the named file as input to the command
Concepts: Input redirection, more file operations
System calls: freopen()

5. A command, with or without arguments, whose output is piped to the input of another command.
Example: ls -l | more
Details: This takes the output of the first command and makes it the input to the second command
Concepts: Pipes, synchronous operation
System calls: pipe()

Note: You must check and correctly handle all return values. This means that you need to read the man pages for each function to figure out what the possible return values are, what errors they indicate, and what you must do when you get that error.

Hints

1. You will need to make use of system calls such as execvp(), fork(), pipe(), wait() and dup2().

2. Assume the user enters "ls -lt | sort | more". Your shell would create a process for each command. A pipe must be created (using the pipe command) between the first and second process and the second and third process. Creating a pipeline between two processes is relatively simple (you have sample code for this), but the building of a multiple command pipeline is more difficult.

3. You may use any of the system calls found in the exec() family. If you use execvp, remember that the first argument in the array is the name of the command itself, and the last argument must be a null pointer.

4. A shell needs a command-line parser. The parser breaks down the string representing the command into constituent parts. These parts are referred to as tokens. To read a line from the user, you may use gets(). The parser you implement may use scanf(), strtok() or any other suitable C library functions. Parsing requires these steps:

  • Read a line from standard input. You may use the gets() system call.
  • A token is a sequence of non-whitespace characters that is separated from other tokens by whitespace characters. For each command line, you should form an array of tokens. This can be done using the strtok() system call. Example code is provided that takes a string and provides the tokens in an array.
  • You should determine commands by analyzing the array created in the previous step. Any tokens between pipe signs are considered to be part of the same command.

5. Develop your code in incremental stages. One order of stages is the following:

  • Write a shell that can fork single program invocations (with no arguments) and wait for their completion.
  • Develop the command line parser.
  • Extend the shell developed earlier to be able to handle arguments.

6. Add support for pipes

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.