From e74cab698579c62286c5210c83c4c7d94b530e99 Mon Sep 17 00:00:00 2001 From: Andrew Wood Date: Tue, 26 May 2026 22:36:58 +0100 Subject: [PATCH] If discarding input but /dev/null can't be used as a splice() destination, fall back to normal read() rather than exiting with an error (#192). --- src/pv/file.c | 18 ++++++++++-------- src/pv/transfer.c | 9 +++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/pv/file.c b/src/pv/file.c index 914fd7c..e7bb7e4 100644 --- a/src/pv/file.c +++ b/src/pv/file.c @@ -533,20 +533,22 @@ int pv_next_file(pvstate_t state, unsigned int filenum, int oldfd) /* * Open a file descriptor to /dev/null, so that input can be * spliced to it to implement -X. + * + * If this fails, transfer.discard_fd will be left at -1, + * which means the transfer functions will not use splice(). */ state->transfer.discard_fd = open("/dev/null", O_WRONLY); /* flawfinder: ignore */ /* flawfinder: /dev/null is trusted. */ if (state->transfer.discard_fd < 0) { - pv_perror("%s", "/dev/null"); - (void) close(fd); - fd = -1; - state->status.exit_status |= PV_ERROREXIT_TRANSITION; + debug("%s: %s", "/dev/null", strerror(errno)); + state->transfer.discard_fd = -1; } - if (!pv_fd_is_dev_null(state->transfer.discard_fd, true)) { - (void) close(fd); - fd = -1; - state->status.exit_status |= PV_ERROREXIT_TRANSITION; + if (!pv_fd_is_dev_null(state->transfer.discard_fd, false)) { + if (state->transfer.discard_fd >= 0) + (void) close(state->transfer.discard_fd); + state->transfer.discard_fd = -1; } + debug("%s: %d", "discard_fd", state->transfer.discard_fd); } #endif /* HAVE_SPLICE */ diff --git a/src/pv/transfer.c b/src/pv/transfer.c index 1f93664..f3bf2c3 100644 --- a/src/pv/transfer.c +++ b/src/pv/transfer.c @@ -432,11 +432,12 @@ static ssize_t pv__transfer__splice_repeated(pvstate_t state, int input_fd, int /* * Early return via pv__transfer__read_repeated() if splice() is - * turned off, or if line mode is active, or if splice() already - * failed on this input file descriptor, or if there's anything - * waiting in the transfer buffer. + * turned off, or if line mode is active, or if there's no output + * fd, or if splice() already failed on this input file descriptor, + * or if there's anything waiting in the transfer buffer. */ - if (state->control.no_splice || state->control.linemode || (input_fd == state->transfer.splice_failed_fd) + if (state->control.no_splice || state->control.linemode || (output_fd < 0) + || (input_fd == state->transfer.splice_failed_fd) || (state->transfer.to_write > 0)) { return pv__transfer__read_repeated(input_fd, buf, count); }