Skip to content

who: report a stdout write error instead of panicking#13389

Open
leeewee wants to merge 2 commits into
uutils:mainfrom
leeewee:who-fix-write-error
Open

who: report a stdout write error instead of panicking#13389
leeewee wants to merge 2 commits into
uutils:mainfrom
leeewee:who-fix-write-error

Conversation

@leeewee

@leeewee leeewee commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #13388

who -q (--count) printed the user list and the trailing count with println!, which aborts (exit 134) when stdout can't be written — e.g. output redirected to a full device. GNU reports the write error and exits 1.

Both stdout output paths now go through a helper that propagates the failure: on error it reports a GNU-style write error: <reason> to stderr and exits 1.

Before:

$ who -q > /dev/full
thread 'main' panicked at library/std/src/io/stdio.rs:...:
failed printing to stdout: No space left on device
Aborted (core dumped)          # exit 134

After:

$ who -q > /dev/full
who: write error: No space left on device        # exit 1

The non--q record-listing path already propagated its write error but reported it without the write error: prefix (who: No space left on device); it now routes through the same helper, so both paths match GNU (who: write error: No space left on device, exit 1).

Same write-error class as chcon (#13061), kill (#13297), and runcon. The existing --heading /dev/full test is updated to the new message, and a -q regression test is added.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/pr/bounded-memory (fails in this run but passes in the 'main' branch)
Note: The gnu test tests/cp/link-heap is now being skipped but was previously passing.
Congrats! The gnu test tests/expand/bounded-memory is now passing!
Congrats! The gnu test tests/rm/many-dir-entries-vs-OOM is now passing!

Comment thread src/uu/who/src/platform/unix.rs Outdated
translate!("who-long-usage", "default_file" => utmpx::DEFAULT_FILE)
}

fn write_error(e: std::io::Error) -> Box<dyn UError> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use thiserror, see #13397.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved, thanks!

`who -q` printed the user list and count with `println!`, which aborts
(exit 134) when stdout can't be written, e.g. `who -q > /dev/full`. Write
through a helper that propagates the failure: on error it reports a
GNU-style `write error: <reason>` to stderr and exits 1.

The non-`-q` record path already propagated its write error but reported
it without the `write error:` prefix; route it through the same helper so
both paths match GNU.

Fixes uutils#13388
@leeewee
leeewee force-pushed the who-fix-write-error branch from b758bcd to de85c9d Compare July 15, 2026 04:50
}

#[derive(Debug, Error)]
enum WhoError {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are more variants expected? Otherwise a struct seems more appropriate imo..

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally define a UtilError enum for each utility. In the case of who, I do expect additional variants in the future, for example, a who-canonicalize-error variant.

#[derive(Debug, Error)]
enum WhoError {
#[error("{}", translate!("who-error-write", "error" => strip_errno(.0)))]
Write(std::io::Error),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it could derive from?

translate!("who-user-count", "count" => users.len())
)
})
.map_err(WhoError::Write)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the map_err can be skipped

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I tried this, but it regresses the output. who's print functions return UResult<()> (Result<(), Box<dyn UError>>), and uucore has a blanket impl From<io::Error> for Box<dyn UError> that builds a UIoError. So with #[from], a bare ? takes that one-step io::Error → Box<dyn UError> conversion and bypasses WhoError — the message drops from who: write error: No space left on device back to who: No space left on device. The explicit .map_err(WhoError::Write)? is what keeps the write-error path going through WhoError and its who-error-write message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer that the error variant is specified explicitly. It’s more future-proof in case we ever add a Read(std::io::Error) variant.

@codspeed-hq

codspeed-hq Bot commented Jul 20, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 339 untouched benchmarks
⏩ 46 skipped benchmarks1


Comparing leeewee:who-fix-write-error (0562952) with main (ef50d8b)

Open in CodSpeed

Footnotes

  1. 46 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

who -q panics (aborts) on a stdout write error when output to /dev/full

4 participants