about summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2019-04-09 18:19:04 +0200
committerProfpatsch <mail@profpatsch.de>2019-04-18 16:10:20 +0200
commit09dc1d8ad625b9a1d5b89593b184d316837ba1cc (patch)
treeefe86ee9c7266a2c5a6416d151944f66d4dedf05 /pkgs/build-support
parent2cd8e92813dfda7684d94cf3bf322d4bae7fdfc2 (diff)
build-support/build-sandbox: add support for mounting /nix
Enables us to run nix *inside* of a sandbox.
We have to mount the whole store, because otherwise realized store
paths built inside of the sandbox are not accessible.
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/build-sandbox/default.nix42
-rw-r--r--pkgs/build-support/build-sandbox/src/Makefile17
-rw-r--r--pkgs/build-support/build-sandbox/src/setup.c13
3 files changed, 53 insertions, 19 deletions
diff --git a/pkgs/build-support/build-sandbox/default.nix b/pkgs/build-support/build-sandbox/default.nix
index 66797268..4e5cffe9 100644
--- a/pkgs/build-support/build-sandbox/default.nix
+++ b/pkgs/build-support/build-sandbox/default.nix
@@ -11,6 +11,10 @@ let
   pathsRuntimeVars = paths.runtimeVars or [];
   # Mount a dash shell in /bin/sh inside the chroot.
   allowBinSh       = attrs.allowBinSh or false;
+  # Enable nix builds from within the sandbox.
+  # Has to write the full nix store to make the outputs accessible.
+  # TODO: get rid of nix & pkg-config if this is enabled (in the Makefile)
+  fullNixStore = attrs.fullNixStore or false;
 
   # Create code snippets for params.c to add extra_mount() calls.
   mkExtraMountParams = isRequired: lib.concatMapStringsSep "\n" (extra: let
@@ -26,11 +30,13 @@ in stdenv.mkDerivation ({
 
   inherit drv;
 
+  # writes files "sandbox-*" to the builder (see nix manual)
   exportReferencesGraph =
     [ "sandbox-closure" drv ] ++
     lib.optionals allowBinSh [ "sandbox-binsh" dash ];
 
   configurePhase = ''
+    # Reads the dependency closures and does … something? TODO: explain
     runtimeDeps="$(sed -ne '
       p; n; n
 
@@ -52,25 +58,36 @@ in stdenv.mkDerivation ({
     echo '#include "setup.h"' > params.c
     echo 'bool setup_app_paths(void) {' >> params.c
 
-    for dep in $runtimeDeps; do
-      echo 'if (!bind_mount("'"$dep"'", true, true, true)) return false;' \
+    ${if fullNixStore then ''
+      # /nix/var needs to be writable for nix to work inside the sandbox
+      echo 'if (!bind_mount("/nix/var", false, true, true)) return false;' \
+        >> params.c
+      echo 'if (!bind_mount("/nix/store", true, true, true)) return false;' \
         >> params.c
-    done
+
+    '' else ''
+      for dep in $runtimeDeps; do
+        echo 'if (!bind_mount("'"$dep"'", true, true, true)) return false;' \
+          >> params.c
+      done
+    ''}
 
     ${mkExtraMountParams true  pathsRequired}
     ${mkExtraMountParams false pathsWanted}
 
     echo 'return true; }' >> params.c
 
-    echo 'bool mount_runtime_path_vars(struct query_state *qs) {' >> params.c
+   ${lib.optionalString (!fullNixStore) ''
+      echo 'bool mount_runtime_path_vars(struct query_state *qs) {' >> params.c
 
-    ${lib.concatMapStringsSep "\n" (pathvar: let
-      escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar);
-      fun = "mount_from_path_var";
-      result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'";
-    in "${result} >> params.c") pathsRuntimeVars}
+      ${lib.concatMapStringsSep "\n" (pathvar: let
+        escaped = lib.escapeShellArg (lib.escape ["\\" "\""] pathvar);
+        fun = "mount_from_path_var";
+        result = "echo 'if (!${fun}(qs, \"'${escaped}'\")) return false;'";
+      in "${result} >> params.c") pathsRuntimeVars}
 
-    echo 'return true; }' >> params.c
+      echo 'return true; }' >> params.c
+    ''}
   '';
 
   postInstall = ''
@@ -82,8 +99,9 @@ in stdenv.mkDerivation ({
   '';
 
   nativeBuildInputs = [ pkgconfig ];
-  buildInputs = [ nix boost ];
+  buildInputs = [ boost nix ];
   makeFlags = [ "BINDIR=${drv}/bin" ]
-           ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash";
+           ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash"
+           ++ lib.optional fullNixStore "FULL_NIX_STORE=1";
 
 } // removeAttrs attrs [ "paths" "allowBinSh" ])
diff --git a/pkgs/build-support/build-sandbox/src/Makefile b/pkgs/build-support/build-sandbox/src/Makefile
index e18ec9d4..8e1218f6 100644
--- a/pkgs/build-support/build-sandbox/src/Makefile
+++ b/pkgs/build-support/build-sandbox/src/Makefile
@@ -1,19 +1,24 @@
 BINARIES = $(wildcard $(BINDIR)/*)
 WRAPPERS = $(subst $(BINDIR),$(out)/bin,$(BINARIES))
 
+OBJECTS = path-cache.o params.o setup.o
+CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\"
+CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main`
+LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main`
+
+ifdef FULL_NIX_STORE
+CFLAGS += -DFULL_NIX_STORE
+else
+OBJECTS += nix-query.o
 NIX_VERSION = `pkg-config --modversion nix-main | \
                sed -e 's/^\([0-9]\+\)\.\([0-9][0-9]\).*/\1\2/' \
                    -e 's/^\([0-9]\+\)\.\([0-9]\).*/\10\2/'`
+CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION)
+endif
 
-OBJECTS = nix-query.o path-cache.o params.o setup.o
-
-CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\"
 ifdef BINSH_EXECUTABLE
 CFLAGS += -DBINSH_EXECUTABLE=\"$(BINSH_EXECUTABLE)\"
 endif
-CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main`
-CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION)
-LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main`
 
 all: $(OBJECTS)
 
diff --git a/pkgs/build-support/build-sandbox/src/setup.c b/pkgs/build-support/build-sandbox/src/setup.c
index 8a5d29b5..8af42a06 100644
--- a/pkgs/build-support/build-sandbox/src/setup.c
+++ b/pkgs/build-support/build-sandbox/src/setup.c
@@ -18,8 +18,10 @@
 #include <unistd.h>
 
 #include "params.h"
-#include "nix-query.h"
 #include "path-cache.h"
+#ifndef FULL_NIX_STORE
+#include "nix-query.h"
+#endif
 
 static path_cache cached_paths = NULL;
 
@@ -604,6 +606,7 @@ static bool setup_binsh(const char *executable)
 }
 #endif
 
+#ifndef FULL_NIX_STORE
 static bool is_dir(const char *path)
 {
     struct stat sb;
@@ -663,6 +666,9 @@ bool mount_from_path_var(struct query_state *qs, const char *name)
     return true;
 }
 
+/* `/etc/static` is a special symlink on NixOS, pointing to a storepath
+   of configs that have to be available at runtime for some programs
+   to function. So we need to mount the closure of that storepath. */
 static bool setup_static_etc(struct query_state *qs)
 {
     char dest[PATH_MAX];
@@ -680,6 +686,7 @@ static bool setup_static_etc(struct query_state *qs)
     return mount_requisites(qs, dest);
 }
 
+/* Bind-mount all necessary nix store paths. */
 static bool setup_runtime_paths(void)
 {
     struct query_state *qs;
@@ -702,6 +709,7 @@ static bool setup_runtime_paths(void)
     free_query(qs);
     return true;
 }
+#endif
 
 static bool setup_runtime_debug(void)
 {
@@ -782,8 +790,11 @@ static bool setup_chroot(void)
     if (!bind_mount("/tmp", false, true, false))
         return false;
 
+    // We don’t need to query the nix store if we mount the full store
+#ifndef FULL_NIX_STORE
     if (!setup_runtime_paths())
         return false;
+#endif
 
     if (!setup_app_paths())
         return false;