diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-07-10T14·50+0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-07-10T14·58+0200 |
commit | 8e9140cfdef9dbd1eb61e4c75c91d452ab5e4a74 (patch) | |
tree | d4480372c993c09c073e3561f3966f7595bcf2aa /src/libutil | |
parent | 1114c7bd57bcab16255d5db5e6f66ae8dece7b1e (diff) |
Refactoring: Move all fork handling into a higher-order function
C++11 lambdas ftw.
Diffstat (limited to 'src/libutil')
-rw-r--r-- | src/libutil/util.cc | 107 | ||||
-rw-r--r-- | src/libutil/util.hh | 7 |
2 files changed, 60 insertions, 54 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 5f6203bc2805..faa2b83c372a 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -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) { - - case -1: - throw SysError("unable to fork"); - - case 0: - try { /* child */ + Pid pid = startProcess([&]() { - if (setuid(uid) == -1) - throw SysError("setting uid"); + 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 */ 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(); - - switch (pid) { + Pid pid = startProcess([&]() { + if (dup2(pipe.writeSide, STDOUT_FILENO) == -1) + throw SysError("dupping stdout"); - 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); - } + if (searchPath) + execvp(program.c_str(), (char * *) &cargs[0]); + else + execv(program.c_str(), (char * *) &cargs[0]); - /* Parent. */ + throw SysError(format("executing `%1%'") % program); + }); pipe.writeSide.close(); diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 07c027a1f919..ad0d377a4f5e 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -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, |