summary refs log tree commit diff
path: root/gnu/packages/aux-files/run-in-namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/packages/aux-files/run-in-namespace.c')
-rw-r--r--gnu/packages/aux-files/run-in-namespace.c83
1 files changed, 78 insertions, 5 deletions
diff --git a/gnu/packages/aux-files/run-in-namespace.c b/gnu/packages/aux-files/run-in-namespace.c
index 5a6b932b87..52a16a5362 100644
--- a/gnu/packages/aux-files/run-in-namespace.c
+++ b/gnu/packages/aux-files/run-in-namespace.c
@@ -371,24 +371,84 @@ exec_with_proot (const char *store, int argc, char *argv[])
 
 #if HAVE_EXEC_WITH_LOADER
 
+/* Traverse PATH, a NULL-terminated string array, and return a colon-separated
+   search path where each item of PATH has been relocated to STORE.  The
+   result is malloc'd.  */
+static char *
+relocated_search_path (const char *path[], const char *store)
+{
+  char *new_path;
+  size_t size = 0;
+
+  for (size_t i = 0; path[i] != NULL; i++)
+    size += strlen (store) + strlen (path[i]) + 1;  /* upper bound */
+
+  new_path = xmalloc (size + 1);
+  new_path[0] = '\0';
+
+  for (size_t i = 0; path[i] != NULL; i++)
+    {
+      if (strncmp (path[i], original_store,
+		   sizeof original_store - 1) == 0)
+	{
+	  strcat (new_path, store);
+	  strcat (new_path, path[i] + sizeof original_store - 1);
+	}
+      else
+	strcat (new_path, path[i]);	  /* possibly $ORIGIN */
+
+      strcat (new_path, ":");
+    }
+
+  new_path[strlen (new_path) - 1] = '\0'; /* Remove trailing colon.  */
+
+  return new_path;
+}
+
+/* Concatenate PATH1 and PATH2 with a colon in between.  The result is
+   potentially malloc'd.  */
+static char *
+concat_paths (const char *path1, const char *path2)
+{
+  if (path1[0] == '\0')
+    return (char *) path2;
+  else
+    {
+      char *result = xmalloc (strlen (path1) + strlen (path2) + 2);
+      strcpy (result, path1);
+      strcat (result, ":");
+      strcat (result, path2);
+      return result;
+    }
+}
+
 /* Execute the wrapped program by invoking the loader (ld.so) directly,
    passing it the audit module and preloading libfakechroot.so.  */
 static void
 exec_with_loader (const char *store, int argc, char *argv[])
 {
+  static const char *audit_library_path[] = LOADER_AUDIT_RUNPATH;
   char *loader = concat (store,
 			 PROGRAM_INTERPRETER + sizeof original_store);
-  size_t loader_specific_argc = 6;
+  size_t loader_specific_argc = 8;
   size_t loader_argc = argc + loader_specific_argc;
   char *loader_argv[loader_argc + 1];
   loader_argv[0] = argv[0];
   loader_argv[1] = "--audit";
   loader_argv[2] = concat (store,
 			   LOADER_AUDIT_MODULE + sizeof original_store);
-  loader_argv[3] = "--preload";
-  loader_argv[4] = concat (store,
+
+  /* The audit module depends on libc.so and libgcc_s.so so honor
+     AUDIT_LIBRARY_PATH.  Additionally, honor $LD_LIBRARY_PATH if set.  */
+  loader_argv[3] = "--library-path";
+  loader_argv[4] =
+    concat_paths (getenv ("LD_LIBRARY_PATH") ?: "",
+		  relocated_search_path (audit_library_path, store));
+
+  loader_argv[5] = "--preload";
+  loader_argv[6] = concat (store,
 			   FAKECHROOT_LIBRARY + sizeof original_store);
-  loader_argv[5] = concat (store,
+  loader_argv[7] = concat (store,
 			   "@WRAPPED_PROGRAM@" + sizeof original_store);
 
   for (size_t i = 0; i < argc; i++)
@@ -401,10 +461,23 @@ exec_with_loader (const char *store, int argc, char *argv[])
   char *new_root = mkdtemp (strdup ("/tmp/guix-exec-XXXXXX"));
   mirror_directory ("/", new_root, make_symlink);
 
+  /* 'mirror_directory' created a symlink for the ancestor of ORIGINAL_STORE,
+     typically "/gnu".  Remove that entry so we can create NEW_STORE
+     below.  */
+  const char *slash = strchr (original_store + 1, '/');
+  const char *top = slash != NULL
+    ? strndupa (original_store, slash - original_store)
+    : original_store;
+  char *new_store_top = concat (new_root, top);
+  unlink (new_store_top);
+
+  /* Now create the store under NEW_ROOT.  */
   char *new_store = concat (new_root, original_store);
   char *new_store_parent = dirname (strdup (new_store));
   mkdir_p (new_store_parent);
-  symlink (store, new_store);
+  err = symlink (store, new_store);
+  if (err < 0)
+    assert_perror (errno);
 
 #ifdef GCONV_DIRECTORY
   /* Tell libc where to find its gconv modules.  This is necessary because