From 81d20007f966e36cc8c9161b7117f3f1affdba02 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2015 00:10:35 +0200 Subject: copy: add splice() based fallback Apparently, sendfile() does not work between fifos and ttys, but splice() does, hence let's optionally fall back to that. This is useful to implement the fallback pager this way. --- src/basic/copy.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/basic/copy.c b/src/basic/copy.c index 33427c6a73..cc5faa80a1 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -30,7 +30,7 @@ #define COPY_BUFFER_SIZE (16*1024) int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { - bool try_sendfile = true; + bool try_sendfile = true, try_splice = true; int r; assert(fdf >= 0); @@ -69,7 +69,23 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { } else if (n == 0) /* EOF */ break; else if (n > 0) - /* Succcess! */ + /* Success! */ + goto next; + } + + /* The try splice, unless we already tried */ + if (try_splice) { + n = splice(fdf, NULL, fdt, NULL, m, 0); + if (n < 0) { + if (errno != EINVAL && errno != ENOSYS) + return -errno; + + try_splice = false; + /* use fallback below */ + } else if (n == 0) /* EOF */ + break; + else if (n > 0) + /* Success! */ goto next; } -- cgit v1.2.3-54-g00ecf From 6a7c676c54eb205d80f124eeb66c84df3c54d174 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2015 00:11:49 +0200 Subject: pager: port fallback pager to use copy_bytes() --- src/shared/pager.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/shared/pager.c b/src/shared/pager.c index 13f03e798b..a5454e377d 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -31,18 +31,16 @@ #include "macro.h" #include "terminal-util.h" #include "signal-util.h" +#include "copy.h" static pid_t pager_pid = 0; noreturn static void pager_fallback(void) { - ssize_t n; - - do { - n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0); - } while (n > 0); + int r; - if (n < 0) { - log_error_errno(errno, "Internal pager failed: %m"); + r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (off_t) -1, false); + if (r < 0) { + log_error_errno(r, "Internal pager failed: %m"); _exit(EXIT_FAILURE); } -- cgit v1.2.3-54-g00ecf From 8b5264aa65ea8f631990174a6f705d5a0d8e95fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Aug 2015 00:13:34 +0200 Subject: pager: also redirect stderr It's really confusing if stdout goes to the pager, but stderr is written directly to the screen. Hence, make sure both stdout and stderr are passed to the pager when doing autopaging. --- src/shared/pager.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/shared/pager.c b/src/shared/pager.c index a5454e377d..85f8fa5b39 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -129,6 +129,8 @@ int pager_open(bool jump_to_end) { /* Return in the parent */ if (dup2(fd[1], STDOUT_FILENO) < 0) return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); + if (dup2(fd[1], STDERR_FILENO) < 0) + return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); safe_close_pair(fd); return 1; @@ -141,6 +143,11 @@ void pager_close(void) { /* Inform pager that we are done */ fclose(stdout); + stdout = NULL; + + fclose(stderr); + stderr = NULL; + kill(pager_pid, SIGCONT); (void) wait_for_terminate(pager_pid, NULL); pager_pid = 0; -- cgit v1.2.3-54-g00ecf