CS 134

Making Our Own Shell

In this part, you are allowed to use functions from the C standard library, such as printf, malloc, free, strlen, strtok, and strerror.

Writing vbsh (Very Basic Shell)

A shell is an interactive command-line interpreter that runs programs on behalf of the user. A shell repeatedly prints a prompt (in our case vbsh>), waits for a command line on standard input, and then carries out some action, as directed by the contents of the command line.

The command line is a sequence of ASCII text words delimited by whitespace. The first word in the command line is either the name of a built-in command or the pathname of an executable file. The remaining words are command-line arguments.

If the first word is a built-in command, the shell immediately executes the command in the current process. Otherwise, the word is assumed to be the pathname of an executable program, and the shell forks a child process, then loads and runs the specified program in the context of the child.

Typing the command line

vbsh> /bin/ls -l -d

runs the ls program in the foreground.

Background on Command Line Arguments

When a program is run from the command line, the shell passes the program a list of arguments. By convention, the shell ensures that when the program begins executing its main routine,

int main(int argc, const char **argv);

the argc parameter is a count of the number of arguments, and argv (which can also equivalently be declared as const char *argv[]) is an array of pointers to the arguments. The first argument, argv[0], is the name of the program being run. The last argument, argv[argc], is a null pointer to indicate the end of the arguments.

Thus, in this case argc and argv arguments have the following values:

argc 3
argv[0] /bin/ls
argv[1] -l
argv[2] -d
argv[3] NULL

C Strings

Remember also that C-style strings are NUL-terminated, and in memory look like this.

H e l l o \0
0 1 2 3 4 5

You can find more about C strings in the C Strings Help Page.

Provided Code

We have already provided some code in vbsh.c to get you started. As provided, the shell supports

  • Running the (built-in) exit command to exit the shell (with no status information).
  • Running external commands.
    • Scans the provided command line to break it into words so that each word can be passed as an argument to the program being run.
    • Uses the execvp function to run the program. execvp is a library wrapper around the execve system call that searches the directories in the PATH environment variable for the program to run. Thus we can actually just type ls instead of /bin/ls to run the ls program.

Your Task

You will need to add the following features:

  • Running the following built-in commands: chdir.
    • Ideally, write a generic mechanism to support built-in commands. You can look at the code in menu.c from OS/161 for inspiration. If you use this approach, it would be easy to make cd an alias for chdir (not required, but it would be a nice touch).
  • Reporting the exit status of a command if it is not zero.
  • Simple background execution (described below).
  • Providing I/O redirection for external commands. For our purposes, each I/O redirection specification is a single argument of the form <file or >file (i.e., no spaces), where each kind of I/O redirection is specified, at most, once.

Status Reporting

If an external program exists with non-zero exit status, your shell should display that status in the form Exit code: n, where n is the exit status.

Background Execution

A user can ask a program to be run in the background by appending a trailing & as the final word on the command line. If the user specifies no input redirection, your shell should close standard input for the command. When a background task is initiated, the shell should print PID p started., where p is the process id, and then continue to read further commands from the user as normal. Just before printing the prompt, the shell should check to see if any background tasks have completed and, if so, print PID p completed, exit code n. for each one.

Sample Session

vbsh> /bin/true
vbsh> /bin/false
Exit code: 1
vbsh> mkdir testdir
vbsh> chdir testdir
vbsh> ls -l
total 0
vbsh> echo Wow >wow.txt
vbsh> ls -l
total 4
-rw-r--r-- 1 melissa melissa 4 Sep  2 15:46 wow.txt
vbsh> cat <wow.txt
Wow
vbsh> sleep 5 &
PID 576474 started.
vbsh> echo lets wait
lets wait
vbsh> echo is it done?
is it done?
PID 576474 completed, exit code 0.

Notice that while chdir is a built-in command, mkdir is an external program. Some shells include their own built-in versions of commands provided by the OS (which might behave differently than the OS's version).

See man builtin for some examples.

You do not need to support:

  • Quoting for arguments to external commands
  • Glob expansion (e.g., ls *.c)
  • Spaces after redirection symbols (e.g., > file is not supported)
  • No space between the command and the & for background execution (e.g., sleep 5& is not supported)
  • Pipes
  • Signals
  • Line editing and command history
  • Job control (e.g., killing background tasks)
  • Environment variables (e.g., echo $PATH)
  • Command substitution (e.g., echo $(ls))
  • Arguments to the shell command itself (it needs none)

If you would like to go further with your shell, speak to me about extra-credit possibilities.

Finally, remember the course policies on collaboration and academic integrity. You may discuss the assignment with others, but you must write your own code. As always, you may not use a large language model (e.g., ChatGPT or GitHub Copilot) to generate code for you.

If you do look at other code sources (e.g., looking at OS/161 code or Stack Overflow), you should not copy them verbatim into your code. Instead, you should understand the code you are looking at and then write your own code from scratch. If you do look at other code sources, you must wait a few minutes after looking at it before you work on your own code to avoid any risk of accidentally using your short-term memory and thus repeating code or concepts by rote.

To Complete This Part of the Assignment…

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)