From d3176ce076407ef3e63667c0436bccf8be317ae4 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra <edolstra@gmail.com>
Date: Wed, 22 Jun 2022 22:43:53 +0200
Subject: [PATCH 1/3] Fix build-remote in nix-static

'build-remote' is now executed via /proc/self/exe so it always works.
---
 src/libstore/build/hook-instance.cc | 25 ++++++++++++++++++-------
 src/libstore/globals.cc             |  5 +++--
 src/libstore/globals.hh             |  2 +-
 src/libutil/util.cc                 | 14 ++++++++++++++
 src/libutil/util.hh                 |  6 +++++-
 src/nix/main.cc                     |  5 +++++
 src/nix/run.cc                      |  2 +-
 7 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/src/libstore/build/hook-instance.cc b/src/libstore/build/hook-instance.cc
index 0f6f580be..1f19ddccc 100644
--- a/src/libstore/build/hook-instance.cc
+++ b/src/libstore/build/hook-instance.cc
@@ -7,6 +7,22 @@ HookInstance::HookInstance()
 {
     debug("starting build hook '%s'", settings.buildHook);
 
+    auto buildHookArgs = tokenizeString<std::list<std::string>>(settings.buildHook.get());
+
+    if (buildHookArgs.empty())
+        throw Error("'build-hook' setting is empty");
+
+    auto buildHook = buildHookArgs.front();
+    buildHookArgs.pop_front();
+
+    Strings args;
+
+    for (auto & arg : buildHookArgs)
+        args.push_back(arg);
+
+    args.push_back(std::string(baseNameOf(settings.buildHook.get())));
+    args.push_back(std::to_string(verbosity));
+
     /* Create a pipe to get the output of the child. */
     fromHook.create();
 
@@ -36,14 +52,9 @@ HookInstance::HookInstance()
         if (dup2(builderOut.readSide.get(), 5) == -1)
             throw SysError("dupping builder's stdout/stderr");
 
-        Strings args = {
-            std::string(baseNameOf(settings.buildHook.get())),
-            std::to_string(verbosity),
-        };
+        execv(buildHook.c_str(), stringsToCharPtrs(args).data());
 
-        execv(settings.buildHook.get().c_str(), stringsToCharPtrs(args).data());
-
-        throw SysError("executing '%s'", settings.buildHook);
+        throw SysError("executing '%s'", buildHook);
     });
 
     pid.setSeparatePG(true);
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index cc009a026..1d7f65135 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -67,12 +67,13 @@ Settings::Settings()
     sandboxPaths = tokenizeString<StringSet>("/bin/sh=" SANDBOX_SHELL);
 #endif
 
-
-/* chroot-like behavior from Apple's sandbox */
+    /* chroot-like behavior from Apple's sandbox */
 #if __APPLE__
     sandboxPaths = tokenizeString<StringSet>("/System/Library/Frameworks /System/Library/PrivateFrameworks /bin/sh /bin/bash /private/tmp /private/var/tmp /usr/lib");
     allowedImpureHostPrefixes = tokenizeString<StringSet>("/System/Library /usr/lib /dev /bin/sh");
 #endif
+
+    buildHook = getSelfExe().value_or("nix") + " __build-remote";
 }
 
 void loadConfFile()
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 0ee27ecb6..9df1c999c 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -195,7 +195,7 @@ public:
         )",
         {"build-timeout"}};
 
-    PathSetting buildHook{this, true, nixLibexecDir + "/nix/build-remote", "build-hook",
+    PathSetting buildHook{this, true, "", "build-hook",
         "The path of the helper program that executes builds to remote machines."};
 
     Setting<std::string> builders{
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index aabd23427..82628461c 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -633,6 +633,20 @@ Path getDataDir()
 }
 
 
+std::optional<Path> getSelfExe()
+{
+    static std::optional<Path> cached = []()
+    {
+        #if __linux__
+        return readLink("/proc/self/exe");
+        #else
+        return std::nullopt;
+        #endif
+    }();
+    return cached;
+}
+
+
 Paths createDirs(const Path & path)
 {
     Paths created;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 90418b04d..d3ed15b0b 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -149,10 +149,14 @@ std::vector<Path> getConfigDirs();
 /* Return $XDG_DATA_HOME or $HOME/.local/share. */
 Path getDataDir();
 
+/* Return the path of the current executable. */
+std::optional<Path> getSelfExe();
+
 /* Create a directory and all its parents, if necessary.  Returns the
    list of created directories, in order of creation. */
 Paths createDirs(const Path & path);
-inline Paths createDirs(PathView path) {
+inline Paths createDirs(PathView path)
+{
     return createDirs(Path(path));
 }
 
diff --git a/src/nix/main.cc b/src/nix/main.cc
index f398e3118..17c92ebc6 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -266,6 +266,11 @@ void mainWrapped(int argc, char * * argv)
     programPath = argv[0];
     auto programName = std::string(baseNameOf(programPath));
 
+    if (argc > 0 && std::string_view(argv[0]) == "__build-remote") {
+        programName = "build-remote";
+        argv++; argc--;
+    }
+
     {
         auto legacy = (*RegisterLegacyCommand::commands)[programName];
         if (legacy) return legacy(argc, argv);
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 25a8fa8d3..45d2dfd0d 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -47,7 +47,7 @@ void runProgramInStore(ref<Store> store,
         Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program };
         for (auto & arg : args) helperArgs.push_back(arg);
 
-        execv(readLink("/proc/self/exe").c_str(), stringsToCharPtrs(helperArgs).data());
+        execv(getSelfExe().value_or("nix").c_str(), stringsToCharPtrs(helperArgs).data());
 
         throw SysError("could not execute chroot helper");
     }

From 184f4e40de0960deccad2147099ea232e5e036c3 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra <edolstra@gmail.com>
Date: Wed, 22 Jun 2022 23:45:36 +0200
Subject: [PATCH 2/3] Remove NIX_LIBEXEC_DIR

---
 src/libstore/globals.cc | 1 -
 src/libstore/globals.hh | 3 ---
 src/libstore/local.mk   | 1 -
 3 files changed, 5 deletions(-)

diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 1d7f65135..0f2ca4b15 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -36,7 +36,6 @@ Settings::Settings()
     , nixStateDir(canonPath(getEnv("NIX_STATE_DIR").value_or(NIX_STATE_DIR)))
     , nixConfDir(canonPath(getEnv("NIX_CONF_DIR").value_or(NIX_CONF_DIR)))
     , nixUserConfFiles(getUserConfigFiles())
-    , nixLibexecDir(canonPath(getEnv("NIX_LIBEXEC_DIR").value_or(NIX_LIBEXEC_DIR)))
     , nixBinDir(canonPath(getEnv("NIX_BIN_DIR").value_or(NIX_BIN_DIR)))
     , nixManDir(canonPath(NIX_MAN_DIR))
     , nixDaemonSocketFile(canonPath(getEnv("NIX_DAEMON_SOCKET_PATH").value_or(nixStateDir + DEFAULT_SOCKET_PATH)))
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 9df1c999c..d7f351166 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -79,9 +79,6 @@ public:
     /* A list of user configuration files to load. */
     std::vector<Path> nixUserConfFiles;
 
-    /* The directory where internal helper programs are stored. */
-    Path nixLibexecDir;
-
     /* The directory where the main programs are stored. */
     Path nixBinDir;
 
diff --git a/src/libstore/local.mk b/src/libstore/local.mk
index b992bcbc0..0f94d3917 100644
--- a/src/libstore/local.mk
+++ b/src/libstore/local.mk
@@ -39,7 +39,6 @@ libstore_CXXFLAGS += \
  -DNIX_STATE_DIR=\"$(localstatedir)/nix\" \
  -DNIX_LOG_DIR=\"$(localstatedir)/log/nix\" \
  -DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
- -DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
  -DNIX_BIN_DIR=\"$(bindir)\" \
  -DNIX_MAN_DIR=\"$(mandir)\" \
  -DLSOF=\"$(lsof)\"

From 1e55ee2961eabd6016dfef1793996ded97c9054c Mon Sep 17 00:00:00 2001
From: Eelco Dolstra <edolstra@gmail.com>
Date: Thu, 23 Jun 2022 01:32:17 +0200
Subject: [PATCH 3/3] getSelfExe(): Support macOS

---
 src/libutil/util.cc | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 82628461c..28df30fef 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -29,6 +29,7 @@
 
 #ifdef __APPLE__
 #include <sys/syscall.h>
+#include <mach-o/dyld.h>
 #endif
 
 #ifdef __linux__
@@ -635,10 +636,17 @@ Path getDataDir()
 
 std::optional<Path> getSelfExe()
 {
-    static std::optional<Path> cached = []()
+    static auto cached = []() -> std::optional<Path>
     {
         #if __linux__
         return readLink("/proc/self/exe");
+        #elif __APPLE__
+        char buf[1024];
+        uint32_t size = sizeof(buf);
+        if (_NSGetExecutablePath(buf, &size) == 0)
+            return buf;
+        else
+            return std::nullopt;
         #else
         return std::nullopt;
         #endif