about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libexpr/parser.y2
-rw-r--r--src/libstore/build.cc14
-rw-r--r--src/libstore/gc.cc115
-rw-r--r--src/libstore/local-store.cc7
-rw-r--r--src/libstore/local-store.hh9
-rw-r--r--src/libstore/remote-store.cc2
-rw-r--r--src/libstore/store-api.cc1
-rw-r--r--src/libstore/store-api.hh4
-rw-r--r--src/nix-env/help.txt2
-rw-r--r--src/nix-env/user-env.cc1
-rw-r--r--src/nix-instantiate/nix-instantiate.cc15
-rw-r--r--src/nix-store/help.txt2
-rw-r--r--src/nix-store/nix-store.cc1
-rw-r--r--src/nix-worker/nix-worker.cc6
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;