diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libexpr/parser.y | 2 | ||||
-rw-r--r-- | src/libstore/build.cc | 14 | ||||
-rw-r--r-- | src/libstore/gc.cc | 115 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 7 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 9 | ||||
-rw-r--r-- | src/libstore/remote-store.cc | 2 | ||||
-rw-r--r-- | src/libstore/store-api.cc | 1 | ||||
-rw-r--r-- | src/libstore/store-api.hh | 4 | ||||
-rw-r--r-- | src/nix-env/help.txt | 2 | ||||
-rw-r--r-- | src/nix-env/user-env.cc | 1 | ||||
-rw-r--r-- | src/nix-instantiate/nix-instantiate.cc | 15 | ||||
-rw-r--r-- | src/nix-store/help.txt | 2 | ||||
-rw-r--r-- | src/nix-store/nix-store.cc | 1 | ||||
-rw-r--r-- | src/nix-worker/nix-worker.cc | 6 |
14 files changed, 122 insertions, 59 deletions
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 449123a1f82c..095e288430f6 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -8,6 +8,8 @@ %parse-param { ParseData * data } %lex-param { yyscan_t scanner } %lex-param { ParseData * data } +%expect 1 +%expect-rr 1 %code requires { diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 467f16597440..77e968ddd08e 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1793,11 +1793,25 @@ void DerivationGoal::startBuilder() if (chdir(tmpDir.c_str()) == -1) throw SysError(format("changing into `%1%'") % tmpDir); + /* Close all other file descriptors. */ + closeMostFDs(set<int>()); + #ifdef CAN_DO_LINUX32_BUILDS + /* Change the personality to 32-bit if we're doing an + i686-linux build on an x86_64-linux machine. */ if (drv.platform == "i686-linux" && thisSystem == "x86_64-linux") { if (personality(0x0008 | 0x8000000 /* == PER_LINUX32_3GB */) == -1) throw SysError("cannot set i686-linux personality"); } + + /* Impersonate a Linux 2.6 machine to get some determinism + in builds that depend on the kernel version. */ + if ((drv.platform == "i686-linux" || drv.platform == "x86_64-linux") && + queryBoolSetting("build-impersonate-linux-26", true)) + { + int cur = personality(0xffffffff); + if (cur != -1) personality(cur | 0x0020000 /* == UNAME26 */); + } #endif /* Fill in the environment. */ diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 95c7154110b3..f6ed7dd2264e 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -1,6 +1,7 @@ #include "globals.hh" #include "misc.hh" #include "local-store.hh" +#include "immutable.hh" #include <boost/shared_ptr.hpp> @@ -55,24 +56,22 @@ int LocalStore::openGCLock(LockType lockType) } -void createSymlink(const Path & link, const Path & target, bool careful) +void createSymlink(const Path & link, const Path & target) { /* Create directories up to `gcRoot'. */ createDirs(dirOf(link)); - /* !!! shouldn't removing and creating the symlink be atomic? */ - - /* Remove the old symlink. */ - if (pathExists(link)) { - if (careful && (!isLink(link) || !isInStore(readLink(link)))) - throw Error(format("cannot create symlink `%1%'; already exists") % link); - unlink(link.c_str()); - } - - /* And create the new one. */ - if (symlink(target.c_str(), link.c_str()) == -1) + /* Create the new symlink. */ + Path tempLink = (format("%1%.tmp-%2%-%3%") + % link % getpid() % rand()).str(); + if (symlink(target.c_str(), tempLink.c_str()) == -1) throw SysError(format("symlinking `%1%' to `%2%'") - % link % target); + % tempLink % target); + + /* Atomically replace the old one. */ + if (rename(tempLink.c_str(), link.c_str()) == -1) + throw SysError(format("cannot rename `%1%' to `%2%'") + % tempLink % link); } @@ -87,7 +86,7 @@ void LocalStore::addIndirectRoot(const Path & path) string hash = printHash32(hashString(htSHA1, path)); Path realRoot = canonPath((format("%1%/%2%/auto/%3%") % nixStateDir % gcRootsDir % hash).str()); - createSymlink(realRoot, path, false); + createSymlink(realRoot, path); } @@ -104,7 +103,11 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath, "(are you running nix-build inside the store?)") % gcRoot); if (indirect) { - createSymlink(gcRoot, storePath, true); + /* Don't clobber the the link if it already exists and doesn't + point to the Nix store. */ + if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) + throw Error(format("cannot create symlink `%1%'; already exists") % gcRoot); + createSymlink(gcRoot, storePath); store.addIndirectRoot(gcRoot); } @@ -119,7 +122,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath, % gcRoot % rootsDir); } - createSymlink(gcRoot, storePath, false); + createSymlink(gcRoot, storePath); } /* Check that the root can be found by the garbage collector. @@ -396,11 +399,11 @@ struct LocalStore::GCState PathSet deleted; PathSet live; PathSet busy; + PathSet invalidated; bool gcKeepOutputs; bool gcKeepDerivations; - GCState(GCResults & results_) : results(results_) - { - } + unsigned long long bytesInvalidated; + GCState(GCResults & results_) : results(results_), bytesInvalidated(0) { } }; @@ -418,12 +421,27 @@ bool LocalStore::isActiveTempFile(const GCState & state, && state.tempRoots.find(string(path, 0, path.size() - suffix.size())) != state.tempRoots.end(); } - + +void LocalStore::deleteGarbage(GCState & state, const Path & path) +{ + printMsg(lvlInfo, format("deleting `%1%'") % path); + unsigned long long bytesFreed, blocksFreed; + deletePathWrapped(path, bytesFreed, blocksFreed); + state.results.bytesFreed += bytesFreed; + state.results.blocksFreed += blocksFreed; +} + + bool LocalStore::tryToDelete(GCState & state, const Path & path) { checkInterrupt(); - - if (!pathExists(path)) return true; + + struct stat st; + if (lstat(path.c_str(), &st)) { + if (errno == ENOENT) return true; + throw SysError(format("getting status of %1%") % path); + } + if (state.deleted.find(path) != state.deleted.end()) return true; if (state.live.find(path) != state.live.end()) return false; @@ -502,28 +520,39 @@ bool LocalStore::tryToDelete(GCState & state, const Path & path) /* The path is garbage, so delete it. */ if (shouldDelete(state.options.action)) { - printMsg(lvlInfo, format("deleting `%1%'") % path); - unsigned long long bytesFreed, blocksFreed; - deleteFromStore(path, bytesFreed, blocksFreed); - state.results.bytesFreed += bytesFreed; - state.results.blocksFreed += blocksFreed; + /* If it's a valid path that's not a regular file or symlink, + invalidate it, rename it, and schedule it for deletion. + The renaming is to ensure that later (when we're not + holding the global GC lock) we can delete the path without + being afraid that the path has become alive again. + Otherwise delete it right away. */ + if (isValidPath(path)) { + if (S_ISDIR(st.st_mode)) { + printMsg(lvlInfo, format("invalidating `%1%'") % path); + // Estimate the amount freed using the narSize field. + state.bytesInvalidated += queryPathInfo(path).narSize; + invalidatePathChecked(path); + makeMutable(path.c_str()); + // Mac OS X cannot rename directories if they are read-only. + if (chmod(path.c_str(), st.st_mode | S_IWUSR) == -1) + throw SysError(format("making `%1%' writable") % path); + Path tmp = (format("%1%-gc-%2%") % path % getpid()).str(); + if (rename(path.c_str(), tmp.c_str())) + throw SysError(format("unable to rename `%1%' to `%2%'") % path % tmp); + state.invalidated.insert(tmp); + } else { + invalidatePathChecked(path); + deleteGarbage(state, path); + } + } else + deleteGarbage(state, path); - if (state.options.maxFreed && state.results.bytesFreed > state.options.maxFreed) { - printMsg(lvlInfo, format("deleted more than %1% bytes; stopping") % state.options.maxFreed); + if (state.options.maxFreed && state.results.bytesFreed + state.bytesInvalidated > state.options.maxFreed) { + printMsg(lvlInfo, format("deleted or invalidated more than %1% bytes; stopping") % state.options.maxFreed); throw GCLimitReached(); } - if (state.options.maxLinks) { - struct stat st; - if (stat(nixStore.c_str(), &st) == -1) - throw SysError(format("statting `%1%'") % nixStore); - if (st.st_nlink < state.options.maxLinks) { - printMsg(lvlInfo, format("link count on the store has dropped below %1%; stopping") % state.options.maxLinks); - throw GCLimitReached(); - } - } - } else printMsg(lvlTalkative, format("would delete `%1%'") % path); @@ -645,6 +674,14 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) } catch (GCLimitReached & e) { } } + + /* Allow other processes to add to the store from here on. */ + fdGCLock.close(); + + /* Delete the invalidated paths now that the lock has been + released. */ + foreach (PathSet::iterator, i, state.invalidated) + deleteGarbage(state, *i); } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index ca541e1cce2e..f04436b7f659 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -1386,11 +1386,8 @@ Paths LocalStore::importPaths(bool requireSignature, Source & source) } -void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFreed, - unsigned long long & blocksFreed) +void LocalStore::invalidatePathChecked(const Path & path) { - bytesFreed = 0; - assertStorePath(path); while (1) { @@ -1410,8 +1407,6 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr break; } catch (SQLiteBusy & e) { }; } - - deletePathWrapped(path, bytesFreed, blocksFreed); } diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 2739c4eea69d..8e3cbe5ce11b 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -164,10 +164,6 @@ public: void collectGarbage(const GCOptions & options, GCResults & results); - /* Delete a path from the Nix store. */ - void deleteFromStore(const Path & path, unsigned long long & bytesFreed, - unsigned long long & blocksFreed); - /* Optimise the disk space usage of the Nix store by hard-linking files with the same contents. */ void optimiseStore(bool dryRun, OptimiseStats & stats); @@ -238,6 +234,9 @@ private: void invalidatePath(const Path & path); + /* Delete a path from the Nix store. */ + void invalidatePathChecked(const Path & path); + void verifyPath(const Path & path, const PathSet & store, PathSet & done, PathSet & validPaths); @@ -249,6 +248,8 @@ private: struct GCState; + void deleteGarbage(GCState & state, const Path & path); + bool tryToDelete(GCState & state, const Path & path); bool isActiveTempFile(const GCState & state, diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index c77a12870513..0b8fa36f6df4 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -466,7 +466,7 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results) writeStrings(options.pathsToDelete, to); writeInt(options.ignoreLiveness, to); writeLongLong(options.maxFreed, to); - writeInt(options.maxLinks, to); + writeInt(0, to); if (GET_PROTOCOL_MINOR(daemonVersion) >= 5) { /* removed options */ writeInt(0, to); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 36ade2170876..19bc048abd02 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -13,7 +13,6 @@ GCOptions::GCOptions() action = gcDeleteDead; ignoreLiveness = false; maxFreed = 0; - maxLinks = 0; } diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 61bcaf50507f..a62a648168f9 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -53,10 +53,6 @@ struct GCOptions no limit. */ unsigned long long maxFreed; - /* Stop after the number of hard links to the Nix store directory - has dropped below `maxLinks'. */ - unsigned int maxLinks; - GCOptions(); }; diff --git a/src/nix-env/help.txt b/src/nix-env/help.txt index 605bf2810a42..0ebdca9b22a5 100644 --- a/src/nix-env/help.txt +++ b/src/nix-env/help.txt @@ -69,6 +69,8 @@ Options: --file / -f FILE: use Nix expression FILE for installation, etc. --verbose / -v: verbose operation (may be repeated) --keep-failed / -K: keep temporary directories of failed builds + --keep-going / -k: build as many dependencies as possible, even if + some dependencies fail to build --preserve-installed: do not replace currently installed versions in `-i' --system-filter SYSTEM: only use derivations for specified platform --prebuilt-only / -b: only use derivations whose prebuilt binaries are diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 0dcdcc0d186f..4480a17aa923 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -118,7 +118,6 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, builder with the manifest as argument. */ Value args, topLevel; state.mkAttrs(args, 3); - mkString(*state.allocAttr(args, state.sSystem), thisSystem); mkString(*state.allocAttr(args, state.symbols.create("manifest")), manifestFile, singleton<PathSet>(manifestFile)); args.attrs->push_back(Attr(state.symbols.create("derivations"), &manifest)); diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 8f3a290f3a6a..d86c9fc84572 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -79,6 +79,7 @@ void run(Strings args) EvalState state; Strings files; bool readStdin = false; + bool findFile = false; bool evalOnly = false; bool parseOnly = false; bool xmlOutput = false; @@ -100,6 +101,8 @@ void run(Strings args) readOnlyMode = true; parseOnly = evalOnly = true; } + else if (arg == "--find-file") + findFile = true; else if (arg == "--attr" || arg == "-A") { if (i == args.end()) throw UsageError("`--attr' requires an argument"); @@ -130,13 +133,23 @@ void run(Strings args) if (attrPaths.empty()) attrPaths.push_back(""); + if (findFile) { + foreach (Strings::iterator, i, files) { + Path p = state.findFile(*i); + if (p == "") throw Error(format("unable to find `%1%'") % *i); + std::cout << p << std::endl; + } + return; + } + store = openStore(); if (readStdin) { Expr * e = parseStdin(state); processExpr(state, attrPaths, parseOnly, strict, autoArgs, evalOnly, xmlOutput, xmlOutputSourceLocation, e); - } + } else if (files.empty()) + files.push_back("./default.nix"); foreach (Strings::iterator, i, files) { Expr * e = state.parseExprFromFile(lookupFileArg(state, *i)); diff --git a/src/nix-store/help.txt b/src/nix-store/help.txt index f3e65a5283b9..ed4a29a67e17 100644 --- a/src/nix-store/help.txt +++ b/src/nix-store/help.txt @@ -65,5 +65,7 @@ Options: --verbose / -v: verbose operation (may be repeated) --keep-failed / -K: keep temporary directories of failed builds + --keep-going / -k: build as many dependencies as possible, even if + some dependencies fail to build --add-root: add garbage collector roots for the result diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 404da2c51f51..fa96725b1b48 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -562,7 +562,6 @@ static void opGC(Strings opFlags, Strings opArgs) long long maxFreed = getIntArg<long long>(*i, i, opFlags.end()); options.maxFreed = maxFreed >= 1 ? maxFreed : 1; } - else if (*i == "--max-links") options.maxLinks = getIntArg<unsigned int>(*i, i, opFlags.end()); else throw UsageError(format("bad sub-operation `%1%' in GC") % *i); if (!opArgs.empty()) throw UsageError("no arguments expected"); diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc index f5201ab6a561..4b0c9e319130 100644 --- a/src/nix-worker/nix-worker.cc +++ b/src/nix-worker/nix-worker.cc @@ -477,7 +477,7 @@ static void performOp(unsigned int clientVersion, options.pathsToDelete = readStorePaths<PathSet>(from); options.ignoreLiveness = readInt(from); options.maxFreed = readLongLong(from); - options.maxLinks = readInt(from); + readInt(from); // obsolete field if (GET_PROTOCOL_MINOR(clientVersion) >= 5) { /* removed options */ readInt(from); @@ -697,6 +697,8 @@ static void daemonLoop() if (fdSocket == -1) throw SysError("cannot create Unix domain socket"); + closeOnExec(fdSocket); + string socketPath = nixStateDir + DEFAULT_SOCKET_PATH; createDirs(dirOf(socketPath)); @@ -751,6 +753,8 @@ static void daemonLoop() throw SysError("accepting connection"); } + closeOnExec(remote); + /* Get the identity of the caller, if possible. */ uid_t clientUid = -1; pid_t clientPid = -1; |