Silently handle fd_output_stream_t append errors in case of SIGINT

If EINTR caused by SIGINT is encountered while writing to the
`fd_output_stream_t` output fd, mark the output stream as errored and return
false to the caller but do not visibly complain.

Addressing the outstanding TODO notwithstanding, this is needed to avoid
littering the tty with spurious errors when the user hits Ctrl-C to abort a
long-running builtin's output (w/ the primary example being `history`).
This commit is contained in:
Mahmoud Al-Qudsi 2022-10-08 12:26:29 -05:00
parent 8e97fcb22c
commit 83636fa599

View file

@ -338,8 +338,17 @@ bool fd_output_stream_t::append(const wchar_t *s, size_t amt) {
if (errored_) return false;
int res = wwrite_to_fd(s, amt, this->fd_);
if (res < 0) {
// TODO: this error is too aggressive, e.g. if we got SIGINT we should not complain.
if (errno != EPIPE) {
// Some of our builtins emit multiple screens worth of data sent to a pager (the primary
// example being the `history` builtin) and receiving SIGINT should be considered normal and
// non-exceptional (user request to abort via Ctrl-C), meaning we shouldn't print an error.
if (errno == EINTR && sigcheck_.check()) {
// We have two options here: we can either return false without setting errored_ to
// true (*this* write will be silently aborted but the onus is on the caller to check
// the return value and skip future calls to `append()`) or we can flag the entire
// output stream as errored, causing us to both return false and skip any future writes.
// We're currently going with the latter, especially seeing as no callers currently
// check the result of `append()` (since it was always a void function before).
} else if (errno != EPIPE) {
wperror(L"write");
}
errored_ = true;