forked from lix-project/lix
libstore: Move some init to preStartBuilder
Change-Id: If36cd51f4b9352e38e7008b1295e7868727718f2
This commit is contained in:
parent
2635a91cb4
commit
e6275f8d2f
|
@ -1,14 +1,11 @@
|
|||
#include "local-derivation-goal.hh"
|
||||
#include "indirect-root-store.hh"
|
||||
#include "hook-instance.hh"
|
||||
#include "worker.hh"
|
||||
#include "builtins.hh"
|
||||
#include "builtins/buildenv.hh"
|
||||
#include "path-references.hh"
|
||||
#include "finally.hh"
|
||||
#include "util.hh"
|
||||
#include "archive.hh"
|
||||
#include "compression.hh"
|
||||
#include "daemon.hh"
|
||||
#include "topo-sort.hh"
|
||||
#include "callback.hh"
|
||||
|
@ -85,14 +82,9 @@ LocalDerivationGoal::~LocalDerivationGoal() noexcept(false)
|
|||
}
|
||||
|
||||
|
||||
inline bool LocalDerivationGoal::needsHashRewrite()
|
||||
bool LocalDerivationGoal::needsHashRewrite()
|
||||
{
|
||||
#if __linux__
|
||||
return !useChroot;
|
||||
#else
|
||||
/* Darwin requires hash rewriting even when sandboxing is enabled. */
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -127,19 +119,7 @@ void LocalDerivationGoal::killChild()
|
|||
|
||||
void LocalDerivationGoal::killSandbox(bool getStats)
|
||||
{
|
||||
if (cgroup) {
|
||||
#if __linux__
|
||||
auto stats = destroyCgroup(*cgroup);
|
||||
if (getStats) {
|
||||
buildResult.cpuUser = stats.cpuUser;
|
||||
buildResult.cpuSystem = stats.cpuSystem;
|
||||
}
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
else if (buildUser) {
|
||||
if (buildUser) {
|
||||
auto uid = buildUser->getUID();
|
||||
assert(uid != 0);
|
||||
killUser(uid);
|
||||
|
@ -166,11 +146,6 @@ void LocalDerivationGoal::tryLocalBuild()
|
|||
if (noChroot)
|
||||
throw Error("derivation '%s' has '__noChroot' set, "
|
||||
"but that's not allowed when 'sandbox' is 'true'", worker.store.printStorePath(drvPath));
|
||||
#if __APPLE__
|
||||
if (additionalSandboxProfile != "")
|
||||
throw Error("derivation '%s' specifies a sandbox profile, "
|
||||
"but this is only allowed when 'sandbox' is 'relaxed'", worker.store.printStorePath(drvPath));
|
||||
#endif
|
||||
useChroot = true;
|
||||
}
|
||||
else if (settings.sandboxMode == smDisabled)
|
||||
|
@ -181,23 +156,14 @@ void LocalDerivationGoal::tryLocalBuild()
|
|||
|
||||
auto & localStore = getLocalStore();
|
||||
if (localStore.storeDir != localStore.realStoreDir.get()) {
|
||||
#if __linux__
|
||||
if (supportsDivertedStore()) {
|
||||
// Diverted store is only possible with different mounts for the host system
|
||||
// and builder. This necessarily means sandboxing.
|
||||
useChroot = true;
|
||||
#else
|
||||
} else {
|
||||
throw Error("building using a diverted store is not supported on this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if __linux__
|
||||
if (useChroot) {
|
||||
if (!mountAndPidNamespacesSupported()) {
|
||||
if (!settings.sandboxFallback)
|
||||
throw Error("this system does not support the kernel namespaces that are required for sandboxing; use '--no-sandbox' to disable sandboxing");
|
||||
debug("auto-disabling sandboxing because the prerequisite namespaces are not available");
|
||||
useChroot = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (useBuildUsers()) {
|
||||
if (!buildUser)
|
||||
|
@ -216,6 +182,8 @@ void LocalDerivationGoal::tryLocalBuild()
|
|||
|
||||
try {
|
||||
|
||||
preStartBuilder();
|
||||
|
||||
/* Okay, we have to build. */
|
||||
startBuilder();
|
||||
|
||||
|
@ -360,58 +328,6 @@ void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck()
|
|||
|
||||
void LocalDerivationGoal::startBuilder()
|
||||
{
|
||||
if ((buildUser && buildUser->getUIDCount() != 1)
|
||||
#if __linux__
|
||||
|| settings.useCgroups
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if __linux__
|
||||
experimentalFeatureSettings.require(Xp::Cgroups);
|
||||
|
||||
auto cgroupFS = getCgroupFS();
|
||||
if (!cgroupFS)
|
||||
throw Error("cannot determine the cgroups file system");
|
||||
|
||||
auto ourCgroups = getCgroups("/proc/self/cgroup");
|
||||
auto ourCgroup = ourCgroups[""];
|
||||
if (ourCgroup == "")
|
||||
throw Error("cannot determine cgroup name from /proc/self/cgroup");
|
||||
|
||||
auto ourCgroupPath = canonPath(*cgroupFS + "/" + ourCgroup);
|
||||
|
||||
if (!pathExists(ourCgroupPath))
|
||||
throw Error("expected cgroup directory '%s'", ourCgroupPath);
|
||||
|
||||
static std::atomic<unsigned int> counter{0};
|
||||
|
||||
cgroup = buildUser
|
||||
? fmt("%s/nix-build-uid-%d", ourCgroupPath, buildUser->getUID())
|
||||
: fmt("%s/nix-build-pid-%d-%d", ourCgroupPath, getpid(), counter++);
|
||||
|
||||
debug("using cgroup '%s'", *cgroup);
|
||||
|
||||
/* When using a build user, record the cgroup we used for that
|
||||
user so that if we got interrupted previously, we can kill
|
||||
any left-over cgroup first. */
|
||||
if (buildUser) {
|
||||
auto cgroupsDir = settings.nixStateDir + "/cgroups";
|
||||
createDirs(cgroupsDir);
|
||||
|
||||
auto cgroupFile = fmt("%s/%d", cgroupsDir, buildUser->getUID());
|
||||
|
||||
if (pathExists(cgroupFile)) {
|
||||
auto prevCgroup = readFile(cgroupFile);
|
||||
destroyCgroup(prevCgroup);
|
||||
}
|
||||
|
||||
writeFile(cgroupFile, *cgroup);
|
||||
}
|
||||
|
||||
#else
|
||||
throw Error("cgroups are not supported on this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Make sure that no other processes are executing under the
|
||||
sandbox uids. This must be done before any chownToBuilder()
|
||||
|
@ -427,10 +343,6 @@ void LocalDerivationGoal::startBuilder()
|
|||
settings.thisSystem,
|
||||
concatStringsSep<StringSet>(", ", worker.store.systemFeatures));
|
||||
|
||||
#if __APPLE__
|
||||
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
|
||||
#endif
|
||||
|
||||
/* Create a temporary directory where the build will take
|
||||
place. */
|
||||
tmpDir = createTempDir("", "nix-build-" + std::string(drvPath.name()), false, false, 0700);
|
||||
|
@ -752,11 +664,7 @@ pid_t LocalDerivationGoal::startChild(std::function<void()> openSlave) {
|
|||
void LocalDerivationGoal::initTmpDir() {
|
||||
/* In a sandbox, for determinism, always use the same temporary
|
||||
directory. */
|
||||
#if __linux__
|
||||
tmpDirInSandbox = useChroot ? settings.sandboxBuildDir : tmpDir;
|
||||
#else
|
||||
tmpDirInSandbox = tmpDir;
|
||||
#endif
|
||||
tmpDirInSandbox = findTmpDirInSandbox();
|
||||
|
||||
/* In non-structured mode, add all bindings specified in the
|
||||
derivation via the environment, except those listed in the
|
||||
|
|
|
@ -96,11 +96,6 @@ struct LocalDerivationGoal : public DerivationGoal
|
|||
typedef map<std::string, std::string> Environment;
|
||||
Environment env;
|
||||
|
||||
#if __APPLE__
|
||||
typedef std::string SandboxProfile;
|
||||
SandboxProfile additionalSandboxProfile;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Hash rewriting.
|
||||
*/
|
||||
|
@ -217,7 +212,7 @@ struct LocalDerivationGoal : public DerivationGoal
|
|||
/**
|
||||
* Whether we need to perform hash rewriting if there are valid output paths.
|
||||
*/
|
||||
bool needsHashRewrite();
|
||||
virtual bool needsHashRewrite();
|
||||
|
||||
/**
|
||||
* The additional states.
|
||||
|
@ -341,6 +336,22 @@ protected:
|
|||
*/
|
||||
virtual void materialisePath(const StorePath & path);
|
||||
|
||||
/**
|
||||
* Early build preparation, right after build user has been
|
||||
* allocated but before that user's processes have been killed.
|
||||
* This should be used to check OS-specific flags
|
||||
* and prepare to kill the build user's process
|
||||
*/
|
||||
virtual void preStartBuilder(){};
|
||||
|
||||
/**
|
||||
* Calculate the value for tmpDirInSandbox. Called once, in `initTmpDir`.
|
||||
*/
|
||||
virtual Path findTmpDirInSandbox()
|
||||
{
|
||||
return tmpDir;
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup dependencies outside the sandbox.
|
||||
* Called in the parent nix process.
|
||||
|
@ -371,12 +382,22 @@ protected:
|
|||
virtual void execBuilder(std::string builder, Strings args, Strings envStrs);
|
||||
|
||||
/**
|
||||
* Whether derivation feature `uid-range` is supported
|
||||
* Whether derivation can be built on current platform with `uid-range` feature
|
||||
*/
|
||||
virtual bool supportsUidRange()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether derivation can be built on current platform with a diverted store
|
||||
* (Store path appears at different path for derivation than on host,
|
||||
* e.g. used in nixos-install)
|
||||
*/
|
||||
virtual bool supportsDivertedStore()
|
||||
{
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -228,6 +228,19 @@ void DarwinLocalStore::findPlatformRoots(UncheckedRoots & unchecked)
|
|||
}
|
||||
}
|
||||
|
||||
void DarwinLocalDerivationGoal::preStartBuilder()
|
||||
{
|
||||
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
|
||||
|
||||
if (settings.sandboxMode == smEnabled && additionalSandboxProfile != "") {
|
||||
throw Error(
|
||||
"derivation '%s' specifies a sandbox profile, "
|
||||
"but this is only allowed when 'sandbox' is 'relaxed'",
|
||||
worker.store.printStorePath(drvPath)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void DarwinLocalDerivationGoal::enterSandbox()
|
||||
{
|
||||
/* This has to appear before import statements. */
|
||||
|
|
|
@ -42,10 +42,35 @@ public:
|
|||
using LocalDerivationGoal::LocalDerivationGoal;
|
||||
|
||||
private:
|
||||
// All work happens in enterSandbox and execBuilder
|
||||
typedef std::string SandboxProfile;
|
||||
SandboxProfile additionalSandboxProfile;
|
||||
|
||||
/**
|
||||
* Validate and set additionalSandboxProfile
|
||||
*/
|
||||
void preStartBuilder() override;
|
||||
|
||||
/**
|
||||
* Prepare the sandbox: This is empty on Darwin since sandbox setup happens in
|
||||
* enterSandbox
|
||||
*/
|
||||
void prepareSandbox() override{};
|
||||
|
||||
/**
|
||||
* Create a sandbox profile as a string, then enter it using `sandbox_init_with_parameters`
|
||||
*/
|
||||
void enterSandbox() override;
|
||||
|
||||
/**
|
||||
* Set process flags to enter or leave rosetta, then execute the builder
|
||||
*/
|
||||
void execBuilder(std::string builder, Strings args, Strings envStrs) override;
|
||||
|
||||
bool needsHashRewrite() override
|
||||
{
|
||||
/* Darwin requires hash rewriting even when sandboxing is enabled. */
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "build/worker.hh"
|
||||
#include "cgroup.hh"
|
||||
#include "finally.hh"
|
||||
#include "gc-store.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "signals.hh"
|
||||
#include "platform/linux/linux.hh"
|
||||
#include "regex.hh"
|
||||
#include "signals.hh"
|
||||
|
||||
#include <regex>
|
||||
|
||||
|
@ -207,6 +208,74 @@ void LinuxLocalDerivationGoal::materialisePath(const StorePath & path)
|
|||
}
|
||||
}
|
||||
|
||||
void LinuxLocalDerivationGoal::preStartBuilder()
|
||||
{
|
||||
if (useChroot) {
|
||||
if (!mountAndPidNamespacesSupported()) {
|
||||
if (!settings.sandboxFallback) {
|
||||
throw Error(
|
||||
"this system does not support the kernel namespaces that are required for "
|
||||
"sandboxing; use '--no-sandbox' to disable sandboxing"
|
||||
);
|
||||
}
|
||||
debug("auto-disabling sandboxing because the prerequisite namespaces are not available"
|
||||
);
|
||||
useChroot = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare cgroups here since we might reuse one from a previous build
|
||||
if ((buildUser && buildUser->getUIDCount() != 1) || settings.useCgroups) {
|
||||
experimentalFeatureSettings.require(Xp::Cgroups);
|
||||
|
||||
auto cgroupFS = getCgroupFS();
|
||||
if (!cgroupFS) {
|
||||
throw Error("cannot determine the cgroups file system");
|
||||
}
|
||||
|
||||
auto ourCgroups = getCgroups("/proc/self/cgroup");
|
||||
auto ourCgroup = ourCgroups[""];
|
||||
if (ourCgroup == "") {
|
||||
throw Error("cannot determine cgroup name from /proc/self/cgroup");
|
||||
}
|
||||
|
||||
auto ourCgroupPath = canonPath(*cgroupFS + "/" + ourCgroup);
|
||||
|
||||
if (!pathExists(ourCgroupPath)) {
|
||||
throw Error("expected cgroup directory '%s'", ourCgroupPath);
|
||||
}
|
||||
|
||||
static std::atomic<unsigned int> counter{0};
|
||||
|
||||
cgroup = buildUser ? fmt("%s/nix-build-uid-%d", ourCgroupPath, buildUser->getUID())
|
||||
: fmt("%s/nix-build-pid-%d-%d", ourCgroupPath, getpid(), counter++);
|
||||
|
||||
debug("using cgroup '%s'", *cgroup);
|
||||
|
||||
/* When using a build user, record the cgroup we used for that
|
||||
user so that if we got interrupted previously, we can kill
|
||||
any left-over cgroup first. */
|
||||
if (buildUser) {
|
||||
auto cgroupsDir = settings.nixStateDir + "/cgroups";
|
||||
createDirs(cgroupsDir);
|
||||
|
||||
auto cgroupFile = fmt("%s/%d", cgroupsDir, buildUser->getUID());
|
||||
|
||||
if (pathExists(cgroupFile)) {
|
||||
auto prevCgroup = readFile(cgroupFile);
|
||||
destroyCgroup(prevCgroup);
|
||||
}
|
||||
|
||||
writeFile(cgroupFile, *cgroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Path LinuxLocalDerivationGoal::findTmpDirInSandbox()
|
||||
{
|
||||
return useChroot ? settings.sandboxBuildDir : tmpDir;
|
||||
}
|
||||
|
||||
pid_t LinuxLocalDerivationGoal::startChild(std::function<void()> openSlave)
|
||||
{
|
||||
// If we're not sandboxing no need to faff about
|
||||
|
@ -909,4 +978,19 @@ void LinuxLocalDerivationGoal::enterSandbox()
|
|||
throw SysError("PR_SET_NO_NEW_PRIVS failed");
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxLocalDerivationGoal::killSandbox(bool getStats)
|
||||
{
|
||||
if (cgroup) {
|
||||
auto stats = destroyCgroup(*cgroup);
|
||||
if (getStats) {
|
||||
buildResult.cpuUser = stats.cpuUser;
|
||||
buildResult.cpuSystem = stats.cpuSystem;
|
||||
}
|
||||
} else if (buildUser) {
|
||||
auto uid = buildUser->getUID();
|
||||
assert(uid != 0);
|
||||
killUser(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,14 +43,23 @@ public:
|
|||
|
||||
private:
|
||||
void materialisePath(const StorePath & path) override;
|
||||
void preStartBuilder() override;
|
||||
Path findTmpDirInSandbox() override;
|
||||
void prepareSandbox() override;
|
||||
pid_t startChild(std::function<void()> openSlave) override;
|
||||
void enterSandbox() override;
|
||||
|
||||
void killSandbox(bool getStatus) override;
|
||||
|
||||
bool supportsUidRange() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool supportsDivertedStore() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue