CPSC 331 Operating Systems Spring 2026

Project 1
Unix Utilities

Due: Wed 2/4 at the start of class

This warmup project has several goals:

Your task is to implement versions of four command line utilities (cat, grep, zip, and unzip) largely as described in the project README, along with learning a bit about Makefiles. Feel free to go look over the README (along with this C lab tutorial) now, but don't start trying to figure out the code yet! Look through the rest of this handout first, then do the red-boxed steps in the Preliminaries and Specifications and Details sections (in that order). The combination of the README and this handout will provide a tutorial-style introduction to programming in C.

Collaboration and the Use of AI

Review the course policy on academic integrity.

Certain uses of AI are permitted on this assignment. AI use is not required.

The basic rule: you may use the code completion features of Copilot but may not use features (such as the coding agent) where code is generated from English language prompts. It is also essential that you understand and think critically about any code suggested by Copilot, both to help develop your C programming skills and because while the code suggestions are often uncannily on target, they are not always exactly what you want.

Using the code explanation features of Copilot Chat is permitted, though be careful that this doesn't spill over into code generation.

Other Policies

Review the policy on late work.

Revise and resubmit applies for this assignment. Review the details of how revise and resubmit works.

Handin

To hand in your project:

Check that the handin was successful and that the directory structure is correct: your handin folder /classes/cs331/handin/username should contain a folder initial-utilities which in turn contains a Makefile and subdirectories wcat, wgrep, wzip, wunzip. Each subdirectory should have a .c file of the same name, a Makefile, and, if you added any test cases, a subdirectory tests containing the appropriate files.


Preliminaries

Do the steps outlined in reddish boxes below before you start writing code.

Directory Structure

Provided Code

The initial-utilities directory contains test cases for each of the programs you will write. Run them from the command line: for the wcat tests, for example, change to the wcat directory (which should be ~/cs331/workspace/initial-utilities/wcat if you set things up as specified above), and run

    ./test-wcat.sh

Treat the provided tests as a backup check: practice your testing skills by first doing your own testing, then run the provided tests to see if you missed anything.

The tester directory contains scripts for running the provided tests along with a README that describes the setup for each test case. There's no need to do anything with the contents of this directory unless you want to define your own test cases.

Extra credit is possible if you find cases missed by the provided tests — see the README in the tester directory for information on how to define a test case and hand in the files for your new case(s) along with your code. Be sure to number your test cases starting one higher than the provided ones — don't modify or replace the provided test cases — and include a description of what the test case covers in the appropriate file.

VSCode

Systems programming usually doesn't require a full IDE, just a code editor with features like syntax highlighting and code completion. Editors like vi/vim and emacs are common in Unix/Linux environments and are useful to know, but they have steep learning curves. In this course, we'll use VSCode, which is much easier to learn but is still powerful and flexible enough for a broad range of programming tasks and languages.

To get auto-formatting support for C in VSCode, set up and configure the Microsoft C/C++ extension:

Additional recommended settings: (locate each by starting to type the setting name in the search box in the Settings tab)

The following settings are a matter of personal preference and are optional to set:

If you want to use Copilot (optional), install the GitHub Copilot extension:

Reference

System Calls, C, and Unix

For system calls, first look them up in the man pages. They are in section 3 — in many cases man whatever will give you the right version, but if not, use man 3 whatever.

For additional reference on system calls as well as C and Unix:

Both Dive Into Systems and C for Java Programmers have a table of contents which can help you locate the right section for something you are looking for. In addition, Dive Into Systems has a search box that you can use to locate specific terms throughout the whole book and you can use your web browser's search function (hamburger menu→Find in Page... or ctrl-F in Firefox) to search what's currently displayed.

Failed Tests / About diff

The provided tests are largely self-documenting. For example, you might see the following:

test 1: passed
test 2: passed
test 3: 3.out incorrect
  what results should be found in file: tests/3.out
  what results produced by your program: tests-out/3.out
  compare the two using diff, cmp, or related tools to debug, e.g.:
  prompt> diff tests/3.out tests-out/3.out
  See tests/3.run for what is being run

To see what went wrong, you should compare the two files tests/3.out (the correct result) and tests-out/3.out (what your program actually output). You can view the files by opening them in VSCode or by using cat in the terminal:

  cat tests/3.out
  cat tests-out/3.out

You can also directly compare them line-by-line using diff as indicated:

  diff tests/3.out tests-out/3.out

Normal diff output shows only the lines that differ and indicates which file they came from. For example:

  1c1
  < Usage: wgrep <searchterm> [<file> ...]
  ---
  > Usage: wgrep <searchterm> <file> ...

< indicates lines present only in the first file and > indicates lines present only in the second file. (In this case we can see that the problem is that the usage message isn't formatted correctly — the [] is missing.) If the files match exactly, diff produces no output.

For longer files, a context diff or side-by-side diff can be useful. There are also more flexible comparisons, such as comparisons which ignore whitespace. As with any command, look up diff in the man pages for more information.


Specifications and Details

Your task is to implement versions of four command line utilities (cat, grep, zip, and unzip) largely as described in the project README, along with learning a bit about Makefiles.

To do this:

wcat

Additional or modified specifications:

Hints/suggestions:

wgrep

Additional or modified specifications:

Hints/suggestions:

wzip

Additional or modified specifications:

Hints/suggestions:

wunzip

Additional or modified specifications:

Hints/suggestions:

Makefiles

Makefiles can look cryptic, but they are powerful tools for automating and simplifying the build process — you specify how a program is compiled once and can then rebuild only what's necessary with a single command, saving time and reducing errors. In addition to building programs, Makefiles often define other useful targets like make clean to remove generated files and make test to run test suites, helping to streamline common development tasks.

In practice, Makefiles are rarely written from scratch. Instead, a generic Makefile is adapted for a new project. As a result, the focus here is on developing a reading knowledge of a basic Makefile pattern and learning how to adapt it rather than on building Makefiles from the ground up.

A Makefile for wcat has been provided in the initial-utilities/wcat directory.

It can be convenient to apply the same operation to all four of wcat, wgrep, wzip, and wunzip with one command. This can also be done with a Makefile.