pipeline is complete. This page builds it, runs the tester, and looks
at what the kernel actually does during a pipeline execution.
Final build
make reExpected output: thirty-one libtci objects, ten libtciutil objects
(one split, nine list functions), three pipeline objects. Two ar lines,
one linker line. No warnings.
If any warning appears, fix it before running the tester. -Wextra
catches unused parameters, missing returns, and sign mismatches — all of
which indicate logic errors that will surface under test.
Run the tester
Clone the companion repo and copy test.sh into your working directory:
git clone https://github.com/thecodingidiot-com/c05-the-pipeline.git
cp c05-the-pipeline/test.sh ~/c05-practice/
cd ~/c05-practice
bash test.shThe tester uses bash -c as an oracle. For each test case, it runs the
same pipeline through the shell and through your pipeline binary, then
diffs the output. A passing test prints PASS; a failing test prints the
diff.
Test categories, in order:
- Single command —
./pipeline infile "cat" outfileagainst< infile cat > outfile. Verifies infile and outfile redirects. - Two commands —
cat | wc -l,sort | uniq. Verifies the pipe between two commands. - Three-command chain —
cat | sort | uniq. Verifies that the generalised loop handles N > 2. - Heredoc — LIMITER form with
cat | wc -l. Verifies that heredoc input reaches cmd1's stdin. - Error cases:
- Bad infile:
./pipeline missing_file "cat" outexits non-zero and produces no output. - Bad outfile:
./pipeline infile "cat" /no/such/dir/outexits non-zero. - Command not found: exit code is 127.
- Bad infile:
- Exit status — the exit code of the last command in the chain is
the exit code of
./pipeline.
All six categories must pass before the chapter is complete.
Inspect with strace
strace logs every system call made by a process. Run the two-command
pipeline under strace to see exactly what happens:
echo "hello" > in.txt
strace -f ./pipeline in.txt "cat" "wc -l" out.txt 2>&1 | head -60-f follows forked children. The output is noisy, but search for the
key calls:
strace -f ./pipeline in.txt "cat" "wc -l" out.txt 2>&1 | grep -E "^(pipe|fork|dup2|execve|openat|waitpid)"You will see:
pipe([3, 4])— the kernel creates the pipe and assigns file descriptors 3 and 4clone(...)— the kernel's implementation offork(same effect)dup2(5, 0)anddup2(4, 1)— file descriptors routed before execexecve("/bin/cat", ...)— the image replacementwait4(...)— the parent collecting the child's exit status
The system calls are exactly what the chapter built, in the order the
code specifies them. strace makes the sequence visible.
The libtciutil list functions
The list functions built in pages 01 and 02 are exercised throughout
pipeline. The tester indirectly verifies them — a broken tciu_lstnew
or tciu_lstclear would cause the binary to crash or leak. If you want
to verify the list functions directly, use the manual test from page 01
before running the full tester.
The list will be used again in every subsequent chapter that needs to manage a collection of unknown length: the shell's command table in c06, the thread pool in c08. What you built here carries forward.
The companion repo
The full reference solution is at github.com/thecodingidiot-com/c05-the-pipeline.
c05-the-pipeline/
├── solution/
│ ├── main.c
│ ├── exec.c
│ ├── pipeline.c
│ └── Makefile
└── test.shThe solution/ directory contains all source files. The Makefile in
solution/ builds libtci and libtciutil in-tree, then links the
pipeline binary. test.sh at the root is what bash test.sh runs.