Skip to content

w: exits with error when utmp session references a missing tty device #718

Description

@Franklin-Qi

Summary

On Linux, w can fail with exit code 1 when /var/run/utmp (or /run/utmp) contains a user session whose tty device does not exist under /dev/.

This is visible in CI (cargo test on ubuntu-latest) and can also happen on real systems when utmp records reference stale or non-device tty names (e.g. certain pts/N, seat names, or leftover entries).

This fails on ubuntu-latest in GitHub Actions, while the same test often passes locally when no utmp records are present.

test test_watch::test_valid_interval_comma ... ok

failures:

---- test_w::test_option_short stdout ----
bin: "/home/runner/work/procps/procps/target/debug/procps"
run: /home/runner/work/procps/procps/target/debug/procps w --short

thread 'test_w::test_option_short' (11461) panicked at tests/by-util/test_w.rs:44:42:
Command was expected to succeed. code: 1
stdout = 
 stderr = w: failed to fetch user info: No such file or directory (os error 2)

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    test_w::test_option_short

test result: FAILED. 221 passed; 1 failed; 1 ignored; 0 measured; 0 filtered out; finished in 3.90s

error: test failed, to rerun pass `-p procps --test tests`
Error: Process completed with exit code 101.

Local Reproduction

Create a utmp record with a user session pointing at a non-existent tty:

python3 << 'PY'
import ctypes, os, time

class ExitStatus(ctypes.Structure):
    _fields_ = [("e_termination", ctypes.c_short), ("e_exit", ctypes.c_short)]

class Utmpx(ctypes.Structure):
    _fields_ = [
        ("ut_type", ctypes.c_short), ("_pad", ctypes.c_short),
        ("ut_pid", ctypes.c_int), ("ut_line", ctypes.c_char * 32),
        ("ut_id", ctypes.c_char * 4), ("ut_user", ctypes.c_char * 32),
        ("ut_host", ctypes.c_char * 256), ("ut_exit", ExitStatus),
        ("ut_session", ctypes.c_int), ("ut_tv_sec", ctypes.c_long),
        ("ut_tv_usec", ctypes.c_long), ("ut_addr_v6", ctypes.c_int * 4),
        ("reserved", ctypes.c_char * 20),
    ]

u = Utmpx()
u.ut_type = 7  # USER_PROCESS
u.ut_pid = os.getpid()
u.ut_line = b"no-such-tty-ci"
u.ut_user = b"testuser"
u.ut_tv_sec = int(time.time())
open("/tmp/fake-ci.utmp", "wb").write(bytes(u))
print("wrote /tmp/fake-ci.utmp")
PY

sudo cp /tmp/fake-ci.utmp /run/utmp
cargo run -q w --short
echo "exit code: $?"
sudo rm -f /run/utmp

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions