Make <nix/buildenv.nix> a builtin builder

This avoids sandbox annoyances.
This commit is contained in:
Eelco Dolstra 2018-03-20 17:28:09 +01:00
parent 9d40787938
commit 668ac3ea2c
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
7 changed files with 69 additions and 94 deletions

6
.gitignore vendored
View file

@ -13,9 +13,6 @@ perl/Makefile.config
/corepkgs/config.nix /corepkgs/config.nix
# /corepkgs/buildenv/
/corepkgs/buildenv/builder.pl
# /corepkgs/channels/ # /corepkgs/channels/
/corepkgs/channels/unpack.sh /corepkgs/channels/unpack.sh
@ -72,9 +69,6 @@ perl/Makefile.config
# /src/nix-channel/ # /src/nix-channel/
/src/nix-channel/nix-channel /src/nix-channel/nix-channel
# /src/buildenv/
/src/buildenv/buildenv
# /src/nix-build/ # /src/nix-build/
/src/nix-build/nix-build /src/nix-build/nix-build

View file

@ -12,7 +12,6 @@ makefiles = \
src/nix-collect-garbage/local.mk \ src/nix-collect-garbage/local.mk \
src/nix-copy-closure/local.mk \ src/nix-copy-closure/local.mk \
src/nix-prefetch-url/local.mk \ src/nix-prefetch-url/local.mk \
src/buildenv/local.mk \
src/resolve-system-dependencies/local.mk \ src/resolve-system-dependencies/local.mk \
src/nix-channel/local.mk \ src/nix-channel/local.mk \
src/nix-build/local.mk \ src/nix-build/local.mk \

View file

@ -1,11 +1,9 @@
with import <nix/config.nix>;
{ derivations, manifest }: { derivations, manifest }:
derivation { derivation {
name = "user-environment"; name = "user-environment";
system = builtins.currentSystem; system = "builtin";
builder = nixLibexecDir + "/nix/buildenv"; builder = "builtin:buildenv";
inherit manifest; inherit manifest;
@ -24,21 +22,4 @@ derivation {
# Also don't bother substituting. # Also don't bother substituting.
allowSubstitutes = false; allowSubstitutes = false;
__sandboxProfile = ''
(allow sysctl-read)
(allow file-read*
(literal "/usr/lib/libSystem.dylib")
(literal "/usr/lib/libSystem.B.dylib")
(literal "/usr/lib/libobjc.A.dylib")
(literal "/usr/lib/libobjc.dylib")
(literal "/usr/lib/libauto.dylib")
(literal "/usr/lib/libc++abi.dylib")
(literal "/usr/lib/libc++.1.dylib")
(literal "/usr/lib/libDiagnosticMessagesClient.dylib")
(subpath "/usr/lib/system")
(subpath "/dev"))
'';
inherit chrootDeps;
} }

View file

@ -1,9 +0,0 @@
programs += buildenv
buildenv_DIR := $(d)
buildenv_INSTALL_DIR := $(libexecdir)/nix
buildenv_LIBS = libmain libstore libutil libformat
buildenv_SOURCES := $(d)/buildenv.cc

View file

@ -2949,6 +2949,8 @@ void DerivationGoal::runChild()
if (drv->builder == "builtin:fetchurl") if (drv->builder == "builtin:fetchurl")
builtinFetchurl(drv2, netrcData); builtinFetchurl(drv2, netrcData);
else if (drv->builder == "builtin:buildenv")
builtinBuildenv(drv2);
else else
throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8)); throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8));
_exit(0); _exit(0);

View file

@ -4,6 +4,8 @@
namespace nix { namespace nix {
// TODO: make pluggable.
void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData); void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData);
void builtinBuildenv(const BasicDerivation & drv);
} }

View file

@ -1,14 +1,15 @@
#include "shared.hh" #include "builtins.hh"
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <fcntl.h> #include <fcntl.h>
#include <algorithm> #include <algorithm>
using namespace nix; namespace nix {
typedef std::map<Path,int> Priorities; typedef std::map<Path,int> Priorities;
static bool isDirectory (const Path & path) static bool isDirectory(const Path & path)
{ {
struct stat st; struct stat st;
if (stat(path.c_str(), &st) == -1) if (stat(path.c_str(), &st) == -1)
@ -16,9 +17,11 @@ static bool isDirectory (const Path & path)
return S_ISDIR(st.st_mode); return S_ISDIR(st.st_mode);
} }
static auto priorities = Priorities{}; // FIXME: change into local variables.
static auto symlinks = 0; static Priorities priorities;
static unsigned long symlinks;
/* For each activated package, create symlinks */ /* For each activated package, create symlinks */
static void createLinks(const Path & srcDir, const Path & dstDir, int priority) static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
@ -95,10 +98,10 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
typedef std::set<Path> FileProp; typedef std::set<Path> FileProp;
static auto done = FileProp{}; static FileProp done;
static auto postponed = FileProp{}; static FileProp postponed = FileProp{};
static auto out = string{}; static Path out;
static void addPkg(const Path & pkgDir, int priority) static void addPkg(const Path & pkgDir, int priority)
{ {
@ -107,7 +110,7 @@ static void addPkg(const Path & pkgDir, int priority)
done.insert(pkgDir); done.insert(pkgDir);
createLinks(pkgDir, out, priority); createLinks(pkgDir, out, priority);
auto propagatedFN = pkgDir + "/nix-support/propagated-user-env-packages"; auto propagatedFN = pkgDir + "/nix-support/propagated-user-env-packages";
auto propagated = string{}; std::string propagated;
{ {
AutoCloseFD fd = open(propagatedFN.c_str(), O_RDONLY | O_CLOEXEC); AutoCloseFD fd = open(propagatedFN.c_str(), O_RDONLY | O_CLOEXEC);
if (!fd) { if (!fd) {
@ -126,62 +129,65 @@ struct Package {
Path path; Path path;
bool active; bool active;
int priority; int priority;
Package(Path path, bool active, int priority) : path{std::move(path)}, active{active}, priority{priority} {} Package(Path path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
}; };
typedef std::vector<Package> Packages; typedef std::vector<Package> Packages;
int main(int argc, char ** argv) void builtinBuildenv(const BasicDerivation & drv)
{ {
return handleExceptions(argv[0], [&]() { auto getAttr = [&](const string & name) {
initNix(); auto i = drv.env.find(name);
out = getEnv("out"); if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
if (mkdir(out.c_str(), 0755) == -1) return i->second;
throw SysError(format("creating %1%") % out); };
/* Convert the stuff we get from the environment back into a coherent out = getAttr("out");
* data type. createDirs(out);
*/
auto pkgs = Packages{}; /* Convert the stuff we get from the environment back into a
auto derivations = tokenizeString<Strings>(getEnv("derivations")); * coherent data type. */
while (!derivations.empty()) { Packages pkgs;
/* !!! We're trusting the caller to structure derivations env var correctly */ auto derivations = tokenizeString<Strings>(getAttr("derivations"));
auto active = derivations.front(); derivations.pop_front(); while (!derivations.empty()) {
auto priority = stoi(derivations.front()); derivations.pop_front(); /* !!! We're trusting the caller to structure derivations env var correctly */
auto outputs = stoi(derivations.front()); derivations.pop_front(); auto active = derivations.front(); derivations.pop_front();
for (auto n = 0; n < outputs; n++) { auto priority = stoi(derivations.front()); derivations.pop_front();
auto path = derivations.front(); derivations.pop_front(); auto outputs = stoi(derivations.front()); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority); for (auto n = 0; n < outputs; n++) {
} auto path = derivations.front(); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority);
} }
}
/* Symlink to the packages that have been installed explicitly by the /* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary * user. Process in priority order to reduce unnecessary
* symlink/unlink steps. * symlink/unlink steps.
*/ */
std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) { std::sort(pkgs.begin(), pkgs.end(), [](const Package & a, const Package & b) {
return a.priority < b.priority || (a.priority == b.priority && a.path < b.path); return a.priority < b.priority || (a.priority == b.priority && a.path < b.path);
});
for (const auto & pkg : pkgs)
if (pkg.active)
addPkg(pkg.path, pkg.priority);
/* Symlink to the packages that have been "propagated" by packages
* installed by the user (i.e., package X declares that it wants Y
* installed as well). We do these later because they have a lower
* priority in case of collisions.
*/
auto priorityCounter = 1000;
while (!postponed.empty()) {
auto pkgDirs = postponed;
postponed = FileProp{};
for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++);
}
std::cerr << "created " << symlinks << " symlinks in user environment\n";
createSymlink(getEnv("manifest"), out + "/manifest.nix");
}); });
for (const auto & pkg : pkgs)
if (pkg.active)
addPkg(pkg.path, pkg.priority);
/* Symlink to the packages that have been "propagated" by packages
* installed by the user (i.e., package X declares that it wants Y
* installed as well). We do these later because they have a lower
* priority in case of collisions.
*/
auto priorityCounter = 1000;
while (!postponed.empty()) {
auto pkgDirs = postponed;
postponed = FileProp{};
for (const auto & pkgDir : pkgDirs)
addPkg(pkgDir, priorityCounter++);
}
printError("created %d symlinks in user environment", symlinks);
createSymlink(getAttr("manifest"), out + "/manifest.nix");
}
} }