diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rwxr-xr-x | scripts/copy-from-other-stores.pl.in | 103 | ||||
-rw-r--r-- | src/libstore/build.cc | 3 | ||||
-rw-r--r-- | src/libstore/gc.cc | 39 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 72 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/optimise-store.cc | 6 |
7 files changed, 68 insertions, 158 deletions
diff --git a/.gitignore b/.gitignore index a175e8dfe291..178783d22d36 100644 --- a/.gitignore +++ b/.gitignore @@ -44,7 +44,6 @@ Makefile.config /scripts/nix-copy-closure /scripts/NixConfig.pm /scripts/NixManifest.pm -/scripts/copy-from-other-stores.pl /scripts/download-from-binary-cache.pl /scripts/find-runtime-roots.pl /scripts/build-remote.pl diff --git a/scripts/copy-from-other-stores.pl.in b/scripts/copy-from-other-stores.pl.in deleted file mode 100755 index 9b0615fe1a10..000000000000 --- a/scripts/copy-from-other-stores.pl.in +++ /dev/null @@ -1,103 +0,0 @@ -#! @perl@ -w @perlFlags@ - -use utf8; -use strict; -use File::Basename; -use IO::Handle; - -my $binDir = $ENV{"NIX_BIN_DIR"} || "@bindir@"; - - -STDOUT->autoflush(1); -binmode STDERR, ":encoding(utf8)"; - -my @remoteStoresAll = split ':', ($ENV{"NIX_OTHER_STORES"} or ""); - -my @remoteStores; -foreach my $dir (@remoteStoresAll) { - push @remoteStores, glob($dir); -} - -exit if scalar @remoteStores == 0; -print "\n"; - - -$ENV{"NIX_REMOTE"} = ""; - - -sub findStorePath { - my $storePath = shift; - foreach my $store (@remoteStores) { - my $sourcePath = "$store/store/" . basename $storePath; - next unless -e $sourcePath || -l $sourcePath; - $ENV{"NIX_DB_DIR"} = "$store/var/nix/db"; - return ($store, $sourcePath) if - system("$binDir/nix-store --check-validity $storePath") == 0; - } - return undef; -} - - -if ($ARGV[0] eq "--query") { - - while (<STDIN>) { - chomp; - my ($cmd, @args) = split " ", $_; - - if ($cmd eq "have") { - foreach my $storePath (@args) { - print "$storePath\n" if defined findStorePath($storePath); - } - print "\n"; - } - - elsif ($cmd eq "info") { - foreach my $storePath (@args) { - my ($store, $sourcePath) = findStorePath($storePath); - next unless defined $store; - - $ENV{"NIX_DB_DIR"} = "$store/var/nix/db"; - - my $deriver = `$binDir/nix-store --query --deriver $storePath`; - die "cannot query deriver of ‘$storePath’" if $? != 0; - chomp $deriver; - $deriver = "" if $deriver eq "unknown-deriver"; - - my @references = split "\n", - `$binDir/nix-store --query --references $storePath`; - die "cannot query references of ‘$storePath’" if $? != 0; - - my $narSize = `$binDir/nix-store --query --size $storePath`; - die "cannot query size of ‘$storePath’" if $? != 0; - chomp $narSize; - - print "$storePath\n"; - print "$deriver\n"; - print scalar @references, "\n"; - print "$_\n" foreach @references; - print "0\n"; - print "$narSize\n"; - } - - print "\n"; - } - - else { die "unknown command ‘$cmd’"; } - } -} - - -elsif ($ARGV[0] eq "--substitute") { - die unless scalar @ARGV == 3; - my $storePath = $ARGV[1]; - my $destPath = $ARGV[2]; - my ($store, $sourcePath) = findStorePath $storePath; - die unless $store; - print STDERR "\n*** Copying ‘$storePath’ from ‘$sourcePath’\n\n"; - system("@coreutils@/cp", "-rpd", $sourcePath, $destPath) == 0 - or die "cannot copy ‘$sourcePath’ to ‘$storePath’"; - print "\n"; # no hash to verify -} - - -else { die; } diff --git a/src/libstore/build.cc b/src/libstore/build.cc index f232fe86a967..3233a8d5cd2a 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1269,6 +1269,9 @@ void DerivationGoal::tryToBuild() { trace("trying to build"); + if (worker.store.storeDir != worker.store.realStoreDir) + throw Error("building with a diverted Nix store is not supported"); + /* Check for the possibility that some other goal in this process has locked the output since we checked in haveDerivation(). (It can't happen between here and the lockPaths() call below diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index e5be048d8d81..77d13bbdcb8d 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -370,7 +370,6 @@ struct LocalStore::GCState bool gcKeepDerivations; unsigned long long bytesInvalidated; bool moveToTrash = true; - Path trashDir; bool shouldDelete; GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { } }; @@ -407,10 +406,12 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) invalidatePathChecked(path); } + Path realPath = realStoreDir + "/" + baseNameOf(path); + struct stat st; - if (lstat(path.c_str(), &st)) { + if (lstat(realPath.c_str(), &st)) { if (errno == ENOENT) return; - throw SysError(format("getting status of %1%") % path); + throw SysError(format("getting status of %1%") % realPath); } printMsg(lvlInfo, format("deleting ‘%1%’") % path); @@ -427,20 +428,20 @@ void LocalStore::deletePathRecursive(GCState & state, const Path & path) // if the path was not valid, need to determine the actual // size. try { - if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) - throw SysError(format("making ‘%1%’ writable") % path); - Path tmp = state.trashDir + "/" + baseNameOf(path); - if (rename(path.c_str(), tmp.c_str())) - throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % path % tmp); + if (chmod(realPath.c_str(), st.st_mode | S_IWUSR) == -1) + throw SysError(format("making ‘%1%’ writable") % realPath); + Path tmp = trashDir + "/" + baseNameOf(path); + if (rename(realPath.c_str(), tmp.c_str())) + throw SysError(format("unable to rename ‘%1%’ to ‘%2%’") % realPath % tmp); state.bytesInvalidated += size; } catch (SysError & e) { if (e.errNo == ENOSPC) { - printMsg(lvlInfo, format("note: can't create move ‘%1%’: %2%") % path % e.msg()); - deleteGarbage(state, path); + printMsg(lvlInfo, format("note: can't create move ‘%1%’: %2%") % realPath % e.msg()); + deleteGarbage(state, realPath); } } } else - deleteGarbage(state, path); + deleteGarbage(state, realPath); if (state.results.bytesFreed + state.bytesInvalidated > state.options.maxFreed) { printMsg(lvlInfo, format("deleted or invalidated more than %1% bytes; stopping") % state.options.maxFreed); @@ -508,7 +509,8 @@ void LocalStore::tryToDelete(GCState & state, const Path & path) { checkInterrupt(); - if (path == linksDir || path == state.trashDir) return; + auto realPath = realStoreDir + "/" + baseNameOf(path); + if (realPath == linksDir || realPath == trashDir) return; Activity act(*logger, lvlDebug, format("considering whether to delete ‘%1%’") % path); @@ -590,7 +592,6 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) { GCState state(results); state.options = options; - state.trashDir = storeDir + "/trash"; state.gcKeepOutputs = settings.gcKeepOutputs; state.gcKeepDerivations = settings.gcKeepDerivations; @@ -639,9 +640,9 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) that is not reachable from `roots' is garbage. */ if (state.shouldDelete) { - if (pathExists(state.trashDir)) deleteGarbage(state, state.trashDir); + if (pathExists(trashDir)) deleteGarbage(state, trashDir); try { - createDirs(state.trashDir); + createDirs(trashDir); } catch (SysError & e) { if (e.errNo == ENOSPC) { printMsg(lvlInfo, format("note: can't create trash directory: %1%") % e.msg()); @@ -671,8 +672,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) try { - AutoCloseDir dir = opendir(storeDir.c_str()); - if (!dir) throw SysError(format("opening directory ‘%1%’") % storeDir); + AutoCloseDir dir = opendir(realStoreDir.c_str()); + if (!dir) throw SysError(format("opening directory ‘%1%’") % realStoreDir); /* Read the store and immediately delete all paths that aren't valid. When using --max-freed etc., deleting @@ -725,8 +726,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) fds.clear(); /* Delete the trash directory. */ - printMsg(lvlInfo, format("deleting ‘%1%’") % state.trashDir); - deleteGarbage(state, state.trashDir); + printMsg(lvlInfo, format("deleting ‘%1%’") % trashDir); + deleteGarbage(state, trashDir); /* Clean up the links directory. */ if (options.action == GCOptions::gcDeleteDead || options.action == GCOptions::gcDeleteSpecific) { diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 1ffacc5b035e..33df25c15833 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -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 diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 5166c04e5319..3a2568ec9479 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -73,10 +73,12 @@ private: Sync<State, std::recursive_mutex> _state; + const Path realStoreDir; const Path dbDir; const Path linksDir; const Path reservedPath; const Path schemaPath; + const Path trashDir; bool requireSigs; diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 33f002f9dbb1..927478121244 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -176,7 +176,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa /* Make the containing directory writable, but only if it's not the store itself (we don't want or need to mess with its permissions). */ - bool mustToggle = !isStorePath(path); + bool mustToggle = dirOf(path) != realStoreDir; if (mustToggle) makeWritable(dirOf(path)); /* When we're done, make the directory read-only again and reset @@ -184,7 +184,7 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path, InodeHa MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : ""); Path tempLink = (format("%1%/.tmp-link-%2%-%3%") - % storeDir % getpid() % rand()).str(); + % realStoreDir % getpid() % rand()).str(); if (link(linkPath.c_str(), tempLink.c_str()) == -1) { if (errno == EMLINK) { @@ -229,7 +229,7 @@ void LocalStore::optimiseStore(OptimiseStats & stats) addTempRoot(i); if (!isValidPath(i)) continue; /* path was GC'ed, probably */ Activity act(*logger, lvlChatty, format("hashing files in ‘%1%’") % i); - optimisePath_(stats, i, inodeHash); + optimisePath_(stats, realStoreDir + "/" + baseNameOf(i), inodeHash); } } |