From 392430b2c4ceb2e476abe2b3acc928581b2a1445 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 20 Aug 2014 15:12:58 +0200 Subject: [PATCH] nix-store -l: Automatically pipe output into $PAGER --- src/libmain/shared.cc | 40 ++++++++++++++++++++++++++++++++++++++ src/libmain/shared.hh | 12 ++++++++++++ src/libutil/util.cc | 4 ++-- src/nix-store/nix-store.cc | 2 ++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 9ac9d2773..ba75847fd 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -285,4 +285,44 @@ int handleExceptions(const string & programName, std::function fun) } +RunPager::RunPager() +{ + string pager = getEnv("PAGER"); + if (!isatty(STDOUT_FILENO) || pager.empty()) return; + + /* Ignore SIGINT. The pager will handle it (and we'll get + SIGPIPE). */ + struct sigaction act; + act.sa_handler = SIG_IGN; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGINT, &act, 0)) throw SysError("ignoring SIGINT"); + + restoreSIGPIPE(); + + Pipe toPager; + toPager.create(); + + pid = startProcess([&]() { + if (dup2(toPager.readSide, STDIN_FILENO) == -1) + throw SysError("dupping stdin"); + execl("/bin/sh", "sh", "-c", pager.c_str(), NULL); + throw SysError(format("executing `%1%'") % pager); + }); + + if (dup2(toPager.writeSide, STDOUT_FILENO) == -1) + throw SysError("dupping stdout"); + +} + + +RunPager::~RunPager() +{ + if (pid != -1) { + close(STDOUT_FILENO); + pid.wait(true); + } +} + + } diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index c74e7cbc1..c56203dae 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -69,6 +69,18 @@ template N getIntArg(const string & opt, /* Show the manual page for the specified program. */ void showManPage(const string & name); +/* The constructor of this class starts a pager if stdout is a + terminal and $PAGER is set. Stdout is redirected to the pager. */ +class RunPager +{ +public: + RunPager(); + ~RunPager(); + +private: + Pid pid; +}; + extern volatile ::sig_atomic_t blockInt; } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index ed283fb8c..14aab7cde 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -931,11 +931,11 @@ void closeOnExec(int fd) void restoreSIGPIPE() { - struct sigaction act, oact; + struct sigaction act; act.sa_handler = SIG_DFL; act.sa_flags = 0; sigemptyset(&act.sa_mask); - if (sigaction(SIGPIPE, &act, &oact)) throw SysError("resetting SIGPIPE"); + if (sigaction(SIGPIPE, &act, 0)) throw SysError("resetting SIGPIPE"); } diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 6a297b429..abe4c7e39 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -459,6 +459,8 @@ static void opReadLog(Strings opFlags, Strings opArgs) { if (!opFlags.empty()) throw UsageError("unknown flag"); + RunPager pager; + foreach (Strings::iterator, i, opArgs) { Path path = useDeriver(followLinksToStorePath(*i));