Refactoring: Move all fork handling into a higher-order function
C++11 lambdas ftw.
This commit is contained in:
parent
1114c7bd57
commit
8e9140cfde
7 changed files with 128 additions and 206 deletions
|
@ -1,5 +1,8 @@
|
|||
#include "config.h"
|
||||
|
||||
#include "util.hh"
|
||||
#include "affinity.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
|
@ -16,8 +19,6 @@
|
|||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
extern char * * environ;
|
||||
|
||||
|
@ -714,6 +715,13 @@ Pid::Pid()
|
|||
}
|
||||
|
||||
|
||||
Pid::Pid(pid_t pid)
|
||||
{
|
||||
Pid();
|
||||
*this = pid;
|
||||
}
|
||||
|
||||
|
||||
Pid::~Pid()
|
||||
{
|
||||
kill();
|
||||
|
@ -801,43 +809,30 @@ void killUser(uid_t uid)
|
|||
users to which the current process can send signals. So we
|
||||
fork a process, switch to uid, and send a mass kill. */
|
||||
|
||||
Pid pid;
|
||||
pid = fork();
|
||||
switch (pid) {
|
||||
Pid pid = startProcess([&]() {
|
||||
|
||||
case -1:
|
||||
throw SysError("unable to fork");
|
||||
if (setuid(uid) == -1)
|
||||
throw SysError("setting uid");
|
||||
|
||||
case 0:
|
||||
try { /* child */
|
||||
|
||||
if (setuid(uid) == -1)
|
||||
throw SysError("setting uid");
|
||||
|
||||
while (true) {
|
||||
while (true) {
|
||||
#ifdef __APPLE__
|
||||
/* OSX's kill syscall takes a third parameter that, among other
|
||||
things, determines if kill(-1, signo) affects the calling
|
||||
process. In the OSX libc, it's set to true, which means
|
||||
"follow POSIX", which we don't want here
|
||||
/* OSX's kill syscall takes a third parameter that, among
|
||||
other things, determines if kill(-1, signo) affects the
|
||||
calling process. In the OSX libc, it's set to true,
|
||||
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
|
||||
if (kill(-1, SIGKILL) == 0) break;
|
||||
if (kill(-1, SIGKILL) == 0) break;
|
||||
#endif
|
||||
if (errno == ESRCH) break; /* no more processes */
|
||||
if (errno != EINTR)
|
||||
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);
|
||||
if (errno == ESRCH) break; /* no more processes */
|
||||
if (errno != EINTR)
|
||||
throw SysError(format("cannot kill processes for uid `%1%'") % uid);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
/* parent */
|
||||
_exit(0);
|
||||
});
|
||||
|
||||
int status = pid.wait(true);
|
||||
if (status != 0)
|
||||
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)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
@ -867,32 +881,17 @@ string runProgram(Path program, bool searchPath, const Strings & args)
|
|||
pipe.create();
|
||||
|
||||
/* Fork. */
|
||||
Pid pid;
|
||||
pid = fork();
|
||||
Pid pid = startProcess([&]() {
|
||||
if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
|
||||
throw SysError("dupping stdout");
|
||||
|
||||
switch (pid) {
|
||||
if (searchPath)
|
||||
execvp(program.c_str(), (char * *) &cargs[0]);
|
||||
else
|
||||
execv(program.c_str(), (char * *) &cargs[0]);
|
||||
|
||||
case -1:
|
||||
throw SysError("unable to fork");
|
||||
|
||||
case 0: /* child */
|
||||
try {
|
||||
if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
|
||||
throw SysError("dupping stdout");
|
||||
|
||||
if (searchPath)
|
||||
execvp(program.c_str(), (char * *) &cargs[0]);
|
||||
else
|
||||
execv(program.c_str(), (char * *) &cargs[0]);
|
||||
throw SysError(format("executing `%1%'") % program);
|
||||
|
||||
} catch (std::exception & e) {
|
||||
writeToStderr("error: " + string(e.what()) + "\n");
|
||||
}
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* Parent. */
|
||||
throw SysError(format("executing `%1%'") % program);
|
||||
});
|
||||
|
||||
pipe.writeSide.close();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <functional>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
@ -237,6 +238,7 @@ class Pid
|
|||
int killSignal;
|
||||
public:
|
||||
Pid();
|
||||
Pid(pid_t pid);
|
||||
~Pid();
|
||||
void operator =(pid_t pid);
|
||||
operator pid_t();
|
||||
|
@ -252,6 +254,11 @@ public:
|
|||
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
|
||||
shell backtick operator). */
|
||||
string runProgram(Path program, bool searchPath = false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue