diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml index daaf00ac3..3362e3e28 100644 --- a/doc/manual/command-ref/conf-file.xml +++ b/doc/manual/command-ref/conf-file.xml @@ -268,7 +268,12 @@ flag, e.g. --option gc-keep-outputs false. to mount a path in a different location in the sandbox; for instance, /bin=/nix-bin will mount the path /nix-bin as /bin inside the - sandbox. + sandbox. If source is followed by + ?, then it is not an error if + source does not exist; for example, + /dev/nvidiactl? specifies that + /dev/nvidiactl will only be mounted in the + sandbox if it exists in the host filesystem. Depending on how Nix was built, the default value for this option may be empty or provide /bin/sh as a diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 4e7b66657..4996a71c4 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -761,7 +761,14 @@ private: GoalState state; /* Stuff we need to pass to initChild(). */ - typedef map DirsInChroot; // maps target path to source path + struct ChrootPath { + Path source; + bool optional; + ChrootPath(Path source = "", bool optional = false) + : source(source), optional(optional) + { } + }; + typedef map DirsInChroot; // maps target path to source path DirsInChroot dirsInChroot; typedef map Environment; Environment env; @@ -1924,20 +1931,30 @@ void DerivationGoal::startBuilder() dirsInChroot.clear(); - for (auto & i : dirs) { + for (auto i : dirs) { + if (i.empty()) continue; + bool optional = false; + if (i[i.size() - 1] == '?') { + optional = true; + i.pop_back(); + } size_t p = i.find('='); if (p == string::npos) - dirsInChroot[i] = i; + dirsInChroot[i] = {i, optional}; else - dirsInChroot[string(i, 0, p)] = string(i, p + 1); + dirsInChroot[string(i, 0, p)] = {string(i, p + 1), optional}; } dirsInChroot[tmpDirInSandbox] = tmpDir; /* Add the closure of store paths to the chroot. */ PathSet closure; for (auto & i : dirsInChroot) - if (isInStore(i.second)) - computeFSClosure(worker.store, toStorePath(i.second), closure); + try { + if (isInStore(i.second.source)) + computeFSClosure(worker.store, toStorePath(i.second.source), closure); + } catch (Error & e) { + throw Error(format("while processing ‘build-sandbox-paths’: %s") % e.what()); + } for (auto & i : closure) dirsInChroot[i] = i; @@ -2328,12 +2345,16 @@ void DerivationGoal::runChild() environment. */ for (auto & i : dirsInChroot) { struct stat st; - Path source = i.second; + Path source = i.second.source; Path target = chrootRootDir + i.first; if (source == "/proc") continue; // backwards compatibility debug(format("bind mounting ‘%1%’ to ‘%2%’") % source % target); - if (stat(source.c_str(), &st) == -1) - throw SysError(format("getting attributes of path ‘%1%’") % source); + if (stat(source.c_str(), &st) == -1) { + if (i.second.optional && errno == ENOENT) + continue; + else + throw SysError(format("getting attributes of path ‘%1%’") % source); + } if (S_ISDIR(st.st_mode)) createDirs(target); else {