#include "build.hh" namespace nix { HookInstance::HookInstance() { debug("starting build hook '%s'", settings.buildHook); /* Create a pipe to get the output of the child. */ fromHook.create(); /* Create the communication pipes. */ toHook.create(); /* Create a pipe to get the output of the builder. */ builderOut.create(); /* Fork the hook. */ pid = startProcess([&]() { commonChildInit(fromHook); if (chdir("/") == -1) throw SysError("changing into /"); /* Dup the communication pipes. */ if (dup2(toHook.readSide.get(), STDIN_FILENO) == -1) throw SysError("dupping to-hook read side"); /* Use fd 4 for the builder's stdout/stderr. */ if (dup2(builderOut.writeSide.get(), 4) == -1) throw SysError("dupping builder's stdout/stderr"); /* Hack: pass the read side of that fd to allow build-remote to read SSH error messages. */ if (dup2(builderOut.readSide.get(), 5) == -1) throw SysError("dupping builder's stdout/stderr"); Strings args = { std::string(baseNameOf(settings.buildHook.get())), std::to_string(verbosity), }; execv(settings.buildHook.get().c_str(), stringsToCharPtrs(args).data()); throw SysError("executing '%s'", settings.buildHook); }); pid.setSeparatePG(true); fromHook.writeSide = -1; toHook.readSide = -1; sink = FdSink(toHook.writeSide.get()); std::map settings; globalConfig.getSettings(settings); for (auto & setting : settings) sink << 1 << setting.first << setting.second.value; sink << 0; } HookInstance::~HookInstance() { try { toHook.writeSide = -1; if (pid != -1) pid.kill(); } catch (...) { ignoreException(); } } }