Restore default signal handling in child processes
In particular, this fixes Ctrl-C in nix-shell sessions.
This commit is contained in:
parent
583ff4ec46
commit
7a65b2470e
7 changed files with 33 additions and 35 deletions
|
@ -30,6 +30,7 @@ static std::pair<FdSink, FdSource> connect(const string & conn)
|
||||||
throw SysError("dupping stdin");
|
throw SysError("dupping stdin");
|
||||||
if (dup2(from.writeSide, STDOUT_FILENO) == -1)
|
if (dup2(from.writeSide, STDOUT_FILENO) == -1)
|
||||||
throw SysError("dupping stdout");
|
throw SysError("dupping stdout");
|
||||||
|
restoreSignals();
|
||||||
execlp("ssh", "ssh", "-x", "-T", conn.c_str(), "nix-store --serve", NULL);
|
execlp("ssh", "ssh", "-x", "-T", conn.c_str(), "nix-store --serve", NULL);
|
||||||
throw SysError("executing ssh");
|
throw SysError("executing ssh");
|
||||||
});
|
});
|
||||||
|
|
|
@ -119,15 +119,9 @@ void initNix()
|
||||||
|
|
||||||
startSignalHandlerThread();
|
startSignalHandlerThread();
|
||||||
|
|
||||||
/* Ignore SIGPIPE. */
|
/* Reset SIGCHLD to its default. */
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
sigemptyset(&act.sa_mask);
|
sigemptyset(&act.sa_mask);
|
||||||
act.sa_handler = SIG_IGN;
|
|
||||||
act.sa_flags = 0;
|
|
||||||
if (sigaction(SIGPIPE, &act, 0))
|
|
||||||
throw SysError("ignoring SIGPIPE");
|
|
||||||
|
|
||||||
/* Reset SIGCHLD to its default. */
|
|
||||||
act.sa_handler = SIG_DFL;
|
act.sa_handler = SIG_DFL;
|
||||||
act.sa_flags = 0;
|
act.sa_flags = 0;
|
||||||
if (sigaction(SIGCHLD, &act, 0))
|
if (sigaction(SIGCHLD, &act, 0))
|
||||||
|
@ -252,7 +246,7 @@ void printVersion(const string & programName)
|
||||||
|
|
||||||
void showManPage(const string & name)
|
void showManPage(const string & name)
|
||||||
{
|
{
|
||||||
restoreSIGPIPE();
|
restoreSignals();
|
||||||
execlp("man", "man", name.c_str(), NULL);
|
execlp("man", "man", name.c_str(), NULL);
|
||||||
throw SysError(format("command ‘man %1%’ failed") % name.c_str());
|
throw SysError(format("command ‘man %1%’ failed") % name.c_str());
|
||||||
}
|
}
|
||||||
|
@ -305,16 +299,6 @@ RunPager::RunPager()
|
||||||
if (!pager) pager = getenv("PAGER");
|
if (!pager) pager = getenv("PAGER");
|
||||||
if (pager && ((string) pager == "" || (string) pager == "cat")) return;
|
if (pager && ((string) pager == "" || (string) pager == "cat")) 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;
|
Pipe toPager;
|
||||||
toPager.create();
|
toPager.create();
|
||||||
|
|
||||||
|
@ -323,6 +307,7 @@ RunPager::RunPager()
|
||||||
throw SysError("dupping stdin");
|
throw SysError("dupping stdin");
|
||||||
if (!getenv("LESS"))
|
if (!getenv("LESS"))
|
||||||
setenv("LESS", "FRSXMK", 1);
|
setenv("LESS", "FRSXMK", 1);
|
||||||
|
restoreSignals();
|
||||||
if (pager)
|
if (pager)
|
||||||
execl("/bin/sh", "sh", "-c", pager, NULL);
|
execl("/bin/sh", "sh", "-c", pager, NULL);
|
||||||
execlp("pager", "pager", NULL);
|
execlp("pager", "pager", NULL);
|
||||||
|
@ -331,6 +316,8 @@ RunPager::RunPager()
|
||||||
throw SysError(format("executing ‘%1%’") % pager);
|
throw SysError(format("executing ‘%1%’") % pager);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pid.setKillSignal(SIGINT);
|
||||||
|
|
||||||
if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
|
if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
|
||||||
throw SysError("dupping stdout");
|
throw SysError("dupping stdout");
|
||||||
}
|
}
|
||||||
|
@ -345,7 +332,11 @@ RunPager::~RunPager()
|
||||||
pid.wait();
|
pid.wait();
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ignoreException();
|
try {
|
||||||
|
pid.kill(true);
|
||||||
|
} catch (...) {
|
||||||
|
ignoreException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -400,6 +400,8 @@ void Goal::trace(const format & f)
|
||||||
/* Common initialisation performed in child processes. */
|
/* Common initialisation performed in child processes. */
|
||||||
static void commonChildInit(Pipe & logPipe)
|
static void commonChildInit(Pipe & logPipe)
|
||||||
{
|
{
|
||||||
|
restoreSignals();
|
||||||
|
|
||||||
/* Put the child in a separate session (and thus a separate
|
/* Put the child in a separate session (and thus a separate
|
||||||
process group) so that it has no controlling terminal (meaning
|
process group) so that it has no controlling terminal (meaning
|
||||||
that e.g. ssh cannot open /dev/tty) and it doesn't receive
|
that e.g. ssh cannot open /dev/tty) and it doesn't receive
|
||||||
|
@ -2662,8 +2664,6 @@ void DerivationGoal::runChild()
|
||||||
for (auto & i : drv->args)
|
for (auto & i : drv->args)
|
||||||
args.push_back(rewriteStrings(i, inputRewrites));
|
args.push_back(rewriteStrings(i, inputRewrites));
|
||||||
|
|
||||||
restoreSIGPIPE();
|
|
||||||
|
|
||||||
/* Indicate that we managed to set up the build environment. */
|
/* Indicate that we managed to set up the build environment. */
|
||||||
writeFull(STDERR_FILENO, string("\1\n"));
|
writeFull(STDERR_FILENO, string("\1\n"));
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,7 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
|
||||||
{
|
{
|
||||||
if ((pid_t) sshMaster == -1) {
|
if ((pid_t) sshMaster == -1) {
|
||||||
sshMaster = startProcess([&]() {
|
sshMaster = startProcess([&]() {
|
||||||
|
restoreSignals();
|
||||||
if (key.empty())
|
if (key.empty())
|
||||||
execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), uri.c_str(), NULL);
|
execlp("ssh", "ssh", "-N", "-M", "-S", socketPath.c_str(), uri.c_str(), NULL);
|
||||||
else
|
else
|
||||||
|
|
|
@ -860,6 +860,8 @@ string runProgram(Path program, bool searchPath, const Strings & args,
|
||||||
Strings args_(args);
|
Strings args_(args);
|
||||||
args_.push_front(program);
|
args_.push_front(program);
|
||||||
|
|
||||||
|
restoreSignals();
|
||||||
|
|
||||||
if (searchPath)
|
if (searchPath)
|
||||||
execvp(program.c_str(), stringsToCharPtrs(args_).data());
|
execvp(program.c_str(), stringsToCharPtrs(args_).data());
|
||||||
else
|
else
|
||||||
|
@ -909,16 +911,6 @@ void closeOnExec(int fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void restoreSIGPIPE()
|
|
||||||
{
|
|
||||||
struct sigaction act;
|
|
||||||
act.sa_handler = SIG_DFL;
|
|
||||||
act.sa_flags = 0;
|
|
||||||
sigemptyset(&act.sa_mask);
|
|
||||||
if (sigaction(SIGPIPE, &act, 0)) throw SysError("resetting SIGPIPE");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
@ -1218,19 +1210,31 @@ void triggerInterrupt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sigset_t savedSignalMask;
|
||||||
|
|
||||||
void startSignalHandlerThread()
|
void startSignalHandlerThread()
|
||||||
{
|
{
|
||||||
|
if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
|
||||||
|
throw SysError("quering signal mask");
|
||||||
|
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
sigemptyset(&set);
|
sigemptyset(&set);
|
||||||
sigaddset(&set, SIGINT);
|
sigaddset(&set, SIGINT);
|
||||||
sigaddset(&set, SIGTERM);
|
sigaddset(&set, SIGTERM);
|
||||||
sigaddset(&set, SIGHUP);
|
sigaddset(&set, SIGHUP);
|
||||||
|
sigaddset(&set, SIGPIPE);
|
||||||
if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
|
if (pthread_sigmask(SIG_BLOCK, &set, nullptr))
|
||||||
throw SysError("blocking signals");
|
throw SysError("blocking signals");
|
||||||
|
|
||||||
std::thread(signalHandlerThread, set).detach();
|
std::thread(signalHandlerThread, set).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void restoreSignals()
|
||||||
|
{
|
||||||
|
if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
|
||||||
|
throw SysError("restoring signals");
|
||||||
|
}
|
||||||
|
|
||||||
/* RAII helper to automatically deregister a callback. */
|
/* RAII helper to automatically deregister a callback. */
|
||||||
struct InterruptCallbackImpl : InterruptCallback
|
struct InterruptCallbackImpl : InterruptCallback
|
||||||
{
|
{
|
||||||
|
|
|
@ -256,10 +256,6 @@ void closeMostFDs(const set<int> & exceptions);
|
||||||
/* Set the close-on-exec flag for the given file descriptor. */
|
/* Set the close-on-exec flag for the given file descriptor. */
|
||||||
void closeOnExec(int fd);
|
void closeOnExec(int fd);
|
||||||
|
|
||||||
/* Restore default handling of SIGPIPE, otherwise some programs will
|
|
||||||
randomly say "Broken pipe". */
|
|
||||||
void restoreSIGPIPE();
|
|
||||||
|
|
||||||
|
|
||||||
/* User interruption. */
|
/* User interruption. */
|
||||||
|
|
||||||
|
@ -423,6 +419,9 @@ void callSuccess(
|
||||||
on the current thread (and thus any threads created by it). */
|
on the current thread (and thus any threads created by it). */
|
||||||
void startSignalHandlerThread();
|
void startSignalHandlerThread();
|
||||||
|
|
||||||
|
/* Restore default signal handling. */
|
||||||
|
void restoreSignals();
|
||||||
|
|
||||||
struct InterruptCallback
|
struct InterruptCallback
|
||||||
{
|
{
|
||||||
virtual ~InterruptCallback() { };
|
virtual ~InterruptCallback() { };
|
||||||
|
|
|
@ -452,6 +452,8 @@ int main(int argc, char ** argv)
|
||||||
|
|
||||||
auto argPtrs = stringsToCharPtrs(args);
|
auto argPtrs = stringsToCharPtrs(args);
|
||||||
|
|
||||||
|
restoreSignals();
|
||||||
|
|
||||||
execvp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), argPtrs.data());
|
execvp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), argPtrs.data());
|
||||||
|
|
||||||
throw SysError("executing shell");
|
throw SysError("executing shell");
|
||||||
|
|
Loading…
Reference in a new issue