Unix Utility
Project Description
This project may be completed individually, or in groups of two. If you decide to work in a group, please first review the
group work policy in the syllabus. Only one member from the group should submit the project. Please do not have
oth members of the group submit the same project.
For this project, you are tasked with implementing a collection of basic Unix utilities using low-level system calls. Not all
utilities are the same di�culty. Please start early and manage your time wisely.
Hint: if you are ever unsure what the expected behaviors of your programs should be, then you should mimic the behaviors
of the co
esponding utilities programs on For example, your head program should work the same way as head
program when given the same options and arguments; but note that head program does support a lot more options
than what you will be required to implement.
Here is the list of utilities that you must implement. For head, tail, and wc, you may also assume that each of the input
files (including standard input) will be less than 1 MB in size. You should prioritize on getting regular text files working first
efore dealing with (the more di�cult) standard input. If standard input ends up not working on your head, tail, and wc
programs, then you will lost at most 5 points for each of the 3 program, for a maximum of 15 points.
1. ./head [ -c number | -n number] [files...]
./tail [ -c number | -n number] [files...]
(50 points) The head and tail utilities should copy their input files to the standard output, ending or starting the
output for each file at a designated point, respectively. Copying must end
egin at the point in each input file indicated
y the -c number or -n number option. The option-argument number is counted in units of lines or bytes, according
to the options -n and -c, respectively. Both line and byte counts start from 1. If no options are specified, act as if the
option -n 10 had been specified. If no files operand is specified, or when one of the files is -, then standard input
is assumed.
-n number: The first (head) or last (tail) number lines of each input file to be copied to standard output. The
application must ensure that the number option-argument is a positive decimal integer. When a file contains less
than number lines, it must be copied to standard output in its entirety. This should not be an e
or.
-c number: Output the first (head) or last (tail) number of bytes. A positive decimal integer as well.
2. ./wc [-clw] [files...]
(30 points) The wc utility should read one or more input files and, by default, write the number of newlines, words, and
ytes, in that order, contained in each input file to the standard output (in other words, the default behavior matches
having the options -clw). The utility should also write a total count for all named files, if more than one input file is
specified. The wc utility should consider a word to be a non-zero-length string of characters delimited by whitespace
characters (e.g., spaces, tabs, newlines, and a few others). Your program should be able to handle any combinations
of the -c, -l and -w options, in any order (e.g, ./wc or ./wc -wl -c or ./wc -l -w or ./wc -c, etc.). If no files
operand is specified, or when one of the files is -, then standard input is assumed.
-c: Write to the standard output the number of bytes in each input file.
-l: Write to the standard output the number of newlines in each input file.
-w: Write to the standard output the number of words in each input file.
Regarding the exact spacing and indentations between di↵erent numbers/counts of the output, your wc program does
not have to perfectly match the wc utility on (of course, all the numbers/counts should match).
1
3. ./true
./false
(10 points) The true utility shall return with exit code EXIT SUCCESS. The false utility shall return with exit code
EXIT FAILURE.
4. ./env
(10 points) The env utility prints all of the cu
ently set environmental variables to standard output.
Nonfunctional Requirements
Your submission needs to satisfy the following nonfunctional requirements:
Directory Setup: If you work individually, then make sure that all of your files are in a directory called
LastName-FirstName-p2, where LastName and FirstName are replaced with your actual last name and first name.
If you work in a group, then the directory should be named LastName1-FirstName1-LastName2-FirstName2-p2, so
that the names of both members of the group are there. For this project, the name of each source file and executable
should match the name of the utility program. For example, the source file of the head program should be contained
in head.c, which will generate an executable named head.
Li
aries: You are allowed to use any of the C standard li
aries, but with the following restrictions: When reading
or writing to a file are concerned, you need to use low-level calls to read(2) and write(2) and related functions. The
printf(3) function is acceptable when you need to display simple output messages to the screen. Whenever possible,
program output should be unbu↵ered. The write(2) system call is always unbu↵ered, but printf(3) requires the
use of setbuf(3) to turn o↵ the bu↵er. You are NOT allowed to use the following system calls in any of you
implementations: fork(2), execve(2), exec(3), popen(3), system(3) (and related functions). Failure to adhere
to this non-functional requirement will cause you to earn no points for the utility programs(s) in which
these fo
idden system calls/functions are used.
Documentations: Your code must be documented using Javadoc style comments. Use inline documentation, as
needed, to explain ambiguous or tricky parts of your code. A maximum of 5 points will be deducted for not including
appropriate documentations.
makefile: You need to include a makefile. The resulting executable names should match to the names of the utility
programs. The very first target in your makefile should produce executables for all the utility programs. Please also
include a “clean” target to remove any object code and executables. The expectation is that the grader should be able
to type make clean and make to clean and compile/link your submission, respectively. A maximum of 5 points will be
deducted for a bad/missing makefile.
Standards & Flags: Make sure that when you compile, you pass the following options to gcc:
-Wall -pedantic-e
ors
Other compile
linker options may be needed in addition to the ones mentioned above.
README File: Make sure to include a README file that includes the following information presented in a reasonably
formatted way:
– as well as your teammate’s info, if applicable.
– compile and run your program.
– Each group member’s detailed contributions to this project, if applicable.
A maximum of 5 points will be deducted for an README file that does not adhere to these standards.
Compiler Warnings: Since you should be compiling with both the -Wall and -pedantic-e
ors options, your code
is expected to compile without gcc issuing any warnings. Failure to adhere to this non-functional requirement will
esult in an automatic 5 point deduction.
Memory Leaks: Since this project may (or may not) make use of dynamic memory allocation, you are expected to
ensure that your project implementation does not result in any memory leaks. We will test for memory leaks using the
valgrind utility. Failure to adhere to this non-functional requirement will result in an automatic 5 point deduction.
2
Sample Input
Here are some examples on how your utility programs should be able to handle various options and arguments. The outputs
are not explicitly shown, but they should match the outputs of the co
esponding utility programs on You are also
strongly encouraged to look up the getopt(3) function and learn to use it to process the options and arguments.
./head file1.txt
./head file1.txt file2.txt
./head -n 5 file1.txt
./head -n 5 file1.txt file2.txt
./head -c 3 file1.txt
./head -c 3 file1.txt file2.txt
./tail file1.txt
./tail file1.txt file2.txt
./tail -n 5 file1.txt
./tail -n 5 file1.txt file2.txt
./tail -c 3 file1.txt
./tail -c 3 file1.txt file2.txt
./wc file1.txt
./wc file1.txt file2.txt
./wc -c file1.txt file2.txt
./wc -lc file1.txt file2.txt
./wc -cl file1.txt file2.txt
./wc -cwl file1.txt file2.txt
./wc -w -l file1.txt file2.txt
./wc -l -cw file1.txt file2.txt
./true
./false
./env
Here are some examples of taking in standard input. Remember, even if you could not get standard input to work, you will
only lose at most 5 points for each of the head, tail, and wc programs, for a maximum of 15 points.
./head
./tail -
./head -n 5
./tail -c 5 -
./head -n 5 file1.txt -
./tail -c 5 - file2.txt
./wc
./wc -
./wc -lw -
./wc -c -w file1.txt - file2.txt
3