linux-sysprog · intermediate · ~20 min

Parse a `/etc/passwd`-style line

Hand-written colon-delimited parser without `strtok` (which has shared state).

Challenge

Implement int parse_passwd_line(const char *line, char *user, size_t user_cap, int *uid, char *home, size_t home_cap).

The line format is:

username:x:uid:gid:gecos:home:shell

Extract:

  • user (field 0) — copy to user, NUL-terminated, capped at user_cap-1.
  • uid (field 2) — parse as int into *uid.
  • home (field 5) — copy to home, NUL-terminated, capped at home_cap-1.

Return:

  • 0 on success.
  • -1 if any required field is missing, parsing fails, or any buffer is too small to hold its field.

Examples

parse_passwd_line("alice:x:1000:1000:Alice:/home/alice:/bin/bash",
                  user, 32, &uid, home, 64)
   -> 0, user="alice", uid=1000, home="/home/alice"

parse_passwd_line("incomplete:x:1", ...) -> -1
parse_passwd_line("alice:x:abc:1000:Alice:/home:/sh", ...) -> -1   // non-numeric uid

Why this matters

/etc/passwd is the canonical colon-separated file. Every Linux administration tool reads it. Practising the parse builds the muscle for any colon- or tab-separated config format.

Input format

Line + output buffers.

Output format

0 / -1 + populated outputs.

Constraints

No strtok (re-entrancy concern); use pointer scanning.

Starter code

#include <stddef.h>
int parse_passwd_line(const char *line, char *user, size_t user_cap,
                      int *uid, char *home, size_t home_cap) { /* TODO */ return -1; }

Common mistakes

Using strtok and clobbering each delimiter — fine for this exercise but bad habit for multi-threaded code.

Edge cases to handle

Missing fields; empty fields; UID = 0 (root); buffer too small.

Complexity

O(strlen(line)).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.