Assignment 02: Trust the Process (Part 1)
Due Sunday, Feb 2, before midnight
The goals for this assignment are:
-
Working with stdout, stdin, and files
-
Understanding redirection and pipes at the command line
-
Working with system calls: read, write, open, fork, exec, wait
-
C practice/review
Get the starter code here |
1. Microcat
By Dianna Xu
In the file, microcat.c
, implement a C program that concatenates and prints files
to standard output. If no arguments are given, it takes input from stdin.
$ ./microcat lyrics.txt
What a beautiful face
I have found in this place
That is circling all round the sun
What a beautiful dream
That could flash on the screen
In a blink of an eye and be gone from me
Soft and sweet
Let me hold it close and keep it here with me
$ cat lyrics.txt | ./microcat
What a beautiful face
I have found in this place
That is circling all round the sun
What a beautiful dream
That could flash on the screen
In a blink of an eye and be gone from me
Soft and sweet
Let me hold it close and keep it here with me
$ ./microcat < lyrics.txt
What a beautiful face
I have found in this place
That is circling all round the sun
What a beautiful dream
That could flash on the screen
In a blink of an eye and be gone from me
Soft and sweet
Let me hold it close and keep it here with me
$ ./microcat
hello
hello
nice hat
nice hat
$ ./microcat B.txt A.txt C.txt D.txt
World
Hello
!!!
All life is precious
Requirements/Hints:
-
This is basically the Unix
cat
command with no flags. -
When working with the standard input and standard output streams, either use the defined file descriptors (e.g.
STDOUT_FILENO
,STDIN_FILENO
), or defined file pointers (e.g.stdin
,stdout
), with eitherread
orfread
. -
Your program should use the system calls, read, write, and open.
-
Ctrl-d will quit your application when reading from stdin
2. Parser
This question is from this lab. |
In the file, parser.c
, implement a function that parses command line input.
This function should fill in a struct Cmd
that holds the information needed to execute. Your struct should look as follows.
struct Cmd {
char **cmd1_argv;
char **cmd2_argv;
char *cmd1_fds[3];
char *cmd2_fds[3];
}
Sample output from your program should look as follows:
Plain command: ls -l
cmd1_args: ["ls", "-l", NULL] /* three-element dynamically-allocated array */
cmd2_args: NULL /* There is no second command here. */
cmd1_fds[0]: NULL /* With no I/O redirects, all descriptors are NULL */
cmd1_fds[1]: NULL
cmd1_fds[2]: NULL
cmd2_fds[0]: NULL
cmd2_fds[1]: NULL
cmd2_fds[2]: NULL
Pipe only command: ls | sort
cmd1_args: ["ls", NULL] /* two-element dynamically-allocated array containing */
cmd2_args: ["sort", NULL] /* two-element dynamically-allocated array containing */
cmd1_fds[0]: NULL /* With no I/O redirects, all descriptors are NULL */
cmd1_fds[1]: NULL
cmd1_fds[2]: NULL
cmd2_fds[0]: NULL
cmd2_fds[1]: NULL
cmd2_fds[2]: NULL
Redirects only: ls -l 1> out.txt 2> error.txt
cmd1_args: ["ls", "-l", NULL] /* three-element dynamically-allocated array */
cmd2_args: NULL /* There is no second command here. */
cmd1_fds[0]: NULL
cmd1_fds[1]: "out.txt"
cmd1_fds[2]: "error.txt"
cmd2_fds[0]: NULL /* There is no second command here. */
cmd2_fds[1]: NULL
cmd2_fds[2]: NULL
Combined: grep -i blah < input.txt | sort 1> output.txt
cmd1_args: ["grep", "-i", "blah", NULL] /* four-element dynamically-allocated array */
cmd2_args: ["sort", NULL] /* two-element dynamically-allocated array containing */
cmd1_fds[0]: "input.txt"
cmd1_fds[1]: NULL
cmd1_fds[2]: NULL
cmd2_fds[0]: NULL
cmd2_fds[1]: "output.txt"
cmd2_fds[2]: NULL
Requirements/Hints:
-
Use only C commands, such as malloc/free, for this program
-
The comments above are to help you understand what memory you should allocate. Don’t print the information in the comments.
-
Make sure you have no memory errors!
-
You can extend the above struct if you like, but don’t change the given data types!
-
You can assume that you will have at most one pipe
-
Note that the 2> error.txt, |, and & portions of the command are instructions to the shell and are NOT command ARGV tokens.
-
To simplify parsing, you may assume that nothing other than white space (spaces, newlines, etc.) will appear after an ampersand (&), there will be at most one ampersand, and that ampersands will not appear for any reason other than to specify background tasks.
3. Simple Shell
In the file, shell.c
, write a program that implements a simple shell.

Requirements:
-
Your program should print a prompt. At minimum, your prompt should show the current working directory and look distinct from the lab machine prompts. In other words, it should be easy to tell what shell if running from the terminal.
-
Use the
readline()
function to get user input. This function supports backspace, tab completion, and more. Documentation for readline can be found here. -
Use the
add_history()
function to save user history. This will allow arrow keys to work. Documentation for readline can be found here. -
Your program should quit if the users types
exit
. -
When the user gives a command, split it into a command and arguments using execvpand then fork a command to execute it.
-
Compiles with
make
. (Do not modify the Makefile) -
No memory errors using
valgrind
-
Adheres to the style guidelines and includes a header comment
-
Your terminal should wait for the command to finish. If the command terminates with an error, report the error.
readline is a package that is installed on goldengate and in our labs. However, you may need to install it on your own machine. On Unix systems, this can be done by running sudo apt install libreadline-dev
|
You can print with colors to the console using ANSI escape sequences (see below).
For example, printf(ANSI_COLOR_GREEN "Green Text" ANSI_COLOR_RESET); will print green text. Here is a good guide!
|
// Helpful macros for working with color #define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_YELLOW "\x1b[33m" #define ANSI_COLOR_BLUE "\x1b[34m" #define ANSI_COLOR_MAGENTA "\x1b[35m" #define ANSI_COLOR_CYAN "\x1b[36m" #define ANSI_COLOR_RESET "\x1b[0m"
Most prompts print helpful information. Above, we use the
system commands gethostname , getcwd , and getpwuid(geteuid()) to get the
machine name, the current working directory, and current user respectively.
|
To check for valgrind errors, run valgrind with your executable as an argument |
Submit your work to Github
Add and check in your program using git and then push your changes to Github.
Run the following command inside your shell-USERNAME
directory.
$ cd shell-USERNAME
$ git add .
$ git commit -m "Descriptive message"
$ git push
Run git status
to check the result of the previous git command.
Check the Github website to make sure that your program uploaded correctly.
4. Grading Rubric
Assignment rubrics
Grades are out of 4 points.
-
(1 points) Microcat
-
(1.5 points) Parser
-
(0.1 points) style and header comment
-
(0.65) Correct behavior: parses line and fills in struct Cmd
-
(0.75) no memory errors
-
-
(1.5 points) Simple shell
-
(0.1 points) style and header comment
-
(0.25 points) Displays unique prompt with current working directory
-
(0.1 points) Uses
readline()
andadd_history()
-
(0.1 points) Quits when the user types
exit
. -
(0.1 points) Forks a process to run the user’s command.
-
(0.1 points) Reports the return status of the command when the child process completes.
-
(0.75 points) no memory errors.
-
When using readline() , valgrind will report that some of your memory is
still reachable. This memory is not leaked. It hasn’t been cleaned up yet from
`readline()’s internal memory. For example, output such as the following is ok
|
==3504== HEAP SUMMARY: ==3504== in use at exit: 204,143 bytes in 221 blocks ==3504== total heap usage: 453 allocs, 232 frees, 244,790 bytes allocated ==3504== ==3504== LEAK SUMMARY: ==3504== definitely lost: 0 bytes in 0 blocks ==3504== indirectly lost: 0 bytes in 0 blocks ==3504== possibly lost: 0 bytes in 0 blocks ==3504== still reachable: 204,143 bytes in 221 blocks ==3504== suppressed: 0 bytes in 0 blocks
Code rubrics
For full credit, your C programs must be feature-complete, robust (e.g. run without memory errors or crashing) and have good style.
-
Some credit lost for missing features or bugs, depending on severity of error
-
-12.5% for style errors. See the class coding style here.
-
-50% for memory errors
-
-100% for failure to checkin work to Github
-
-100% for failure to compile on linux using make