forked from lix-project/lix
Refactoring: Move all fork handling into a higher-order function
C++11 lambdas ftw.
This commit is contained in:
parent
1114c7bd57
commit
8e9140cfde
|
@ -24,30 +24,14 @@ static std::pair<FdSink, FdSource> connect(const string & conn)
|
||||||
Pipe to, from;
|
Pipe to, from;
|
||||||
to.create();
|
to.create();
|
||||||
from.create();
|
from.create();
|
||||||
pid_t child = fork();
|
startProcess([&]() {
|
||||||
switch (child) {
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
case 0:
|
|
||||||
try {
|
|
||||||
restoreAffinity();
|
|
||||||
if (dup2(to.readSide, STDIN_FILENO) == -1)
|
if (dup2(to.readSide, STDIN_FILENO) == -1)
|
||||||
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");
|
||||||
execlp("ssh"
|
execlp("ssh", "ssh", "-x", "-T", conn.c_str(), "nix-store --serve", NULL);
|
||||||
, "ssh"
|
|
||||||
, "-x"
|
|
||||||
, "-T"
|
|
||||||
, conn.c_str()
|
|
||||||
, "nix-store --serve"
|
|
||||||
, NULL);
|
|
||||||
throw SysError("executing ssh");
|
throw SysError("executing ssh");
|
||||||
} catch (std::exception & e) {
|
});
|
||||||
std::cerr << "error: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
// If child exits unexpectedly, we'll EPIPE or EOF early.
|
// If child exits unexpectedly, we'll EPIPE or EOF early.
|
||||||
// If we exit unexpectedly, child will EPIPE or EOF early.
|
// If we exit unexpectedly, child will EPIPE or EOF early.
|
||||||
// So no need to keep track of it.
|
// So no need to keep track of it.
|
||||||
|
|
|
@ -602,14 +602,7 @@ HookInstance::HookInstance()
|
||||||
builderOut.create();
|
builderOut.create();
|
||||||
|
|
||||||
/* Fork the hook. */
|
/* Fork the hook. */
|
||||||
pid = fork();
|
pid = startProcess([&]() {
|
||||||
switch (pid) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
try { /* child */
|
|
||||||
|
|
||||||
commonChildInit(fromHook);
|
commonChildInit(fromHook);
|
||||||
|
|
||||||
|
@ -630,14 +623,8 @@ HookInstance::HookInstance()
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
throw SysError(format("executing `%1%'") % buildHook);
|
throw SysError(format("executing `%1%'") % buildHook);
|
||||||
|
});
|
||||||
|
|
||||||
} catch (std::exception & e) {
|
|
||||||
writeToStderr("build hook error: " + string(e.what()) + "\n");
|
|
||||||
}
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parent */
|
|
||||||
pid.setSeparatePG(true);
|
pid.setSeparatePG(true);
|
||||||
pid.setKillSignal(SIGTERM);
|
pid.setKillSignal(SIGTERM);
|
||||||
fromHook.writeSide.close();
|
fromHook.writeSide.close();
|
||||||
|
@ -2781,15 +2768,7 @@ void SubstitutionGoal::tryToRun()
|
||||||
const char * * argArr = strings2CharPtrs(args);
|
const char * * argArr = strings2CharPtrs(args);
|
||||||
|
|
||||||
/* Fork the substitute program. */
|
/* Fork the substitute program. */
|
||||||
pid = fork();
|
pid = startProcess([&]() {
|
||||||
|
|
||||||
switch (pid) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
try { /* child */
|
|
||||||
|
|
||||||
commonChildInit(logPipe);
|
commonChildInit(logPipe);
|
||||||
|
|
||||||
|
@ -2799,14 +2778,8 @@ void SubstitutionGoal::tryToRun()
|
||||||
execv(sub.c_str(), (char * *) argArr);
|
execv(sub.c_str(), (char * *) argArr);
|
||||||
|
|
||||||
throw SysError(format("executing `%1%'") % sub);
|
throw SysError(format("executing `%1%'") % sub);
|
||||||
|
});
|
||||||
|
|
||||||
} catch (std::exception & e) {
|
|
||||||
writeToStderr("substitute error: " + string(e.what()) + "\n");
|
|
||||||
}
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parent */
|
|
||||||
pid.setSeparatePG(true);
|
pid.setSeparatePG(true);
|
||||||
pid.setKillSignal(SIGTERM);
|
pid.setKillSignal(SIGTERM);
|
||||||
outPipe.writeSide.close();
|
outPipe.writeSide.close();
|
||||||
|
|
|
@ -1083,16 +1083,7 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
|
||||||
|
|
||||||
setSubstituterEnv();
|
setSubstituterEnv();
|
||||||
|
|
||||||
run.pid = fork();
|
run.pid = startProcess([&]() {
|
||||||
|
|
||||||
switch (run.pid) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0: /* child */
|
|
||||||
try {
|
|
||||||
restoreAffinity();
|
|
||||||
if (dup2(toPipe.readSide, STDIN_FILENO) == -1)
|
if (dup2(toPipe.readSide, STDIN_FILENO) == -1)
|
||||||
throw SysError("dupping stdin");
|
throw SysError("dupping stdin");
|
||||||
if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)
|
if (dup2(fromPipe.writeSide, STDOUT_FILENO) == -1)
|
||||||
|
@ -1101,13 +1092,7 @@ void LocalStore::startSubstituter(const Path & substituter, RunningSubstituter &
|
||||||
throw SysError("dupping stderr");
|
throw SysError("dupping stderr");
|
||||||
execl(substituter.c_str(), substituter.c_str(), "--query", NULL);
|
execl(substituter.c_str(), substituter.c_str(), "--query", NULL);
|
||||||
throw SysError(format("executing `%1%'") % substituter);
|
throw SysError(format("executing `%1%'") % substituter);
|
||||||
} catch (std::exception & e) {
|
});
|
||||||
std::cerr << "error: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parent. */
|
|
||||||
|
|
||||||
run.program = baseNameOf(substituter);
|
run.program = baseNameOf(substituter);
|
||||||
run.to = toPipe.writeSide.borrow();
|
run.to = toPipe.writeSide.borrow();
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "util.hh"
|
||||||
|
#include "affinity.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -16,8 +19,6 @@
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "util.hh"
|
|
||||||
|
|
||||||
|
|
||||||
extern char * * environ;
|
extern char * * environ;
|
||||||
|
|
||||||
|
@ -714,6 +715,13 @@ Pid::Pid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Pid::Pid(pid_t pid)
|
||||||
|
{
|
||||||
|
Pid();
|
||||||
|
*this = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Pid::~Pid()
|
Pid::~Pid()
|
||||||
{
|
{
|
||||||
kill();
|
kill();
|
||||||
|
@ -801,25 +809,17 @@ void killUser(uid_t uid)
|
||||||
users to which the current process can send signals. So we
|
users to which the current process can send signals. So we
|
||||||
fork a process, switch to uid, and send a mass kill. */
|
fork a process, switch to uid, and send a mass kill. */
|
||||||
|
|
||||||
Pid pid;
|
Pid pid = startProcess([&]() {
|
||||||
pid = fork();
|
|
||||||
switch (pid) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
try { /* child */
|
|
||||||
|
|
||||||
if (setuid(uid) == -1)
|
if (setuid(uid) == -1)
|
||||||
throw SysError("setting uid");
|
throw SysError("setting uid");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
/* OSX's kill syscall takes a third parameter that, among other
|
/* OSX's kill syscall takes a third parameter that, among
|
||||||
things, determines if kill(-1, signo) affects the calling
|
other things, determines if kill(-1, signo) affects the
|
||||||
process. In the OSX libc, it's set to true, which means
|
calling process. In the OSX libc, it's set to true,
|
||||||
"follow POSIX", which we don't want here
|
which means "follow POSIX", which we don't want here
|
||||||
*/
|
*/
|
||||||
if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
|
if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break;
|
||||||
#else
|
#else
|
||||||
|
@ -830,14 +830,9 @@ void killUser(uid_t uid)
|
||||||
throw SysError(format("cannot kill processes for uid `%1%'") % uid);
|
throw SysError(format("cannot kill processes for uid `%1%'") % uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (std::exception & e) {
|
|
||||||
writeToStderr((format("killing processes belonging to uid `%1%': %2%\n") % uid % e.what()).str());
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
});
|
||||||
|
|
||||||
/* parent */
|
|
||||||
int status = pid.wait(true);
|
int status = pid.wait(true);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
throw Error(format("cannot kill processes for uid `%1%': %2%") % uid % statusToString(status));
|
throw Error(format("cannot kill processes for uid `%1%': %2%") % uid % statusToString(status));
|
||||||
|
@ -852,6 +847,25 @@ void killUser(uid_t uid)
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
pid_t startProcess(std::function<void()> fun, const string & errorPrefix)
|
||||||
|
{
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == -1) throw SysError("unable to fork");
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
try {
|
||||||
|
restoreAffinity();
|
||||||
|
fun();
|
||||||
|
} catch (std::exception & e) {
|
||||||
|
writeToStderr(errorPrefix + string(e.what()) + "\n");
|
||||||
|
}
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
string runProgram(Path program, bool searchPath, const Strings & args)
|
string runProgram(Path program, bool searchPath, const Strings & args)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
@ -867,16 +881,7 @@ string runProgram(Path program, bool searchPath, const Strings & args)
|
||||||
pipe.create();
|
pipe.create();
|
||||||
|
|
||||||
/* Fork. */
|
/* Fork. */
|
||||||
Pid pid;
|
Pid pid = startProcess([&]() {
|
||||||
pid = fork();
|
|
||||||
|
|
||||||
switch (pid) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0: /* child */
|
|
||||||
try {
|
|
||||||
if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
|
if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
|
||||||
throw SysError("dupping stdout");
|
throw SysError("dupping stdout");
|
||||||
|
|
||||||
|
@ -884,15 +889,9 @@ string runProgram(Path program, bool searchPath, const Strings & args)
|
||||||
execvp(program.c_str(), (char * *) &cargs[0]);
|
execvp(program.c_str(), (char * *) &cargs[0]);
|
||||||
else
|
else
|
||||||
execv(program.c_str(), (char * *) &cargs[0]);
|
execv(program.c_str(), (char * *) &cargs[0]);
|
||||||
|
|
||||||
throw SysError(format("executing `%1%'") % program);
|
throw SysError(format("executing `%1%'") % program);
|
||||||
|
});
|
||||||
} catch (std::exception & e) {
|
|
||||||
writeToStderr("error: " + string(e.what()) + "\n");
|
|
||||||
}
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parent. */
|
|
||||||
|
|
||||||
pipe.writeSide.close();
|
pipe.writeSide.close();
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
@ -237,6 +238,7 @@ class Pid
|
||||||
int killSignal;
|
int killSignal;
|
||||||
public:
|
public:
|
||||||
Pid();
|
Pid();
|
||||||
|
Pid(pid_t pid);
|
||||||
~Pid();
|
~Pid();
|
||||||
void operator =(pid_t pid);
|
void operator =(pid_t pid);
|
||||||
operator pid_t();
|
operator pid_t();
|
||||||
|
@ -252,6 +254,11 @@ public:
|
||||||
void killUser(uid_t uid);
|
void killUser(uid_t uid);
|
||||||
|
|
||||||
|
|
||||||
|
/* Fork a process that runs the given function, and return the child
|
||||||
|
pid to the caller. */
|
||||||
|
pid_t startProcess(std::function<void()> fun, const string & errorPrefix = "error: ");
|
||||||
|
|
||||||
|
|
||||||
/* Run a program and return its stdout in a string (i.e., like the
|
/* Run a program and return its stdout in a string (i.e., like the
|
||||||
shell backtick operator). */
|
shell backtick operator). */
|
||||||
string runProgram(Path program, bool searchPath = false,
|
string runProgram(Path program, bool searchPath = false,
|
||||||
|
|
|
@ -872,17 +872,7 @@ static void daemonLoop()
|
||||||
printMsg(lvlInfo, format("accepted connection from pid %1%, uid %2%") % clientPid % clientUid);
|
printMsg(lvlInfo, format("accepted connection from pid %1%, uid %2%") % clientPid % clientUid);
|
||||||
|
|
||||||
/* Fork a child to handle the connection. */
|
/* Fork a child to handle the connection. */
|
||||||
pid_t child;
|
startProcess([&]() {
|
||||||
child = fork();
|
|
||||||
|
|
||||||
switch (child) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
try { /* child */
|
|
||||||
|
|
||||||
/* Background the daemon. */
|
/* Background the daemon. */
|
||||||
if (setsid() == -1)
|
if (setsid() == -1)
|
||||||
throw SysError(format("creating a new session"));
|
throw SysError(format("creating a new session"));
|
||||||
|
@ -901,11 +891,8 @@ static void daemonLoop()
|
||||||
to.fd = remote;
|
to.fd = remote;
|
||||||
processConnection(trusted);
|
processConnection(trusted);
|
||||||
|
|
||||||
} catch (std::exception & e) {
|
_exit(0);
|
||||||
writeToStderr("unexpected Nix daemon error: " + string(e.what()) + "\n");
|
}, "unexpected Nix daemon error: ");
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Interrupted & e) {
|
} catch (Interrupted & e) {
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -939,27 +939,14 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
Pipe fromDecompressor;
|
Pipe fromDecompressor;
|
||||||
fromDecompressor.create();
|
fromDecompressor.create();
|
||||||
|
|
||||||
Pid pid;
|
Pid pid = startProcess([&]() {
|
||||||
pid = fork();
|
|
||||||
|
|
||||||
switch (pid) {
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
throw SysError("unable to fork");
|
|
||||||
|
|
||||||
case 0: /* child */
|
|
||||||
try {
|
|
||||||
fromDecompressor.readSide.close();
|
fromDecompressor.readSide.close();
|
||||||
if (dup2(fromDecompressor.writeSide, STDOUT_FILENO) == -1)
|
if (dup2(fromDecompressor.writeSide, STDOUT_FILENO) == -1)
|
||||||
throw SysError("dupping stdout");
|
throw SysError("dupping stdout");
|
||||||
// FIXME: use absolute path.
|
// FIXME: use absolute path.
|
||||||
execlp(compression.c_str(), compression.c_str(), "-d", NULL);
|
execlp(compression.c_str(), compression.c_str(), "-d", NULL);
|
||||||
throw SysError(format("executing `%1%'") % compression);
|
throw SysError(format("executing `%1%'") % compression);
|
||||||
} catch (std::exception & e) {
|
});
|
||||||
std::cerr << "error: " << e.what() << std::endl;
|
|
||||||
}
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fromDecompressor.writeSide.close();
|
fromDecompressor.writeSide.close();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue