about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/download.cc4
-rw-r--r--src/libstore/http-binary-cache-store.cc4
-rw-r--r--src/libutil/util.cc19
-rw-r--r--src/libutil/util.hh8
-rwxr-xr-xsrc/nix-build/nix-build.cc80
5 files changed, 74 insertions, 41 deletions
diff --git a/src/libstore/download.cc b/src/libstore/download.cc
index ca324595a300..d7d0e29c0626 100644
--- a/src/libstore/download.cc
+++ b/src/libstore/download.cc
@@ -98,7 +98,7 @@ struct CurlDownloader : public Downloader
         {
             assert(!done);
             done = true;
-            failure(std::make_exception_ptr(e));
+            callFailure(failure, std::make_exception_ptr(e));
         }
 
         size_t writeCallback(void * contents, size_t size, size_t nmemb)
@@ -241,8 +241,8 @@ struct CurlDownloader : public Downloader
                 (httpStatus == 200 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
             {
                 result.cached = httpStatus == 304;
-                success(result);
                 done = true;
+                callSuccess(success, failure, const_cast<const DownloadResult &>(result));
             } else {
                 Error err =
                     (httpStatus == 404 || code == CURLE_FILE_COULDNT_READ_FILE) ? NotFound :
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 60728de04c9c..74ae7a4d198a 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -86,7 +86,9 @@ protected:
                     std::rethrow_exception(exc);
                 } catch (DownloadError & e) {
                     if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden)
-                        success(0);
+                        return success(0);
+                    failure(exc);
+                } catch (...) {
                     failure(exc);
                 }
             });
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 1750e03737b7..68311a3df8ef 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -59,6 +59,21 @@ string getEnv(const string & key, const string & def)
 }
 
 
+std::map<std::string, std::string> getEnv()
+{
+    std::map<std::string, std::string> env;
+    for (size_t i = 0; environ[i]; ++i) {
+        auto s = environ[i];
+        auto eq = strchr(s, '=');
+        if (!eq)
+            // invalid env, just keep going
+            continue;
+        env.emplace(std::string(s, eq), std::string(eq + 1));
+    }
+    return env;
+}
+
+
 Path absPath(Path path, Path dir)
 {
     if (path[0] != '/') {
@@ -1215,10 +1230,10 @@ string base64Decode(const string & s)
 }
 
 
-void callFailure(const std::function<void(std::exception_ptr exc)> & failure)
+void callFailure(const std::function<void(std::exception_ptr exc)> & failure, std::exception_ptr exc)
 {
     try {
-        failure(std::current_exception());
+        failure(exc);
     } catch (std::exception & e) {
         printMsg(lvlError, format("uncaught exception: %s") % e.what());
         abort();
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 182a38fb3928..1a43bf400a03 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -8,9 +8,11 @@
 #include <dirent.h>
 #include <unistd.h>
 #include <signal.h>
+
 #include <functional>
 #include <limits>
 #include <cstdio>
+#include <map>
 
 #ifndef HAVE_STRUCT_DIRENT_D_TYPE
 #define DT_UNKNOWN 0
@@ -25,6 +27,9 @@ namespace nix {
 /* Return an environment variable. */
 string getEnv(const string & key, const string & def = "");
 
+/* Get the entire environment. */
+std::map<std::string, std::string> getEnv();
+
 /* Return an absolutized path, resolving paths relative to the
    specified directory, or the current directory otherwise.  The path
    is also canonicalised. */
@@ -378,7 +383,8 @@ string get(const T & map, const string & key, const string & def = "")
 
 /* Call ‘failure’ with the current exception as argument. If ‘failure’
    throws an exception, abort the program. */
-void callFailure(const std::function<void(std::exception_ptr exc)> & failure);
+void callFailure(const std::function<void(std::exception_ptr exc)> & failure,
+    std::exception_ptr exc = std::current_exception());
 
 
 /* Evaluate the function ‘f’. If it returns a value, call ‘success’
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 248474d5316a..eb5719e47fb2 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -1,20 +1,20 @@
 #include <cstring>
+#include <fstream>
+#include <iostream>
 #include <regex>
-#include "util.hh"
-#include <unistd.h>
-#include "shared.hh"
 #include <sstream>
 #include <vector>
-#include <iostream>
-#include <fstream>
+
+#include <unistd.h>
+
 #include "store-api.hh"
 #include "globals.hh"
 #include "derivations.hh"
+#include "affinity.hh"
+#include "util.hh"
+#include "shared.hh"
 
 using namespace nix;
-using std::stringstream;
-
-extern char ** environ;
 
 /* Recreate the effect of the perl shellwords function, breaking up a
  * string into arguments like a shell word, including escapes
@@ -373,32 +373,28 @@ int main(int argc, char ** argv)
                 runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
 
                 // Set the environment.
+                auto env = getEnv();
+
                 auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp"));
+
                 if (pure) {
-                    std::vector<string> skippedEnv{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
-                    std::vector<string> removed;
-                    for (auto i = size_t{0}; environ[i]; ++i) {
-                        auto eq = strchr(environ[i], '=');
-                        if (!eq)
-                            // invalid env, just keep going
-                            continue;
-                        std::string name(environ[i], eq);
-                        if (find(skippedEnv.begin(), skippedEnv.end(), name) == skippedEnv.end())
-                            removed.emplace_back(std::move(name));
-                    }
-                    for (const auto & name : removed)
-                        unsetenv(name.c_str());
+                    std::set<string> keepVars{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
+                    decltype(env) newEnv;
+                    for (auto & i : env)
+                        if (keepVars.count(i.first))
+                            newEnv.emplace(i);
+                    env = newEnv;
                     // NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
-                    setenv("__ETC_PROFILE_SOURCED", "1", 1);
+                    env["__ETC_PROFILE_SOURCED"] = "1";
                 }
-                setenv("NIX_BUILD_TOP", tmp.c_str(), 1);
-                setenv("TMPDIR", tmp.c_str(), 1);
-                setenv("TEMPDIR", tmp.c_str(), 1);
-                setenv("TMP", tmp.c_str(), 1);
-                setenv("TEMP", tmp.c_str(), 1);
-                setenv("NIX_STORE", store->storeDir.c_str(), 1);
-                for (const auto & env : drv.env)
-                    setenv(env.first.c_str(), env.second.c_str(), 1);
+
+                env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
+                env["NIX_STORE"] = store->storeDir;
+
+                for (auto & var : drv.env)
+                    env.emplace(var);
+
+                restoreAffinity();
 
                 // Run a shell using the derivation's environment.  For
                 // convenience, source $stdenv/setup to setup additional
@@ -420,11 +416,25 @@ int main(int argc, char ** argv)
                         "shopt -u nullglob; "
                         "unset TZ; %4%"
                         "%5%"
-                        ) % (Path) tmpDir % (pure ? "" : "p=$PATH") % (pure ? "" : "PATH=$PATH:$p; unset p; ") % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "") % envCommand).str());
-                if (interactive)
-                    execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", "--rcfile", rcfile.c_str(), NULL);
-                else
-                    execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", rcfile.c_str(), NULL);
+                        )
+                        % (Path) tmpDir
+                        % (pure ? "" : "p=$PATH; ")
+                        % (pure ? "" : "PATH=$PATH:$p; unset p; ")
+                        % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "")
+                        % envCommand).str());
+
+                Strings envStrs;
+                for (auto & i : env)
+                    envStrs.push_back(i.first + "=" + i.second);
+
+                auto args = interactive
+                    ? Strings{"bash", "--rcfile", rcfile}
+                    : Strings{"bash", rcfile};
+
+                execvpe(getEnv("NIX_BUILD_SHELL", "bash").c_str(),
+                        stringsToCharPtrs(args).data(),
+                        stringsToCharPtrs(envStrs).data());
+
                 throw SysError("executing shell");
             }