diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 693ad15..853ec88 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -175,6 +175,7 @@ struct pvstate_s { volatile sig_atomic_t clear_tty_tostop_on_exit; /* whether to clear tty TOSTOP on exit */ volatile sig_atomic_t suspend_stderr; /* whether writing to stderr is suspended */ volatile sig_atomic_t skip_next_sigcont; /* whether to ignore the next SIGCONT */ + volatile sig_atomic_t pipe_closed; /* whether the output pipe was closed */ } flag; /***************** diff --git a/src/pv/loop.c b/src/pv/loop.c index 1949ab8..0ce68c4 100644 --- a/src/pv/loop.c +++ b/src/pv/loop.c @@ -95,12 +95,12 @@ int pv_main_loop(pvstate_t state) struct stat sb; memset(&sb, 0, sizeof(sb)); if (0 == fstat(output_fd, &sb)) { - /*@-type@*/ + /*@-type@ */ if ((sb.st_mode & S_IFMT) == S_IFIFO) { output_is_pipe = true; debug("%s", "output is a pipe"); } - /*@+type@*/ /* splint says st_mode is __mode_t, not mode_t */ + /*@+type@ *//* splint says st_mode is __mode_t, not mode_t */ } else { debug("%s(%d): %s", "fstat", output_fd, strerror(errno)); } @@ -292,7 +292,12 @@ int pv_main_loop(pvstate_t state) if (output_is_pipe) { int nbytes; nbytes = 0; - if (0 == ioctl(output_fd, FIONREAD, &nbytes)) { + if (0 != state->flag.pipe_closed) { + if (0 != state->transfer.written_but_not_consumed) + debug("%s", + "clearing written_but_not_consumed because the output pipe was closed"); + state->transfer.written_but_not_consumed = 0; + } else if (0 == ioctl(output_fd, FIONREAD, &nbytes)) { if (nbytes >= 0) { if (((size_t) nbytes) != state->transfer.written_but_not_consumed) debug("%s: %d", "written_but_not_consumed is now", nbytes); diff --git a/src/pv/transfer.c b/src/pv/transfer.c index 12b95e3..7e37248 100644 --- a/src/pv/transfer.c +++ b/src/pv/transfer.c @@ -636,6 +636,7 @@ static int pv__transfer_read(pvstate_t state, int fd, bool *eof_in, bool *eof_ou static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long *lineswritten) { ssize_t nwritten; + int write_errno; if (NULL == state->transfer.transfer_buffer) { pv_error(state, "%s", _("no transfer buffer allocated")); @@ -646,6 +647,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long } nwritten = 0; + write_errno = 0; if (state->control.discard_input) { nwritten = state->transfer.to_write; @@ -693,6 +695,7 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long (size_t) (state->transfer.to_write), state->control.sync_after_write); if (nwritten < 0) { + write_errno = (int) errno; debug("%s: %ld: %s", "bytes written", (long) nwritten, strerror(errno)); } else { debug("%s: %ld", "bytes written", (long) nwritten); @@ -808,11 +811,11 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long * blocked on first write such that nwritten == 0, just wait a bit and * then return zero, since this was a transient error. */ - if ((0 == nwritten) || (EINTR == errno) || (EAGAIN == errno)) { + if ((0 == nwritten) || (EINTR == write_errno) || (EAGAIN == write_errno)) { if (0 == nwritten) { debug("%s", "attempted write blocked - waiting briefly"); } else { - debug("%s: %s", "transient write error - waiting briefly", strerror(errno)); + debug("%s: %s", "transient write error - waiting briefly", strerror(write_errno)); } (void) is_data_ready(-1, NULL, -1, NULL, 10000); return 0; @@ -822,13 +825,14 @@ static int pv__transfer_write(pvstate_t state, bool *eof_in, bool *eof_out, long * SIGPIPE means we've finished. Don't output an error because it's * not really our error to report. */ - if (EPIPE == errno) { + if (EPIPE == write_errno) { *eof_in = true; *eof_out = true; + state->flag.pipe_closed = 1; return 0; } - pv_error(state, "%s: %s", _("write failed"), strerror(errno)); + pv_error(state, "%s: %s", _("write failed"), strerror(write_errno)); state->status.exit_status |= PV_ERROREXIT_TRANSFER; *eof_out = true; state->transfer.written = -1;