Moving more code out of DerivationGoal::startBuilder()

This commit is contained in:
Eelco Dolstra 2017-01-25 12:00:28 +01:00
parent e8c43abd9a
commit a529c740d2
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE

View file

@ -780,6 +780,7 @@ private:
}; };
typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path typedef map<Path, ChrootPath> DirsInChroot; // maps target path to source path
DirsInChroot dirsInChroot; DirsInChroot dirsInChroot;
typedef map<string, string> Environment; typedef map<string, string> Environment;
Environment env; Environment env;
@ -817,6 +818,8 @@ private:
const uid_t sandboxUid = 1000; const uid_t sandboxUid = 1000;
const gid_t sandboxGid = 100; const gid_t sandboxGid = 100;
const static Path homeDir;
public: public:
DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs,
Worker & worker, BuildMode buildMode = bmNormal); Worker & worker, BuildMode buildMode = bmNormal);
@ -864,6 +867,12 @@ private:
/* Start building a derivation. */ /* Start building a derivation. */
void startBuilder(); void startBuilder();
/* Fill in the environment for the builder. */
void initEnv();
/* Make a file owned by the builder. */
void chownToBuilder(const Path & path);
/* Handle the exportReferencesGraph attribute. */ /* Handle the exportReferencesGraph attribute. */
void doExportReferencesGraph(); void doExportReferencesGraph();
@ -907,6 +916,9 @@ private:
}; };
const Path DerivationGoal::homeDir = "/homeless-shelter";
DerivationGoal::DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs, DerivationGoal::DerivationGoal(const Path & drvPath, const StringSet & wantedOutputs,
Worker & worker, BuildMode buildMode) Worker & worker, BuildMode buildMode)
: Goal(worker) : Goal(worker)
@ -1672,11 +1684,7 @@ void DerivationGoal::startBuilder()
additionalSandboxProfile = get(drv->env, "__sandboxProfile"); additionalSandboxProfile = get(drv->env, "__sandboxProfile");
#endif #endif
/* Are we doing a chroot build? Note that fixed-output /* Are we doing a chroot build? */
derivations are never done in a chroot, mainly so that
functions like fetchurl (which needs a proper /etc/resolv.conf)
work properly. Purity checking for fixed-output derivations
is somewhat pointless anyway. */
{ {
string x = settings.get("build-use-sandbox", string x = settings.get("build-use-sandbox",
/* deprecated alias */ /* deprecated alias */
@ -1703,31 +1711,15 @@ void DerivationGoal::startBuilder()
if (worker.store.storeDir != worker.store.realStoreDir) if (worker.store.storeDir != worker.store.realStoreDir)
useChroot = true; useChroot = true;
/* Construct the environment passed to the builder. */ /* If `build-users-group' is not empty, then we have to build as
env.clear(); one of the members of that group. */
if (settings.buildUsersGroup != "" && getuid() == 0) {
buildUser.acquire();
/* Most shells initialise PATH to some default (/bin:/usr/bin:...) when /* Make sure that no other processes are executing under this
PATH is not set. We don't want this, so we fill it in with some dummy uid. */
value. */ buildUser.kill();
env["PATH"] = "/path-not-set"; }
/* Set HOME to a non-existing path to prevent certain programs from using
/etc/passwd (or NIS, or whatever) to locate the home directory (for
example, wget looks for ~/.wgetrc). I.e., these tools use /etc/passwd
if HOME is not set, but they will just assume that the settings file
they are looking for does not exist if HOME is set but points to some
non-existing path. */
Path homeDir = "/homeless-shelter";
env["HOME"] = homeDir;
/* Tell the builder where the Nix store is. Usually they
shouldn't care, but this is useful for purity checking (e.g.,
the compiler or linker might only want to accept paths to files
in the store or in the build directory). */
env["NIX_STORE"] = worker.store.storeDir;
/* The maximum number of cores to utilize for parallel building. */
env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
/* Create a temporary directory where the build will take /* Create a temporary directory where the build will take
place. */ place. */
@ -1737,86 +1729,18 @@ void DerivationGoal::startBuilder()
/* In a sandbox, for determinism, always use the same temporary /* In a sandbox, for determinism, always use the same temporary
directory. */ directory. */
tmpDirInSandbox = useChroot ? canonPath("/tmp", true) + "/nix-build-" + drvName + "-0" : tmpDir; tmpDirInSandbox = useChroot ? canonPath("/tmp", true) + "/nix-build-" + drvName + "-0" : tmpDir;
chownToBuilder(tmpDir);
/* Add all bindings specified in the derivation via the /* Construct the environment passed to the builder. */
environments, except those listed in the passAsFile initEnv();
attribute. Those are passed as file names pointing to
temporary files containing the contents. */
PathSet filesToChown;
StringSet passAsFile = tokenizeString<StringSet>(get(drv->env, "passAsFile"));
int fileNr = 0;
for (auto & i : drv->env) {
if (passAsFile.find(i.first) == passAsFile.end()) {
env[i.first] = i.second;
} else {
string fn = ".attr-" + std::to_string(fileNr++);
Path p = tmpDir + "/" + fn;
writeFile(p, i.second);
filesToChown.insert(p);
env[i.first + "Path"] = tmpDirInSandbox + "/" + fn;
}
}
/* For convenience, set an environment pointing to the top build
directory. */
env["NIX_BUILD_TOP"] = tmpDirInSandbox;
/* Also set TMPDIR and variants to point to this directory. */
env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDirInSandbox;
/* Explicitly set PWD to prevent problems with chroot builds. In
particular, dietlibc cannot figure out the cwd because the
inode of the current directory doesn't appear in .. (because
getdents returns the inode of the mount point). */
env["PWD"] = tmpDirInSandbox;
/* Compatibility hack with Nix <= 0.7: if this is a fixed-output
derivation, tell the builder, so that for instance `fetchurl'
can skip checking the output. On older Nixes, this environment
variable won't be set, so `fetchurl' will do the check. */
if (fixedOutput) env["NIX_OUTPUT_CHECKED"] = "1";
/* *Only* if this is a fixed-output derivation, propagate the
values of the environment variables specified in the
`impureEnvVars' attribute to the builder. This allows for
instance environment variables for proxy configuration such as
`http_proxy' to be easily passed to downloaders like
`fetchurl'. Passing such environment variables from the caller
to the builder is generally impure, but the output of
fixed-output derivations is by definition pure (since we
already know the cryptographic hash of the output). */
if (fixedOutput) {
Strings varNames = tokenizeString<Strings>(get(drv->env, "impureEnvVars"));
for (auto & i : varNames) env[i] = getEnv(i);
}
/* Substitute output placeholders with the actual output paths. */ /* Substitute output placeholders with the actual output paths. */
for (auto & output : drv->outputs) for (auto & output : drv->outputs)
inputRewrites[hashPlaceholder(output.first)] = output.second.path; inputRewrites[hashPlaceholder(output.first)] = output.second.path;
/* Handle exportReferencesGraph(), if set. */ /* Handle exportReferencesGraph(), if set. */
doExportReferencesGraph(); doExportReferencesGraph();
/* If `build-users-group' is not empty, then we have to build as
one of the members of that group. */
if (settings.buildUsersGroup != "" && getuid() == 0) {
buildUser.acquire();
/* Make sure that no other processes are executing under this
uid. */
buildUser.kill();
/* Change ownership of the temporary build directory. */
filesToChown.insert(tmpDir);
for (auto & p : filesToChown)
if (chown(p.c_str(), buildUser.getUID(), buildUser.getGID()) == -1)
throw SysError(format("cannot change ownership of %1%") % p);
}
if (useChroot) { if (useChroot) {
string defaultChrootDirs; string defaultChrootDirs;
@ -2203,6 +2127,93 @@ void DerivationGoal::startBuilder()
} }
void DerivationGoal::initEnv()
{
env.clear();
/* Most shells initialise PATH to some default (/bin:/usr/bin:...) when
PATH is not set. We don't want this, so we fill it in with some dummy
value. */
env["PATH"] = "/path-not-set";
/* Set HOME to a non-existing path to prevent certain programs from using
/etc/passwd (or NIS, or whatever) to locate the home directory (for
example, wget looks for ~/.wgetrc). I.e., these tools use /etc/passwd
if HOME is not set, but they will just assume that the settings file
they are looking for does not exist if HOME is set but points to some
non-existing path. */
env["HOME"] = homeDir;
/* Tell the builder where the Nix store is. Usually they
shouldn't care, but this is useful for purity checking (e.g.,
the compiler or linker might only want to accept paths to files
in the store or in the build directory). */
env["NIX_STORE"] = worker.store.storeDir;
/* The maximum number of cores to utilize for parallel building. */
env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
/* Add all bindings specified in the derivation via the
environments, except those listed in the passAsFile
attribute. Those are passed as file names pointing to
temporary files containing the contents. */
StringSet passAsFile = tokenizeString<StringSet>(get(drv->env, "passAsFile"));
int fileNr = 0;
for (auto & i : drv->env) {
if (passAsFile.find(i.first) == passAsFile.end()) {
env[i.first] = i.second;
} else {
string fn = ".attr-" + std::to_string(fileNr++);
Path p = tmpDir + "/" + fn;
writeFile(p, i.second);
chownToBuilder(p);
env[i.first + "Path"] = tmpDirInSandbox + "/" + fn;
}
}
/* For convenience, set an environment pointing to the top build
directory. */
env["NIX_BUILD_TOP"] = tmpDirInSandbox;
/* Also set TMPDIR and variants to point to this directory. */
env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDirInSandbox;
/* Explicitly set PWD to prevent problems with chroot builds. In
particular, dietlibc cannot figure out the cwd because the
inode of the current directory doesn't appear in .. (because
getdents returns the inode of the mount point). */
env["PWD"] = tmpDirInSandbox;
/* Compatibility hack with Nix <= 0.7: if this is a fixed-output
derivation, tell the builder, so that for instance `fetchurl'
can skip checking the output. On older Nixes, this environment
variable won't be set, so `fetchurl' will do the check. */
if (fixedOutput) env["NIX_OUTPUT_CHECKED"] = "1";
/* *Only* if this is a fixed-output derivation, propagate the
values of the environment variables specified in the
`impureEnvVars' attribute to the builder. This allows for
instance environment variables for proxy configuration such as
`http_proxy' to be easily passed to downloaders like
`fetchurl'. Passing such environment variables from the caller
to the builder is generally impure, but the output of
fixed-output derivations is by definition pure (since we
already know the cryptographic hash of the output). */
if (fixedOutput) {
Strings varNames = tokenizeString<Strings>(get(drv->env, "impureEnvVars"));
for (auto & i : varNames) env[i] = getEnv(i);
}
}
void DerivationGoal::chownToBuilder(const Path & path)
{
if (!buildUser.enabled()) return;
if (chown(path.c_str(), buildUser.getUID(), buildUser.getGID()) == -1)
throw SysError(format("cannot change ownership of %1%") % path);
}
void DerivationGoal::doExportReferencesGraph() void DerivationGoal::doExportReferencesGraph()
{ {
/* The `exportReferencesGraph' feature allows the references graph /* The `exportReferencesGraph' feature allows the references graph