hercules-ci-agent-0.10.7: hercules-ci-nix-daemon/daemon.cc
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <string_view>
#include <nix/util/error.hh>
#include <nix/util/fmt.hh>
#include <nix/util/config-global.hh>
#include <nix/util/serialise.hh>
#include <nix/util/signals.hh>
#include <nix/store/daemon.hh>
#include <nix/main/shared.hh>
using namespace nix;
using nix::unix::closeOnExec;
static void sigChldHandler(int sigNo)
{
// Ensure we don't modify errno of whatever we've interrupted
auto saved_errno = errno;
// Reap all dead children.
while (waitpid(-1, 0, WNOHANG) > 0) ;
errno = saved_errno;
}
static void setSigChldAction()
{
struct sigaction act, oact;
act.sa_handler = sigChldHandler;
sigfillset(&act.sa_mask);
act.sa_flags = 0;
if (sigaction(SIGCHLD, &act, &oact))
throw SysError("setting SIGCHLD handler");
}
extern "C" int main(int argc, char **argv) {
nix::initNix();
for (int i = 1; i < argc && argv[i]; i++) {
std::string arg(argv[i]);
if (arg == "--option") {
if (i + 2 < argc) {
nix::globalConfig.set(argv[i+1], argv[i+2]);
i += 2;
}
else {
std::cerr << "Not enough arguments to --option" << std::endl;
return 1;
}
}
}
// See withNixDaemonProxy for stdin (ab)use
AutoCloseFD socketFD = dup(0);
closeOnExec(socketFD.get());
// Put /dev/null on stdin
int devnull = open("/dev/null", O_RDONLY);
dup2(devnull, 0);
close(devnull);
setSigChldAction();
while (1) {
struct sockaddr_un remoteAddr;
socklen_t remoteAddrLen = sizeof(remoteAddr);
try {
AutoCloseFD remote = accept(socketFD.get(), (struct sockaddr *) &remoteAddr, &remoteAddrLen);
checkInterrupt();
if (!remote) {
if (errno == EINTR) continue;
else throw SysError("hercules-ci-nix-daemon: accepting connection");
}
closeOnExec(remote.get());
ProcessOptions options;
options.errorPrefix = "hercules-ci-nix-daemon: unexpected error: ";
options.dieWithParent = false;
options.runExitHandlers = true;
options.allowVfork = false;
startProcess([&]() {
socketFD = -1;
// Regular nix daemon creates a new session for connections and
// does not kill connection child processes. Those are not
// appropriate behaviors for a temporary proxy.
FdSource from(remote.get());
FdSink to(remote.get());
// TODO: disable caching without interfering with user parameters
ref<Store> store = openStore();
TrustedFlag trusted = NotTrusted;
daemon::RecursiveFlag recursive = daemon::NotRecursive;
daemon::processConnection(
store
, std::move(from)
, std::move(to)
, trusted
, recursive
);
});
} catch (Interrupted & e) {
return 0;
} catch (Error & error) {
ErrorInfo ei = error.info();
ei.msg = HintFmt("hercules-ci-nix-daemon: error processing connection: %1%", ei.msg.str());
logError(ei);
}
}
return 0;
}