diff options
-rw-r--r-- | src/libstore/download.cc | 4 | ||||
-rw-r--r-- | src/libstore/http-binary-cache-store.cc | 4 | ||||
-rw-r--r-- | src/libutil/util.cc | 19 | ||||
-rw-r--r-- | src/libutil/util.hh | 8 | ||||
-rwxr-xr-x | src/nix-build/nix-build.cc | 80 |
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"); } |