diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 09af57871..86930c2e3 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -310,7 +310,7 @@ void printVersion(const string & programName) void showManPage(const string & name) { - restoreSignals(); + restoreProcessContext(); setenv("MANPATH", settings.nixManDir.c_str(), 1); execlp("man", "man", name.c_str(), nullptr); throw SysError("command 'man %1%' failed", name.c_str()); @@ -373,7 +373,7 @@ RunPager::RunPager() throw SysError("dupping stdin"); if (!getenv("LESS")) setenv("LESS", "FRSXMK", 1); - restoreSignals(); + restoreProcessContext(); if (pager) execl("/bin/sh", "sh", "-c", pager, nullptr); execlp("pager", "pager", nullptr); diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index 235eed37a..93f72675d 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -50,7 +50,7 @@ std::unique_ptr SSHMaster::startCommand(const std::string options.dieWithParent = false; conn->sshPid = startProcess([&]() { - restoreSignals(); + restoreProcessContext(); close(in.writeSide.get()); close(out.readSide.get()); @@ -110,7 +110,7 @@ Path SSHMaster::startMaster() options.dieWithParent = false; state->sshMaster = startProcess([&]() { - restoreSignals(); + restoreProcessContext(); close(out.readSide.get()); diff --git a/src/libutil/util.cc b/src/libutil/util.cc index a6fcabbec..06821abb1 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1116,7 +1116,7 @@ void runProgram2(const RunOptions & options) Strings args_(options.args); args_.push_front(options.program); - restoreSignals(); + restoreProcessContext(); if (options.searchPath) execvp(options.program.c_str(), stringsToCharPtrs(args_).data()); @@ -1612,12 +1612,19 @@ void startSignalHandlerThread() std::thread(signalHandlerThread, set).detach(); } -void restoreSignals() +static void restoreSignals() { if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr)) throw SysError("restoring signals"); } +void restoreProcessContext() +{ + restoreSignals(); + + restoreAffinity(); +} + /* RAII helper to automatically deregister a callback. */ struct InterruptCallbackImpl : InterruptCallback { @@ -1680,10 +1687,11 @@ string showBytes(uint64_t bytes) } +// FIXME: move to libstore/build void commonChildInit(Pipe & logPipe) { const static string pathNullDevice = "/dev/null"; - restoreSignals(); + restoreProcessContext(); /* Put the child in a separate session (and thus a separate process group) so that it has no controlling terminal (meaning diff --git a/src/libutil/util.hh b/src/libutil/util.hh index ef5e5012b..4762d1e55 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -300,6 +300,11 @@ std::pair runProgram(const RunOptions & options); void runProgram2(const RunOptions & options); +/* Restore the original inherited Unix process context (such as signal + masks, stack size, CPU affinity). */ +void restoreProcessContext(); + + class ExecError : public Error { public: @@ -513,9 +518,6 @@ class Callback; on the current thread (and thus any threads created by it). */ void startSignalHandlerThread(); -/* Restore default signal handling. */ -void restoreSignals(); - struct InterruptCallback { virtual ~InterruptCallback() { }; diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index d46bc1f2b..9acbedda2 100755 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -422,8 +422,6 @@ static void main_nix_build(int argc, char * * argv) } else env[var.first] = var.second; - restoreAffinity(); - /* Run a shell using the derivation's environment. For convenience, source $stdenv/setup to setup additional environment variables and shell functions. Also don't @@ -473,7 +471,7 @@ static void main_nix_build(int argc, char * * argv) auto argPtrs = stringsToCharPtrs(args); - restoreSignals(); + restoreProcessContext(); logger->stop(); diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 7cc7b85be..498a7b45c 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -462,8 +462,7 @@ struct CmdDevelop : Common, MixEnvironment auto args = phase || !command.empty() ? Strings{std::string(baseNameOf(shell)), rcFilePath} : Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; - restoreAffinity(); - restoreSignals(); + restoreProcessContext(); execvp(shell.c_str(), stringsToCharPtrs(args).data()); diff --git a/src/nix/edit.cc b/src/nix/edit.cc index 6472dd27a..b26417b18 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -42,7 +42,8 @@ struct CmdEdit : InstallableCommand auto args = editorFor(pos); - restoreSignals(); + restoreProcessContext(); + execvp(args.front().c_str(), stringsToCharPtrs(args).data()); std::string command; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index bce8d31dc..eed79c332 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -343,24 +343,6 @@ StringSet NixRepl::completePrefix(string prefix) } -static int runProgram(const string & program, const Strings & args) -{ - Strings args2(args); - args2.push_front(program); - - Pid pid; - pid = fork(); - if (pid == -1) throw SysError("forking"); - if (pid == 0) { - restoreAffinity(); - execvp(program.c_str(), stringsToCharPtrs(args2).data()); - _exit(1); - } - - return pid.wait(); -} - - bool isVarName(const string & s) { if (s.size() == 0) return false; @@ -462,7 +444,7 @@ bool NixRepl::processLine(string line) auto args = editorFor(pos); auto editor = args.front(); args.pop_front(); - runProgram(editor, args); + runProgram(editor, true, args); // Reload right after exiting the editor state->resetFileCache(); @@ -481,7 +463,7 @@ bool NixRepl::processLine(string line) state->callFunction(f, v, result, Pos()); StorePath drvPath = getDerivationPath(result); - runProgram(settings.nixBinDir + "/nix-shell", Strings{state->store->printStorePath(drvPath)}); + runProgram(settings.nixBinDir + "/nix-shell", true, {state->store->printStorePath(drvPath)}); } else if (command == ":b" || command == ":i" || command == ":s") { @@ -494,16 +476,18 @@ bool NixRepl::processLine(string line) /* We could do the build in this process using buildPaths(), but doing it in a child makes it easier to recover from problems / SIGINT. */ - if (runProgram(settings.nixBinDir + "/nix", Strings{"build", "--no-link", drvPathRaw}) == 0) { + try { + runProgram(settings.nixBinDir + "/nix", true, {"build", "--no-link", drvPathRaw}); auto drv = state->store->readDerivation(drvPath); std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; for (auto & i : drv.outputsAndOptPaths(*state->store)) std::cout << fmt(" %s -> %s\n", i.first, state->store->printStorePath(*i.second.second)); + } catch (ExecError &) { } } else if (command == ":i") { - runProgram(settings.nixBinDir + "/nix-env", Strings{"-i", drvPathRaw}); + runProgram(settings.nixBinDir + "/nix-env", true, {"-i", drvPathRaw}); } else { - runProgram(settings.nixBinDir + "/nix-shell", Strings{drvPathRaw}); + runProgram(settings.nixBinDir + "/nix-shell", true, {drvPathRaw}); } } diff --git a/src/nix/run.cc b/src/nix/run.cc index ba60e57d8..b5d8ab38a 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -31,9 +31,7 @@ struct RunCommon : virtual Command { stopProgressBar(); - restoreSignals(); - - restoreAffinity(); + restoreProcessContext(); /* If this is a diverted store (i.e. its "logical" location (typically /nix/store) differs from its "physical" location