linux-sysprog · intermediate · ~20 min

Parse a `/etc/passwd`-style line

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

Challenge

Pull the username, UID, and home directory out of one /etc/passwd-style colon-separated line.

Task

Implement int parse_passwd_line(const char *line, char *user, size_t user_cap, int *uid, char *home, size_t home_cap) that extracts three fields from line.

Input

  • line: one record in the format username:x:uid:gid:gecos:home:shell (exactly 7 colon-separated fields).
  • user, user_cap: buffer for field 0 (the username).
  • uid: where to store field 2 (the numeric UID).
  • home, home_cap: buffer for field 5 (the home directory).

Output

On success, copies field 0 into user and field 5 into home (each NUL-terminated, capped at cap - 1), parses field 2 into *uid, and returns 0. Returns -1 if the line does not have all 7 fields, if the UID field is not a clean integer, or if either string field does not fit its buffer.

Example

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   (too few fields)
parse_passwd_line("alice:x:abc:1000:Alice:/home:/sh", ...)     ->   -1   (non-numeric uid)

Edge cases

  • Fewer than 7 fields: -1.
  • A non-numeric UID field: -1.
  • A field that does not fit its destination buffer: -1.
  • UID may be 0 (root).

Rules

  • Parse by scanning for colons; do not use strtok (it has shared state).

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

A line 'username:x:uid:gid:gecos:home:shell' plus output buffers user/user_cap, uid, home/home_cap.

Output format

Fills user, *uid, home and returns 0; returns -1 on missing fields, non-numeric uid, or a too-small buffer.

Constraints

Exactly 7 colon-separated fields required. NUL-terminate string outputs. Do not use strtok.

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.