libmain: run pagers with a libexec helper
this is mostly a test and example for the libexec helper infrastructure, but it also lets us simplify pager launching until we we can more easily handle executable-not-found errors the launch fallbacks would cause when using runProgram2 instead of fork. ideally we'd use `posix_spawn` later. fixes #1104 Change-Id: Ia33cc12e8a9d60ffad6f5c055bb1b8b596810e64
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
run_pager = executable(
|
||||
'run-pager',
|
||||
files('run-pager.cc'),
|
||||
install : true,
|
||||
install_dir : libexecdir / 'lix',
|
||||
)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "common.hh"
|
||||
|
||||
LIBEXEC_HELPER(0)
|
||||
|
||||
int helperMain(const char * name, std::span<char *> args) noexcept
|
||||
{
|
||||
auto pager = args.empty() ? nullptr : args[0];
|
||||
|
||||
if (!getenv("LESS")) {
|
||||
setenv("LESS", "FRSXMK", 1);
|
||||
}
|
||||
if (pager) {
|
||||
execl("/bin/sh", "sh", "-c", pager, nullptr);
|
||||
}
|
||||
execlp("pager", "pager", nullptr);
|
||||
execlp("less", "less", nullptr);
|
||||
execlp("more", "more", nullptr);
|
||||
die("could not find a pager to run, please set PAGER or NIX_PAGER");
|
||||
}
|
||||
+23
-22
@@ -12,6 +12,8 @@
|
||||
#include "lix/libutil/log-format.hh"
|
||||
#include "lix/libutil/config.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
#include "lix/libutil/file-descriptor.hh"
|
||||
#include "lix/libutil/processes.hh"
|
||||
#include "lix/libutil/result.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libmain/loggers.hh"
|
||||
@@ -26,6 +28,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <kj/async-io.h>
|
||||
#include <kj/common.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@@ -373,7 +376,7 @@ int handleExceptions(const std::string & programName, std::function<int()> fun)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::pair<Pid, AutoCloseFD> startPager()
|
||||
static std::pair<RunningHelper, AutoCloseFD> startPager()
|
||||
{
|
||||
if (!isOutputARealTerminal(StandardOutputStream::Stdout)) {
|
||||
return {};
|
||||
@@ -384,27 +387,18 @@ static std::pair<Pid, AutoCloseFD> startPager()
|
||||
return {};
|
||||
}
|
||||
|
||||
logger->pause();
|
||||
|
||||
Pipe toPager;
|
||||
toPager.create();
|
||||
|
||||
auto pid = startProcess([&]() {
|
||||
if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
|
||||
throw SysError("dupping stdin");
|
||||
if (!getenv("LESS"))
|
||||
setenv("LESS", "FRSXMK", 1);
|
||||
restoreProcessContext();
|
||||
if (pager)
|
||||
execl("/bin/sh", "sh", "-c", pager, nullptr);
|
||||
execlp("pager", "pager", nullptr);
|
||||
execlp("less", "less", nullptr);
|
||||
execlp("more", "more", nullptr);
|
||||
throw SysError("executing '%1%'", pager);
|
||||
});
|
||||
auto helper = runHelper(
|
||||
"run-pager",
|
||||
{
|
||||
.args = pager ? Strings{pager} : Strings{},
|
||||
.redirections = {{.dup = STDIN_FILENO, .from = toPager.readSide.get()}},
|
||||
}
|
||||
);
|
||||
|
||||
pid.setKillSignal(SIGINT);
|
||||
return {std::move(pid), std::move(toPager.writeSide)};
|
||||
return {std::move(helper), std::move(toPager.writeSide)};
|
||||
}
|
||||
|
||||
void withPager(kj::Function<void(Pager &)> fn)
|
||||
@@ -422,15 +416,22 @@ void withPager(kj::Function<void(Pager &)> fn)
|
||||
}
|
||||
};
|
||||
|
||||
auto [pagerPid, pagerPipe] = startPager();
|
||||
logger->pause();
|
||||
KJ_DEFER(logger->resume());
|
||||
|
||||
auto [pagerProc, pagerPipe] = startPager();
|
||||
KJ_DEFER({
|
||||
if (pagerPid) {
|
||||
logger->resume();
|
||||
if (pagerProc) {
|
||||
pagerProc.kill();
|
||||
}
|
||||
});
|
||||
|
||||
PagerImpl pager{pagerPid ? pagerPid.get() : STDOUT_FILENO};
|
||||
PagerImpl pager{pagerProc ? pagerPipe.get() : STDOUT_FILENO};
|
||||
fn(pager);
|
||||
pagerPipe.close();
|
||||
if (pagerProc) {
|
||||
pagerProc.waitAndCheck();
|
||||
}
|
||||
}
|
||||
|
||||
PrintFreed::~PrintFreed()
|
||||
|
||||
Reference in New Issue
Block a user