From fc62890f2d952787cb0c6595ec36b38c6861c567 Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Fri, 18 Oct 2019 21:30:59 +0200 Subject: [PATCH] execlineb: change execlineb wrapper to C script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- pkgs/tools/misc/execline/default.nix | 41 ++++++++----------- pkgs/tools/misc/execline/execlineb-wrapper.c | 43 ++++++++++++++++++++ 2 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 pkgs/tools/misc/execline/execlineb-wrapper.c diff --git a/pkgs/tools/misc/execline/default.nix b/pkgs/tools/misc/execline/default.nix index 14aeb26748e..a1907434181 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 00000000000..09ccf990af7 --- /dev/null +++ b/pkgs/tools/misc/execline/execlineb-wrapper.c @@ -0,0 +1,43 @@ +#include +#include + +#include +#include +#include +#include + +#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 + ); +}