Files
lix/lix/libexec/launch-builder-darwin.cc
T
eldritch horrors ac64c727b5 libstore: move build child launching to libexec
this allows us great flexibility in how children are launched (since the
actual launching is done by a separate executable), makes fork no longer
needed in the core codebase (outside of runProgram, anyway), and we even
get to use linux vfork to its full potential to decrease the launch cost
of sandboxes to a constant factor (previously it was O(#drvs + #deps) of
the build graph, which obviously goes to n² quickly if you are unlucky.)

Change-Id: I66e2d1b20242dc24d708666ef325fb8725bd9296
2026-02-03 14:11:33 +00:00

91 lines
3.1 KiB
C++

#include "launch-builder.hh"
#include "lix/libstore/build/request.capnp.h"
#include "lix/libutil/rpc.hh"
#include <cstdlib>
#include <spawn.h>
#include <string_view>
#include <sys/sysctl.h>
#include <unistd.h>
namespace nix {
/* This definition is undocumented but depended upon by all major browsers. */
extern "C" int sandbox_init_with_parameters(
const char * profile, uint64_t flags, const char * const parameters[], char ** errorbuf
);
bool prepareChildSetup(build::Request::Reader request)
{
return true;
}
void finishChildSetup(build::Request::Reader request)
{
const auto config = request.getPlatform().getDarwin();
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try
different mechanisms to find temporary directories, so we want to open up a broader place for them
to put their files, if needed. */
auto globalTmpDir = rpc::to<std::string>(config.getGlobalTempDir());
/* They don't like trailing slashes on subpath directives */
if (globalTmpDir.back() == '/') {
globalTmpDir.pop_back();
}
if (auto env = getenv("_NIX_TEST_NO_SANDBOX"); env && env != std::string_view("1")) {
std::vector<const char *> sandboxArgs;
sandboxArgs.push_back("_NIX_BUILD_TOP");
sandboxArgs.push_back(config.getTempDir().cStr());
sandboxArgs.push_back("_GLOBAL_TMP_DIR");
sandboxArgs.push_back(globalTmpDir.c_str());
if (config.getAllowLocalNetworking()) {
sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING");
sandboxArgs.push_back("1");
}
sandboxArgs.push_back(nullptr);
// NOLINTNEXTLINE(lix-unsafe-c-calls): all of these are env names or paths
if (sandbox_init_with_parameters(config.getSandboxProfile().cStr(), 0, sandboxArgs.data(), nullptr)) {
writeFull(STDERR_FILENO, "failed to configure sandbox\n");
_exit(1);
}
}
}
[[noreturn]]
void execBuilder(build::Request::Reader request)
{
const auto config = request.getPlatform().getDarwin();
posix_spawnattr_t attrp;
if (posix_spawnattr_init(&attrp)) {
throw SysError("failed to initialize builder");
}
if (posix_spawnattr_setflags(&attrp, POSIX_SPAWN_SETEXEC)) {
throw SysError("failed to initialize builder");
}
const auto platform = rpc::to<std::string_view>(config.getPlatform());
if (platform == "aarch64-darwin") {
// Unset kern.curproc_arch_affinity so we can escape Rosetta
int affinity = 0;
sysctlbyname("kern.curproc_arch_affinity", nullptr, nullptr, &affinity, sizeof(affinity));
cpu_type_t cpu = CPU_TYPE_ARM64;
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, nullptr);
} else if (platform == "x86_64-darwin") {
cpu_type_t cpu = CPU_TYPE_X86_64;
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, nullptr);
}
ExecRequest req{request};
posix_spawn(nullptr, req.builder.c_str(), nullptr, &attrp, req.args.data(), req.envs.data());
throw SysError(errno, std::format("running {}", req.builder));
}
}