thecodingidiot.com

The PipelineShip It

Ship It

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 re

Expected 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.sh

The 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:

  1. Single command./pipeline infile "cat" outfile against < infile cat > outfile. Verifies infile and outfile redirects.
  2. Two commandscat | wc -l, sort | uniq. Verifies the pipe between two commands.
  3. Three-command chaincat | sort | uniq. Verifies that the generalised loop handles N > 2.
  4. Heredoc — LIMITER form with cat | wc -l. Verifies that heredoc input reaches cmd1's stdin.
  5. Error cases:
    • Bad infile: ./pipeline missing_file "cat" out exits non-zero and produces no output.
    • Bad outfile: ./pipeline infile "cat" /no/such/dir/out exits non-zero.
    • Command not found: exit code is 127.
  6. 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 4
  • clone(...) — the kernel's implementation of fork (same effect)
  • dup2(5, 0) and dup2(4, 1) — file descriptors routed before exec
  • execve("/bin/cat", ...) — the image replacement
  • wait4(...) — 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.sh

The 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.

up next

Who Wants to Be a Game Developer? Acoustic

Who Wants to Be a Game Developer? Acoustic