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/buildenv/
/corepkgs/buildenv/builder.pl
# /corepkgs/channels/
/corepkgs/channels/unpack.sh
@ -72,9 +69,6 @@ perl/Makefile.config
# /src/nix-channel/
/src/nix-channel/nix-channel
# /src/buildenv/
/src/buildenv/buildenv
# /src/nix-build/
/src/nix-build/nix-build

View file

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

View file

@ -1,11 +1,9 @@
with import <nix/config.nix>;
{ derivations, manifest }:
derivation {
name = "user-environment";
system = builtins.currentSystem;
builder = nixLibexecDir + "/nix/buildenv";
system = "builtin";
builder = "builtin:buildenv";
inherit manifest;
@ -24,21 +22,4 @@ derivation {
# Also don't bother substituting.
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")
builtinFetchurl(drv2, netrcData);
else if (drv->builder == "builtin:buildenv")
builtinBuildenv(drv2);
else
throw Error(format("unsupported builtin function '%1%'") % string(drv->builder, 8));
_exit(0);

View file

@ -4,6 +4,8 @@
namespace nix {
// TODO: make pluggable.
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/types.h>
#include <fcntl.h>
#include <algorithm>
using namespace nix;
namespace nix {
typedef std::map<Path,int> Priorities;
static bool isDirectory (const Path & path)
static bool isDirectory(const Path & path)
{
struct stat st;
if (stat(path.c_str(), &st) == -1)
@ -16,9 +17,11 @@ static bool isDirectory (const Path & path)
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 */
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;
static auto done = FileProp{};
static auto postponed = FileProp{};
static FileProp done;
static FileProp postponed = FileProp{};
static auto out = string{};
static Path out;
static void addPkg(const Path & pkgDir, int priority)
{
@ -107,7 +110,7 @@ static void addPkg(const Path & pkgDir, int priority)
done.insert(pkgDir);
createLinks(pkgDir, out, priority);
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);
if (!fd) {
@ -126,62 +129,65 @@ struct Package {
Path path;
bool active;
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;
int main(int argc, char ** argv)
void builtinBuildenv(const BasicDerivation & drv)
{
return handleExceptions(argv[0], [&]() {
initNix();
out = getEnv("out");
if (mkdir(out.c_str(), 0755) == -1)
throw SysError(format("creating %1%") % out);
auto getAttr = [&](const string & name) {
auto i = drv.env.find(name);
if (i == drv.env.end()) throw Error("attribute '%s' missing", name);
return i->second;
};
/* Convert the stuff we get from the environment back into a coherent
* data type.
*/
auto pkgs = Packages{};
auto derivations = tokenizeString<Strings>(getEnv("derivations"));
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly */
auto active = derivations.front(); derivations.pop_front();
auto priority = stoi(derivations.front()); derivations.pop_front();
auto outputs = stoi(derivations.front()); derivations.pop_front();
for (auto n = 0; n < outputs; n++) {
auto path = derivations.front(); derivations.pop_front();
pkgs.emplace_back(path, active != "false", priority);
}
out = getAttr("out");
createDirs(out);
/* Convert the stuff we get from the environment back into a
* coherent data type. */
Packages pkgs;
auto derivations = tokenizeString<Strings>(getAttr("derivations"));
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly */
auto active = derivations.front(); derivations.pop_front();
auto priority = stoi(derivations.front()); derivations.pop_front();
auto outputs = stoi(derivations.front()); derivations.pop_front();
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
* user. Process in priority order to reduce unnecessary
* symlink/unlink steps.
*/
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);
});
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");
/* Symlink to the packages that have been installed explicitly by the
* user. Process in priority order to reduce unnecessary
* symlink/unlink steps.
*/
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);
});
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");
}
}