diff --git a/include/pager.h b/include/pager.h index 9ca42eb35..0a7140d70 100644 --- a/include/pager.h +++ b/include/pager.h @@ -1,6 +1,9 @@ #ifndef UTIL_LINUX_PAGER #define UTIL_LINUX_PAGER -void setup_pager(void); +void pager_redirect(void); + +void pager_open(void); +void pager_close(void); #endif diff --git a/lib/pager.c b/lib/pager.c index e8cf10913..fb2c2d9d8 100644 --- a/lib/pager.c +++ b/lib/pager.c @@ -17,11 +17,11 @@ #include "c.h" #include "xalloc.h" #include "nls.h" +#include "ttyutils.h" +#include "pager.h" #define NULL_DEVICE "/dev/null" -void setup_pager(void); - static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; struct child_process { @@ -30,6 +30,10 @@ struct child_process { int in; int out; int err; + + int org_err; + int org_out; + unsigned no_stdin:1; void (*preexec_cb)(void); }; @@ -144,6 +148,9 @@ static void pager_preexec(void) static void wait_for_pager(void) { + if (pager_process.pid == 0) + return; + fflush(stdout); fflush(stderr); /* signal EOF to pager */ @@ -158,7 +165,7 @@ static void wait_for_pager_signal(int signo) raise(signo); } -void setup_pager(void) +static void __setup_pager(void) { const char *pager = getenv("PAGER"); @@ -191,10 +198,50 @@ void setup_pager(void) signal(SIGTERM, wait_for_pager_signal); signal(SIGQUIT, wait_for_pager_signal); signal(SIGPIPE, wait_for_pager_signal); +} + +/* Setup pager and redirects output to the $PAGER. The pager is closed at exit. + */ +void pager_redirect(void) +{ + if (pager_process.pid) + return; /* already running */ + + __setup_pager(); atexit(wait_for_pager); } +/* Setup pager and redirect output, the pager may be closed by pager_close(). + */ +void pager_open(void) +{ + if (pager_process.pid) + return; /* already running */ + + pager_process.org_out = dup(STDOUT_FILENO); + pager_process.org_err = dup(STDERR_FILENO); + + __setup_pager(); +} + +/* Close pager and restore original std{out,err}. + */ +void pager_close(void) +{ + if (pager_process.pid == 0) + return; + + wait_for_pager(); + dup2(pager_process.org_out, STDOUT_FILENO); + dup2(pager_process.org_err, STDERR_FILENO); + + close(pager_process.org_out); + close(pager_process.org_err); + + memset(&pager_process, 0, sizeof(pager_process)); +} + #ifdef TEST_PROGRAM #define MAX 255 @@ -204,7 +251,7 @@ int main(int argc __attribute__ ((__unused__)), { int i; - setup_pager(); + pager_setup(); for (i = 0; i < MAX; i++) printf("%d\n", i); return EXIT_SUCCESS; diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index a2ab3a2e3..0056b2520 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -1418,7 +1418,7 @@ int main(int argc, char *argv[]) nopager = 1; ctl.pager = nopager ? 0 : ctl.pager; if (ctl.pager) - setup_pager(); + pager_redirect(); switch (ctl.action) { case SYSLOG_ACTION_READ_ALL: @@ -1432,7 +1432,7 @@ int main(int argc, char *argv[]) errx(EXIT_FAILURE, _("--raw can be used together with --level or " "--facility only when reading messages from /dev/kmsg")); if (ctl.pager) - setup_pager(); + pager_redirect(); n = read_buffer(&ctl, &buf); if (n > 0) print_buffer(&ctl, buf, n);