about summary refs log tree commit diff
path: root/pkgs/games/build-support
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2017-10-03 21:32:35 +0200
committeraszlig <aszlig@redmoonstudios.org>2017-10-03 23:41:37 +0200
commit0bf66bd8d1a1db8c512c66069731bf67a9836a44 (patch)
tree3d010ba317b2dbe8c4f9d05d18de568ff9bf2f62 /pkgs/games/build-support
parent2c68ece11b950dc9f078ff843a0ba137c76f7076 (diff)
pkgs/sandbox: Mount paths from path-like variables
On NixOS the LD_LIBRARY_PATH looks similar to this (depending on the
configuration):

/run/opengl-driver/lib:/run/opengl-driver-32/lib

However, we don't have these paths available within the sandbox, because
so far we've only used exportReferencesGraph to gather the runtime
dependencies after the build has succeeded.

This obviously doesn't take into account runtime dependencies from the
system itself.

We are now taking care of this by using the Nix store library to query
the requisities of all the paths that are contained inside path-like
variables (multiple paths delimited by colons) and mount them during
sandbox setup.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'pkgs/games/build-support')
-rw-r--r--pkgs/games/build-support/build-sandbox/default.nix15
-rw-r--r--pkgs/games/build-support/build-sandbox/src/Makefile10
-rw-r--r--pkgs/games/build-support/build-sandbox/src/get-closure.cc23
-rw-r--r--pkgs/games/build-support/build-sandbox/src/nix-query.cc116
-rw-r--r--pkgs/games/build-support/build-sandbox/src/nix-query.h6
-rw-r--r--pkgs/games/build-support/build-sandbox/src/params.h2
-rw-r--r--pkgs/games/build-support/build-sandbox/src/setup.c66
-rw-r--r--pkgs/games/build-support/build-sandbox/src/setup.h2
8 files changed, 211 insertions, 29 deletions
diff --git a/pkgs/games/build-support/build-sandbox/default.nix b/pkgs/games/build-support/build-sandbox/default.nix
index 337456e0..e7243d2c 100644
--- a/pkgs/games/build-support/build-sandbox/default.nix
+++ b/pkgs/games/build-support/build-sandbox/default.nix
@@ -1,6 +1,6 @@
 { stdenv, lib, pkgconfig, nix }:
 
-drv: { extraSandboxPaths ? [], ... }@attrs:
+drv: { extraSandboxPaths ? [], runtimePathVariables ? [], ... }@attrs:
 
 stdenv.mkDerivation ({
   name = "${drv.name}-sandboxed";
@@ -43,11 +43,20 @@ stdenv.mkDerivation ({
     in "${result} >> params.c") extraSandboxPaths}
 
     echo 'return true; }' >> params.c
-    cat params.c
+
+    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") runtimePathVariables}
+
+    echo 'return true; }' >> params.c
   '';
 
   nativeBuildInputs = [ pkgconfig ];
   buildInputs = [ nix ];
   makeFlags = [ "BINDIR=${drv}/bin" ];
 
-} // removeAttrs attrs [ "extraSandboxPaths" ])
+} // removeAttrs attrs [ "extraSandboxPaths" "runtimePathVariables" ])
diff --git a/pkgs/games/build-support/build-sandbox/src/Makefile b/pkgs/games/build-support/build-sandbox/src/Makefile
index 49b266fe..f662b5ba 100644
--- a/pkgs/games/build-support/build-sandbox/src/Makefile
+++ b/pkgs/games/build-support/build-sandbox/src/Makefile
@@ -1,10 +1,14 @@
 BINARIES = $(wildcard $(BINDIR)/*)
 WRAPPERS = $(subst $(BINDIR),$(out)/bin,$(BINARIES))
 
-OBJECTS = get-closure.o params.o setup.o
+NIX_VERSION = `pkg-config --modversion nix-main | \
+               sed -e 's/^\([0-9]\+\)\.\([0-9]\+\).*/\1\2/'`
 
-CFLAGS = -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\"
-CXXFLAGS = -Wall -std=c++14 `pkg-config --cflags nix-main`
+OBJECTS = nix-query.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`
+CXXFLAGS += -DNIX_VERSION=$(NIX_VERSION)
 LDFLAGS = `pkg-config --libs nix-main`
 
 all: $(OBJECTS)
diff --git a/pkgs/games/build-support/build-sandbox/src/get-closure.cc b/pkgs/games/build-support/build-sandbox/src/get-closure.cc
deleted file mode 100644
index 11330a9c..00000000
--- a/pkgs/games/build-support/build-sandbox/src/get-closure.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <nix/util.hh>
-#include <nix/local-store.hh>
-#include <nix/store-api.hh>
-#include <nix/misc.hh>
-
-using namespace nix;
-
-int get_closure(const char *path)
-{
-    Path query(path);
-    PathSet paths;
-    auto store = openStore(false);
-
-    computeFSClosure(
-        *store, followLinksToStorePath(query), paths, false, true
-    );
-
-    for (auto i = paths.begin(); i != paths.end(); ++i) {
-        // TODO!
-    }
-
-    return 1;
-}
diff --git a/pkgs/games/build-support/build-sandbox/src/nix-query.cc b/pkgs/games/build-support/build-sandbox/src/nix-query.cc
new file mode 100644
index 00000000..128c376a
--- /dev/null
+++ b/pkgs/games/build-support/build-sandbox/src/nix-query.cc
@@ -0,0 +1,116 @@
+#include <iostream>
+
+#if NIX_VERSION >= 112
+#include <nix/config.h>
+#endif
+#include <nix/util.hh>
+#include <nix/local-store.hh>
+#include <nix/store-api.hh>
+
+#if NIX_VERSION < 112
+#include <nix/misc.hh>
+#include <nix/globals.hh>
+#endif
+
+using namespace nix;
+
+struct query_state {
+#if NIX_VERSION >= 112
+    std::shared_ptr<Store> store;
+#else
+    std::shared_ptr<StoreAPI> store;
+#endif
+    PathSet paths;
+    PathSet::iterator iter;
+};
+
+static Path get_store_path(query_state *qs, Path path)
+{
+    Path canonicalized = canonPath(path, true);
+#if NIX_VERSION >= 112
+    return qs->store->toStorePath(canonicalized);
+#else
+    return toStorePath(canonicalized);
+#endif
+}
+
+static Path get_ancestor(query_state *qs, Path path)
+{
+    size_t pos = 0;
+    std::string tmp;
+
+    while (pos != std::string::npos) {
+        if ((pos = path.find('/', pos + 1)) != std::string::npos) {
+            Path current = path.substr(0, pos);
+
+            if (!isLink(current))
+                continue;
+
+            try {
+                current = get_store_path(qs, current);
+            } catch (...) {
+                continue;
+            }
+
+            return current;
+        }
+    }
+
+    return path;
+}
+
+extern "C" {
+    struct query_state *new_query(void) {
+        query_state *initial = new query_state();
+#if NIX_VERSION >= 112
+        initial->store = openStore();
+#else
+        settings.processEnvironment();
+        settings.loadConfFile();
+        initial->store = openStore(false);
+#endif
+        return initial;
+    }
+
+    void free_query(query_state *qs) {
+        delete qs;
+    }
+
+    bool query_requisites(query_state *qs, const char *path)
+    {
+        Path query(path);
+
+        try {
+            query = get_ancestor(qs, query);
+
+#if NIX_VERSION >= 112
+            qs->store->computeFSClosure(
+                qs->store->followLinksToStorePath(query),
+                qs->paths, false, true
+            );
+#else
+            computeFSClosure(
+                *qs->store, followLinksToStorePath(query),
+                qs->paths, false, true
+            );
+#endif
+        } catch (Error &e) {
+            std::cerr << "Error while querying requisites for "
+                      << query << ": " << e.what()
+                      << std::endl;
+            return false;
+        }
+
+        qs->iter = qs->paths.begin();
+
+        return true;
+    }
+
+    const char *next_query_result(query_state *qs)
+    {
+        if (qs->iter == qs->paths.end())
+            return NULL;
+
+        return (qs->iter++)->c_str();
+    }
+}
diff --git a/pkgs/games/build-support/build-sandbox/src/nix-query.h b/pkgs/games/build-support/build-sandbox/src/nix-query.h
new file mode 100644
index 00000000..3eef7c4a
--- /dev/null
+++ b/pkgs/games/build-support/build-sandbox/src/nix-query.h
@@ -0,0 +1,6 @@
+struct query_state;
+
+struct query_state *new_query(void);
+void free_query(struct query_state *qs);
+bool query_requisites(struct query_state *qs, const char *path);
+const char *next_query_result(struct query_state *qs);
diff --git a/pkgs/games/build-support/build-sandbox/src/params.h b/pkgs/games/build-support/build-sandbox/src/params.h
index ea33872d..ecfa7295 100644
--- a/pkgs/games/build-support/build-sandbox/src/params.h
+++ b/pkgs/games/build-support/build-sandbox/src/params.h
@@ -2,7 +2,9 @@
 #define _PARAMS_H
 
 #include <stdbool.h>
+#include "nix-query.h"
 
 bool setup_app_paths(void);
+bool mount_runtime_path_vars(struct query_state *qs);
 
 #endif
diff --git a/pkgs/games/build-support/build-sandbox/src/setup.c b/pkgs/games/build-support/build-sandbox/src/setup.c
index 72b2f80e..3251a861 100644
--- a/pkgs/games/build-support/build-sandbox/src/setup.c
+++ b/pkgs/games/build-support/build-sandbox/src/setup.c
@@ -18,6 +18,7 @@
 #include <unistd.h>
 
 #include "params.h"
+#include "nix-query.h"
 
 static bool write_proc(int proc_pid_fd, const char *fname, const char *buf,
                        size_t buflen, bool ignore_errors)
@@ -193,6 +194,7 @@ static bool bind_file(const char *path)
         return false;
     }
 
+    free(target);
     return true;
 }
 
@@ -480,6 +482,67 @@ static bool setup_xauthority(void)
     return result;
 }
 
+static bool mount_requisites(struct query_state *qs, const char *path)
+{
+    const char *requisite;
+
+    if (!query_requisites(qs, path)) {
+        fprintf(stderr, "Unable to get requisites for %s.\n", path);
+        return false;
+    }
+
+    while ((requisite = next_query_result(qs)) != NULL) {
+        if (!bind_mount(requisite, true, false))
+            return false;
+    }
+
+    return true;
+}
+
+bool mount_from_path_var(struct query_state *qs, const char *name)
+{
+    char *buf, *ptr, *value = getenv(name);
+
+    if (value == NULL)
+        return true;
+
+    if ((buf = strdup(value)) == NULL) {
+        fprintf(stderr, "strdup %s: %s\n", value, strerror(errno));
+        return false;
+    }
+
+    ptr = strtok(buf, ":");
+
+    while (ptr != NULL) {
+        if (!mount_requisites(qs, ptr)) {
+            free(buf);
+            return false;
+        }
+        ptr = strtok(NULL, ":");
+    }
+
+    free(buf);
+    return true;
+}
+
+static bool setup_runtime_paths(void)
+{
+    struct query_state *qs;
+
+    if ((qs = new_query()) == NULL) {
+        fputs("Unable to allocate Nix query state.\n", stderr);
+        return false;
+    }
+
+    if (!mount_runtime_path_vars(qs)) {
+        free_query(qs);
+        return false;
+    }
+
+    free_query(qs);
+    return true;
+}
+
 static bool setup_chroot(void)
 {
     int mflags;
@@ -512,6 +575,9 @@ static bool setup_chroot(void)
     if (!bind_mount("/tmp", true, false))
         return false;
 
+    if (!setup_runtime_paths())
+        return false;
+
     if (!setup_app_paths())
         return false;
 
diff --git a/pkgs/games/build-support/build-sandbox/src/setup.h b/pkgs/games/build-support/build-sandbox/src/setup.h
index 19cc6ca2..c3b69699 100644
--- a/pkgs/games/build-support/build-sandbox/src/setup.h
+++ b/pkgs/games/build-support/build-sandbox/src/setup.h
@@ -3,10 +3,12 @@
 
 #include <stdbool.h>
 #include <sys/types.h>
+#include "nix-query.h"
 
 bool write_maps(pid_t parent_pid);
 bool bind_mount(const char *path, bool restricted, bool resolve);
 bool extra_mount(const char *path);
+bool mount_from_path_var(struct query_state *qs, const char *name);
 bool setup_sandbox(void);
 
 #endif