about summary refs log tree commit diff
path: root/pkgs/tools
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2019-10-18 21:30:59 +0200
committerProfpatsch <mail@profpatsch.de>2019-10-19 15:49:39 +0200
commitfc62890f2d952787cb0c6595ec36b38c6861c567 (patch)
tree3c06f7a3fbc0128a0ea66f3cd6e7188bf85e7177 /pkgs/tools
parentd2c9469ef75d47836764f168b4d927e0c3abe908 (diff)
execlineb: change execlineb wrapper to C script
Instead of using execlineb to define the execlineb wrapper, we replace
it by a little C wrapper.

This is mainly done because on non-Linux systems (i.e. mainly macOS),
it is impossible for a shebang interpreter to be itself a shebang
script.
It is, however, perfectly fine to have a chain that goes
shebang -> ELF -> shebang -> ELF -> …

Co-Authored-By: Laurent Bercot <ska-skaware@skarnet.org>
Diffstat (limited to 'pkgs/tools')
-rw-r--r--pkgs/tools/misc/execline/default.nix41
-rw-r--r--pkgs/tools/misc/execline/execlineb-wrapper.c43
2 files changed, 61 insertions, 23 deletions
diff --git a/pkgs/tools/misc/execline/default.nix b/pkgs/tools/misc/execline/default.nix
index 14aeb26748e1a..a19074341818e 100644
--- a/pkgs/tools/misc/execline/default.nix
+++ b/pkgs/tools/misc/execline/default.nix
@@ -1,6 +1,6 @@
 { lib, skawarePackages
 # for execlineb-with-builtins
-, coreutils, gnugrep, writeScriptBin, runCommand
+, coreutils, gnugrep, writeScriptBin, runCommand, runCommandCC
 # Whether to wrap bin/execlineb to have the execline tools on its PATH.
 , execlineb-with-builtins ? true
 }:
@@ -43,29 +43,24 @@ let
 
     };
 
-  # a wrapper around execlineb, which provides all execline
+  # A wrapper around execlineb, which provides all execline
   # tools on `execlineb`’s PATH.
-  execlineb-with-builtins-drv =
-    let eldir = "${execline}/bin";
-    in writeScriptBin "execlineb" ''
-      #!${eldir}/execlineb -s0
-      # appends the execlineb bin dir to PATH if not yet in PATH
-      ${eldir}/define eldir ${eldir}
-      ''${eldir}/ifelse
-      {
-        # since this is nix, we can grep for the execline drv hash in PATH
-        # to see whether it’s already in there
-        ''${eldir}/pipeline
-        { ${coreutils}/bin/printenv PATH }
-        ${gnugrep}/bin/grep --quiet "${eldir}"
-      }
-      # it’s there already
-      { ''${eldir}/execlineb $@ }
-      # not there yet, add it
-      ''${eldir}/importas oldpath PATH
-      ''${eldir}/export PATH "''${eldir}:''${oldpath}"
-      ''${eldir}/execlineb $@
-    '';
+  # It is implemented as a C script, because on non-Linux,
+  # nested shebang lines are not supported.
+  execlineb-with-builtins-drv = runCommandCC "execlineb" {} ''
+    mkdir -p $out/bin
+    cc \
+      -O \
+      -Wall -Wpedantic \
+      -D 'EXECLINEB_PATH()="${execline}/bin/execlineb"' \
+      -D 'EXECLINE_BIN_PATH()="${execline}/bin"' \
+      -I "${skalibs.dev}/include" \
+      -L "${skalibs.lib}/lib" \
+      -l"skarnet" \
+      -o "$out/bin/execlineb" \
+      ${./execlineb-wrapper.c}
+  '';
+
 
   # the original execline package, with bin/execlineb overwritten
   execline-with-builtins = runCommand "my-execline"
diff --git a/pkgs/tools/misc/execline/execlineb-wrapper.c b/pkgs/tools/misc/execline/execlineb-wrapper.c
new file mode 100644
index 0000000000000..09ccf990af7f3
--- /dev/null
+++ b/pkgs/tools/misc/execline/execlineb-wrapper.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include <skalibs/stralloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/env.h>
+
+#define dienomem() strerr_diefu1sys(111, "stralloc_catb")
+
+// macros from outside
+/* const char* EXECLINEB_PATH; */
+/* const char* EXECLINE_BIN_PATH; */
+
+int main(int argc, char const* argv[], char const *const *envp)
+{
+  PROG = "execlineb-wrapper";
+
+  char const* path = getenv("PATH");
+  stralloc path_modif = STRALLOC_ZERO;
+
+  // modify PATH if unset or EXECLINEB_BIN_PATH is not yet there
+  if ( !path || ! strstr(path, EXECLINE_BIN_PATH())) {
+    // prepend our execline path
+    if ( ! stralloc_cats(&path_modif, "PATH=")
+         || ! stralloc_cats(&path_modif, EXECLINE_BIN_PATH()) ) dienomem();
+    // old path was not empty
+    if ( path && path[0] ) {
+      if ( ! stralloc_catb(&path_modif, ":", 1)
+           || ! stralloc_cats(&path_modif, path) ) dienomem();
+    }
+    // append final \0
+    if ( ! stralloc_0(&path_modif) ) dienomem();
+  }
+
+  // exec into execlineb and append path_modif to the environment
+  xpathexec_r_name(
+    EXECLINEB_PATH(),
+    argv,
+    envp, env_len(envp),
+    path_modif.s, path_modif.len
+  );
+}