nix-shell: Fix $PATH handling in the impure case
We were passing "p=$PATH" rather than "p=$PATH;", resulting in some invalid shell code. Also, construct a separate environment for the child rather than overwriting the parent's.
This commit is contained in:
parent
9fc4cb2ae9
commit
4de0639105
3 changed files with 55 additions and 29 deletions
|
@ -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)
|
Path absPath(Path path, Path dir)
|
||||||
{
|
{
|
||||||
if (path[0] != '/') {
|
if (path[0] != '/') {
|
||||||
|
|
|
@ -8,9 +8,11 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
|
#ifndef HAVE_STRUCT_DIRENT_D_TYPE
|
||||||
#define DT_UNKNOWN 0
|
#define DT_UNKNOWN 0
|
||||||
|
@ -25,6 +27,9 @@ namespace nix {
|
||||||
/* Return an environment variable. */
|
/* Return an environment variable. */
|
||||||
string getEnv(const string & key, const string & def = "");
|
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
|
/* Return an absolutized path, resolving paths relative to the
|
||||||
specified directory, or the current directory otherwise. The path
|
specified directory, or the current directory otherwise. The path
|
||||||
is also canonicalised. */
|
is also canonicalised. */
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
extern char ** environ;
|
|
||||||
|
|
||||||
/* Recreate the effect of the perl shellwords function, breaking up a
|
/* Recreate the effect of the perl shellwords function, breaking up a
|
||||||
* string into arguments like a shell word, including escapes
|
* string into arguments like a shell word, including escapes
|
||||||
*/
|
*/
|
||||||
|
@ -375,32 +373,26 @@ int main(int argc, char ** argv)
|
||||||
runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
|
runProgram(settings.nixBinDir + "/nix-store", false, nixStoreArgs);
|
||||||
|
|
||||||
// Set the environment.
|
// Set the environment.
|
||||||
|
auto env = getEnv();
|
||||||
|
|
||||||
auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp"));
|
auto tmp = getEnv("TMPDIR", getEnv("XDG_RUNTIME_DIR", "/tmp"));
|
||||||
|
|
||||||
if (pure) {
|
if (pure) {
|
||||||
std::vector<string> skippedEnv{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
|
std::set<string> keepVars{"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL"};
|
||||||
std::vector<string> removed;
|
decltype(env) newEnv;
|
||||||
for (auto i = size_t{0}; environ[i]; ++i) {
|
for (auto & i : env)
|
||||||
auto eq = strchr(environ[i], '=');
|
if (keepVars.count(i.first))
|
||||||
if (!eq)
|
newEnv.emplace(i);
|
||||||
// invalid env, just keep going
|
env = newEnv;
|
||||||
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());
|
|
||||||
// NixOS hack: prevent /etc/bashrc from sourcing /etc/profile.
|
// 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);
|
env["NIX_BUILD_TOP"] = env["TMPDIR"] = env["TEMPDIR"] = env["TMP"] = env["TEMP"] = tmp;
|
||||||
setenv("TEMPDIR", tmp.c_str(), 1);
|
env["NIX_STORE"] = store->storeDir;
|
||||||
setenv("TMP", tmp.c_str(), 1);
|
|
||||||
setenv("TEMP", tmp.c_str(), 1);
|
for (auto & var : drv.env)
|
||||||
setenv("NIX_STORE", store->storeDir.c_str(), 1);
|
env.emplace(var);
|
||||||
for (const auto & env : drv.env)
|
|
||||||
setenv(env.first.c_str(), env.second.c_str(), 1);
|
|
||||||
|
|
||||||
restoreAffinity();
|
restoreAffinity();
|
||||||
|
|
||||||
|
@ -424,11 +416,25 @@ int main(int argc, char ** argv)
|
||||||
"shopt -u nullglob; "
|
"shopt -u nullglob; "
|
||||||
"unset TZ; %4%"
|
"unset TZ; %4%"
|
||||||
"%5%"
|
"%5%"
|
||||||
) % (Path) tmpDir % (pure ? "" : "p=$PATH") % (pure ? "" : "PATH=$PATH:$p; unset p; ") % (getenv("TZ") ? (string("export TZ='") + getenv("TZ") + "'; ") : "") % envCommand).str());
|
)
|
||||||
if (interactive)
|
% (Path) tmpDir
|
||||||
execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", "--rcfile", rcfile.c_str(), NULL);
|
% (pure ? "" : "p=$PATH; ")
|
||||||
else
|
% (pure ? "" : "PATH=$PATH:$p; unset p; ")
|
||||||
execlp(getEnv("NIX_BUILD_SHELL", "bash").c_str(), "bash", rcfile.c_str(), NULL);
|
% (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");
|
throw SysError("executing shell");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue