Use deterministic $TMPDIR in sandbox

Rather than using $<host-TMPDIR>/nix-build-<drvname>-<number>, the
temporary directory is now always /tmp/nix-build-<drvname>-0. This
improves bitwise-exact reproducibility for builds that store $TMPDIR
in their build output. (Of course, those should still be fixed...)
This commit is contained in:
Eelco Dolstra 2015-12-02 14:59:07 +01:00
parent f327970129
commit 8063fc497a

View file

@ -745,6 +745,9 @@ private:
/* The temporary directory. */ /* The temporary directory. */
Path tmpDir; Path tmpDir;
/* The path of the temporary directory in the sandbox. */
Path tmpDirInSandbox;
/* File descriptor for the log file. */ /* File descriptor for the log file. */
FILE * fLogFile = 0; FILE * fLogFile = 0;
BZFILE * bzLogFile = 0; BZFILE * bzLogFile = 0;
@ -1727,6 +1730,28 @@ void DerivationGoal::startBuilder()
% drv->platform % settings.thisSystem % drvPath); % drv->platform % settings.thisSystem % drvPath);
} }
/* Are we doing a chroot build? Note that fixed-output
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",
/* deprecated alias */
settings.get("build-use-chroot", string("false")));
if (x != "true" && x != "false" && x != "relaxed")
throw Error("option build-use-sandbox must be set to one of true, false or relaxed");
if (x == "true") {
if (get(drv->env, "__noChroot") == "1")
throw Error(format("derivation %1% has __noChroot set, but that's not allowed when build-use-sandbox is true") % drvPath);
useChroot = true;
}
else if (x == "false")
useChroot = false;
else if (x == "relaxed")
useChroot = !fixedOutput && get(drv->env, "__noChroot") != "1";
}
/* Construct the environment passed to the builder. */ /* Construct the environment passed to the builder. */
env.clear(); env.clear();
@ -1755,7 +1780,12 @@ void DerivationGoal::startBuilder()
/* Create a temporary directory where the build will take /* Create a temporary directory where the build will take
place. */ place. */
tmpDir = createTempDir("", "nix-build-" + storePathToName(drvPath), false, false, 0700); auto drvName = storePathToName(drvPath);
tmpDir = createTempDir("", "nix-build-" + drvName, false, false, 0700);
/* In a sandbox, for determinism, always use the same temporary
directory. */
tmpDirInSandbox = useChroot ? "/tmp/nix-build-" + drvName + "-0" : tmpDir;
/* Add all bindings specified in the derivation via the /* Add all bindings specified in the derivation via the
environments, except those listed in the passAsFile environments, except those listed in the passAsFile
@ -1777,16 +1807,16 @@ void DerivationGoal::startBuilder()
/* For convenience, set an environment pointing to the top build /* For convenience, set an environment pointing to the top build
directory. */ directory. */
env["NIX_BUILD_TOP"] = tmpDir; env["NIX_BUILD_TOP"] = tmpDirInSandbox;
/* Also set TMPDIR and variants to point to this directory. */ /* Also set TMPDIR and variants to point to this directory. */
env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDir; env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmpDirInSandbox;
/* Explicitly set PWD to prevent problems with chroot builds. In /* Explicitly set PWD to prevent problems with chroot builds. In
particular, dietlibc cannot figure out the cwd because the particular, dietlibc cannot figure out the cwd because the
inode of the current directory doesn't appear in .. (because inode of the current directory doesn't appear in .. (because
getdents returns the inode of the mount point). */ getdents returns the inode of the mount point). */
env["PWD"] = tmpDir; env["PWD"] = tmpDirInSandbox;
/* Compatibility hack with Nix <= 0.7: if this is a fixed-output /* Compatibility hack with Nix <= 0.7: if this is a fixed-output
derivation, tell the builder, so that for instance `fetchurl' derivation, tell the builder, so that for instance `fetchurl'
@ -1875,28 +1905,6 @@ void DerivationGoal::startBuilder()
} }
/* Are we doing a chroot build? Note that fixed-output
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",
/* deprecated alias */
settings.get("build-use-chroot", string("false")));
if (x != "true" && x != "false" && x != "relaxed")
throw Error("option build-use-sandbox must be set to one of true, false or relaxed");
if (x == "true") {
if (get(drv->env, "__noChroot") == "1")
throw Error(format("derivation %1% has __noChroot set, but that's not allowed when build-use-sandbox is true") % drvPath);
useChroot = true;
}
else if (x == "false")
useChroot = false;
else if (x == "relaxed")
useChroot = !fixedOutput && get(drv->env, "__noChroot") != "1";
}
if (useChroot) { if (useChroot) {
string defaultChrootDirs; string defaultChrootDirs;
@ -1925,7 +1933,7 @@ void DerivationGoal::startBuilder()
else else
dirsInChroot[string(i, 0, p)] = string(i, p + 1); dirsInChroot[string(i, 0, p)] = string(i, p + 1);
} }
dirsInChroot[tmpDir] = tmpDir; dirsInChroot[tmpDirInSandbox] = tmpDir;
/* Add the closure of store paths to the chroot. */ /* Add the closure of store paths to the chroot. */
PathSet closure; PathSet closure;
@ -2391,7 +2399,7 @@ void DerivationGoal::runChild()
} }
#endif #endif
if (chdir(tmpDir.c_str()) == -1) if (chdir(tmpDirInSandbox.c_str()) == -1)
throw SysError(format("changing into %1%") % tmpDir); throw SysError(format("changing into %1%") % tmpDir);
/* Close all other file descriptors. */ /* Close all other file descriptors. */