1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-16 07:22:43 +01:00

LocalStore: Allow the physical and logical store directories to differ

This is primarily to subsume the functionality of the
copy-from-other-stores substituter. For example, in the NixOS
installer, we can now do (assuming we're in the target chroot, and the
Nix store of the installation CD is bind-mounted on /tmp/nix):

  $ nix-build ... --option substituters 'local?state=/tmp/nix/var&real=/tmp/nix/store'

However, unlike copy-from-other-stores, this also allows write access
to such a store. One application might be fetching substitutes for
/nix/store in a situation where the user doesn't have sufficient
privileges to create /nix, e.g.:

  $ NIX_REMOTE="local?state=/home/alice/nix/var&real=/home/alice/nix/store" nix-build ...
This commit is contained in:
Eelco Dolstra 2016-06-02 15:08:18 +02:00
parent 064816ab98
commit 4494000e04
7 changed files with 68 additions and 158 deletions

View file

@ -38,10 +38,12 @@ namespace nix {
LocalStore::LocalStore(const Params & params)
: LocalFSStore(params)
, realStoreDir(get(params, "real", storeDir))
, dbDir(get(params, "state", "") != "" ? get(params, "state", "") + "/db" : settings.nixDBPath)
, linksDir(storeDir + "/.links")
, linksDir(realStoreDir + "/.links")
, reservedPath(dbDir + "/reserved")
, schemaPath(dbDir + "/schema")
, trashDir(realStoreDir + "/trash")
, requireSigs(settings.get("signed-binary-caches", std::string("")) != "") // FIXME: rename option
, publicKeys(getDefaultPublicKeys())
{
@ -53,7 +55,7 @@ LocalStore::LocalStore(const Params & params)
}
/* Create missing state directories if they don't already exist. */
createDirs(storeDir);
createDirs(realStoreDir);
makeStoreWritable();
createDirs(linksDir);
Path profilesDir = stateDir + "/profiles";
@ -83,21 +85,21 @@ LocalStore::LocalStore(const Params & params)
% settings.buildUsersGroup);
else {
struct stat st;
if (stat(storeDir.c_str(), &st))
throw SysError(format("getting attributes of path %1%") % storeDir);
if (stat(realStoreDir.c_str(), &st))
throw SysError(format("getting attributes of path %1%") % realStoreDir);
if (st.st_uid != 0 || st.st_gid != gr->gr_gid || (st.st_mode & ~S_IFMT) != perm) {
if (chown(storeDir.c_str(), 0, gr->gr_gid) == -1)
throw SysError(format("changing ownership of path %1%") % storeDir);
if (chmod(storeDir.c_str(), perm) == -1)
throw SysError(format("changing permissions on path %1%") % storeDir);
if (chown(realStoreDir.c_str(), 0, gr->gr_gid) == -1)
throw SysError(format("changing ownership of path %1%") % realStoreDir);
if (chmod(realStoreDir.c_str(), perm) == -1)
throw SysError(format("changing permissions on path %1%") % realStoreDir);
}
}
}
/* Ensure that the store and its parents are not symlinks. */
if (getEnv("NIX_IGNORE_SYMLINK_STORE") != "1") {
Path path = storeDir;
Path path = realStoreDir;
struct stat st;
while (path != "/") {
if (lstat(path.c_str(), &st))
@ -343,15 +345,15 @@ void LocalStore::makeStoreWritable()
if (getuid() != 0) return;
/* Check if /nix/store is on a read-only mount. */
struct statvfs stat;
if (statvfs(storeDir.c_str(), &stat) != 0)
if (statvfs(realStoreDir.c_str(), &stat) != 0)
throw SysError("getting info about the Nix store mount point");
if (stat.f_flag & ST_RDONLY) {
if (unshare(CLONE_NEWNS) == -1)
throw SysError("setting up a private mount namespace");
if (mount(0, storeDir.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
throw SysError(format("remounting %1% writable") % storeDir);
if (mount(0, realStoreDir.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
throw SysError(format("remounting %1% writable") % realStoreDir);
}
#endif
}
@ -917,23 +919,25 @@ void LocalStore::addToStore(const ValidPathInfo & info, const std::string & nar,
PathLocks outputLock;
Path realPath = realStoreDir + "/" + baseNameOf(info.path);
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
lock on this path). */
Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS"));
if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end())
outputLock.lockPaths({info.path});
outputLock.lockPaths({realPath});
if (repair || !isValidPath(info.path)) {
deletePath(info.path);
deletePath(realPath);
StringSource source(nar);
restorePath(info.path, source);
restorePath(realPath, source);
canonicalisePathMetaData(info.path, -1);
canonicalisePathMetaData(realPath, -1);
optimisePath(info.path); // FIXME: combine with hashPath()
optimisePath(realPath); // FIXME: combine with hashPath()
registerValidPath(info);
}
@ -957,19 +961,21 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
/* The first check above is an optimisation to prevent
unnecessary lock acquisition. */
PathLocks outputLock({dstPath});
Path realPath = realStoreDir + "/" + baseNameOf(dstPath);
PathLocks outputLock({realPath});
if (repair || !isValidPath(dstPath)) {
deletePath(dstPath);
deletePath(realPath);
if (recursive) {
StringSource source(dump);
restorePath(dstPath, source);
restorePath(realPath, source);
} else
writeFile(dstPath, dump);
writeFile(realPath, dump);
canonicalisePathMetaData(dstPath, -1);
canonicalisePathMetaData(realPath, -1);
/* Register the SHA-256 hash of the NAR serialisation of
the path in the database. We may just have computed it
@ -980,9 +986,9 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
hash.first = hashAlgo == htSHA256 ? h : hashString(htSHA256, dump);
hash.second = dump.size();
} else
hash = hashPath(htSHA256, dstPath);
hash = hashPath(htSHA256, realPath);
optimisePath(dstPath); // FIXME: combine with hashPath()
optimisePath(realPath); // FIXME: combine with hashPath()
ValidPathInfo info;
info.path = dstPath;
@ -1026,21 +1032,23 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
if (repair || !isValidPath(dstPath)) {
PathLocks outputLock({dstPath});
Path realPath = realStoreDir + "/" + baseNameOf(dstPath);
PathLocks outputLock({realPath});
if (repair || !isValidPath(dstPath)) {
deletePath(dstPath);
deletePath(realPath);
writeFile(dstPath, s);
writeFile(realPath, s);
canonicalisePathMetaData(dstPath, -1);
canonicalisePathMetaData(realPath, -1);
StringSink sink;
dumpString(s, sink);
auto hash = hashString(htSHA256, *sink.s);
optimisePath(dstPath);
optimisePath(realPath);
ValidPathInfo info;
info.path = dstPath;
@ -1067,7 +1075,7 @@ Path LocalStore::createTempDirInStore()
/* There is a slight possibility that `tmpDir' gets deleted by
the GC between createTempDir() and addTempRoot(), so repeat
until `tmpDir' exists. */
tmpDir = createTempDir(storeDir);
tmpDir = createTempDir(realStoreDir);
addTempRoot(tmpDir);
} while (!pathExists(tmpDir));
return tmpDir;
@ -1107,7 +1115,7 @@ bool LocalStore::verifyStore(bool checkContents, bool repair)
AutoCloseFD fdGCLock = openGCLock(ltWrite);
PathSet store;
for (auto & i : readDirectory(storeDir)) store.insert(i.name);
for (auto & i : readDirectory(realStoreDir)) store.insert(i.name);
/* Check whether all valid paths actually exist. */
printMsg(lvlInfo, "checking path existence...");
@ -1271,7 +1279,7 @@ void LocalStore::upgradeStore7()
{
if (getuid() != 0) return;
printMsg(lvlError, "removing immutable bits from the Nix store (this may take a while)...");
makeMutable(storeDir);
makeMutable(realStoreDir);
}
#else