The learning objectives for Utilities Unleashed are:
- Fork, Exec, Wait
- Environment Variables
- Writing a C Program
- Using argv, argc
- Introduction to core utils
In this lab, you will be implementing the following C utilities:
- Do not worry about flags or features that we do not mention.
- Do not print any of your debug information out for your final submission.
- All printing (except env vars) should be handled with
- A common issue is double printouts. If this happens to you, try flushing stdout before you fork/exec. If this solves your issue, ask yourself why.
format.c and .h#
Since this lab requires your programs to print messages to
stderr, we have provided you with
format.h. You should not be printing out to stdout and stderr at all. Instead, you should be using the provided functions. You can find documentation for each function in
format.h. Please read the documentation in
format.h multiple times to determine when each function should be used. This is our way of ensuring that you do not lose points for formatting issues, but it also means that you are responsible for handling any errors mentioned in
It is common for students to fail certain test cases on this assignment with seemingly functional code, it is almost always because of improper usage of
In this lab, you will be implementing
time – run a program and report how long it took
So if a user enters:
./time sleep 2
then time will run
sleep with the argument
2 and print how long it took in seconds:
sleep 2 took 2.002345 seconds
For more examples, you can play with Linux’s builtin
time command by typing
time YOURCOMMAND (
time ls -l, for example) in your terminal. Be sure to add
./ to the beginning (or use the full path to your
time executable file if you are in another directory), otherwise the builtin
time will be called.
We’ve also provided a test executable to run basic tests on your time implementation. Note that although these tests are similar to those that will be run on the autograder they are not identical, so passing locally does not guarantee you will receive full credit. It is still your responsibility to ensure you have functional code.
Pro tip: 1 second == 1,000,000,000 nanoseconds.
- You may not use the existing
- You must use
wait(no other solutions will be accepted).
- If the child process does not terminate successfully (where its exit status is non-zero), you should exit with status 1 without printing the time.
- We will only run
timewith one program.
- The commands we will run can take any number of arguments.
- Do your time computations with double-precision floating pointer numbers (
double) rather that single-precision (
- We have provided functions in
format.hthat we expect you to use wherever appropriate.
In this lab, you will be implementing a special version of
env – run a program in modified environments
./env [key=val1] [key2=val1] ... -- cmd [args] ..
Please re-read this section multiple times before starting:
- Each variable is in the form of
NAME=v1, separated by spaces.
- Values may contain references to environment variables in the form
%NAME, including variables that were set earlier. As a result, variables should be processed from left to right.
- Each reference should be replaced with its value.
- The names of variables (both in
value) only contain letters, numbers, or underscore characters.
- For each environment variable
keyin the child environment.
- Each execution must be done with
- The last variable/value(s) pairing is followed by a
Everything following the
--is the command and any arguments that will be executed by env.
- Invalid input should result in the usage being printed. It is your job to enforce correct usage! You shouldn’t ignore bad usage.
This is the canonical example and a practical use case:
$ ./env TZ=EST5EDT -- date Sat Sep 9 19:19:42 EDT 2017 $
Example of using references to other variables:
$ ./env TEMP=EST5EDT TZ=%TEMP -- date Sat Sep 9 19:19:42 EDT 2017 $
This has the exact same behavior as before, because
TEMP is first set to
EST5EDT, and then when
TZ is set to
%TEMP, the value of
EST5EDT is retrieved and then
TZ is set to that. Notice that the variables are set sequentially, or else it wouldn’t work.
time, you can play with Linux’s builtin
env command by typing
env <var-list> <command-name> (
env MYVAR=CS241 printenv, for example) in your terminal. Again, remember to add
./ to the beginning (or the full path to your
env executable file if you are in another directory), otherwise the builtin
env will be called. Do not use the built-in env, or you will immediately fail the assignment
In addition, keep in mind that the builtin
$ instead of
% to denote environment variables. In practice, it can be very useful to change some environment variables when running certain commands.
Extra: Why Env?
For example, you may notice people write
#!/usr/bin/env python on the first line of their Python script. This line ensures the Python interpreter used is the first one on user’s environment
$PATH. However, users may want to use another version of Python, and it may not be the first one on
$PATH. Say, your desired location is
/usr/local/bin for instance.
One way to solve this is by exporting
$PATH to the correct position in your terminal, however, this may mess up other commands or executable under the same session.
An alternative and better way is to use our
env, and enter:
./env PATH=/usr/local/bin -- ./XXX.py
then it runs the script with the desired Python interpreter.
- You may not use the existing
envprogram. (Our specification is different than the existing
- You may not replace
- You may not use
- All changes in environment variables and execution must happen only in the child process.
- You must use
- If a variable doesn’t exist, interpret its value as a zero-length string.
- Do not fork bomb the autograder! You will fail if you forkbomb the AG. (See the warning.)