In class we saw how to use fork()
, execvp()
, and waitpid()
so that a command can be executed in a child process, and then control can return to the parent when the child has terminated.
In this assignment you will extend this example by writing a simple shell.
The most basic functionality of an interactive shell, such as bash
, is to prompt the user to enter a command, execute the command the user enters, and repeat. Most shells have more functionality as well, such as pipes and scripting language constructs, but we will only implement the most basic functionality ourselves in C.
For full credit, make sure you follow all of these requirements:
"> "
is fine. Print your prompt to stderr
. See the examples section for more on stderr
.execvp()
is successful, then the child process is replaced with the new executable and the exit status of the child is whatever the exit status of the called program is. If execvp()
fails, the child must print a “command not found” error to stderr
and return a non-zero exit status.waitpid()
. Once the child terminates, the parent must print a message to stderr
indicating the exit status of the child. The parent process must then print the prompt again to stderr
argv
array that is passed to execvp()
. Do not worry about handling backslash-escaped spaces and quoted strings, that is beyond the scope of this assignment.getline()
to return -1 (see below)See the class code section of the class site for exec.c
, the example code from class.
When using printf()
, output goes to standard output, or stdout
. There is another output stream available called standard error, or stderr
. This stream is used for printing errors, warnings, or any other informative things that are not part of the program’s main output. I have asked you to print everything that the shell prints out to stderr
, which you can do using fprintf()
and passing it the special stderr
file descriptor. Conversion characters sequences like %d
work the same with fprintf()
as they do for printf()
. Here is a simple example:
"Hello, error world!\n"); fprintf(stderr,
You can use getline()
to get the command from the user. There is a tutorial here and you can read the detailed manual by running man getline
in a terminal (when reading a manual page with man
you can scroll up and down with the arrow keys, and then quit by pressing q
). Be sure to look at the example in the tutorial. Probably the trickiest part is that you need to pass getline()
a pointer to a malloc()
allocated string. This is a pointer to a pointer, so it has type char **
. You need to allocate initial memory for the string using malloc()
, but it does not really matter how many bytes it is because getline()
will re-allocate a larger string if needed.
There are many ways that you can get the space-delimited arguments from the string that the user enters. One way is to simply loop over the characters, copying each character into the current argument array element, and then moving to the next array element when you encounter a space. You can use also use strtok()
. Here is a strtok()
tutorial. If you use strtok()
, be sure to replace the \n
in the user’s command with a \0
right off the bat. strchr()
can be used to get a pointer to the first occurrence of a character in a string. These functions also have man pages.
Below is an example run. On the first line I am running the shell program that I wrote, which is named simple_shell
. The following lines are now interacting with my simple shell instead of with bash
. The command ls
is executed three times. Once without any additional arguments, once with the -l
argument which causes more detailed output, and once with a filename that does not exist which causes a non-zero exit condition.
$ ./simple_shell
> ls
simple_shell simple_shell.c
command exited with a status of 0
> ls -l
total 24
-rwxr-xr-x 1 nws nws 17136 Sep 6 14:11 simple_shell
-rw-r--r-- 1 nws nws 981 Sep 6 14:09 simple_shell.c
command exited with a status of 0
> ls this_file_does_not_exist.txt
ls: cannot access 'this_file_does_not_exist.txt': No such file or directory
command exited with a status of 2
Make sure you test your shell with some other commands. Try cat simple_shell.c
to print out the contents of simple_shell.c
. Make sure you try commands with more than 2 arguments as well.
Write your program in the provided simple_shell.c
and push back to git-keeper. I will grade the assignment manually.