From ced825791a83b508ebe995683e97029a5bd71cb1 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Mon, 2 Feb 2026 18:26:56 +0100 Subject: [PATCH] libstore: add capnp build request parameter struct to builders there's nothing in here yet, we'll add that piece by piece. Change-Id: Ib276d9e8281bb08013197db0f2bbfd8eec76b5ce --- lix/libstore/build/local-derivation-goal.cc | 32 +++++++++++---- lix/libstore/build/local-derivation-goal.hh | 23 ++++++++--- lix/libstore/build/meson.build | 45 ++++++++++++--------- lix/libstore/build/request.capnp | 7 ++++ lix/libstore/platform/darwin.cc | 6 ++- lix/libstore/platform/darwin.hh | 5 ++- lix/libstore/platform/linux.cc | 14 ++++--- lix/libstore/platform/linux.hh | 10 +++-- meson.build | 1 + 9 files changed, 97 insertions(+), 46 deletions(-) create mode 100644 lix/libstore/build/request.capnp diff --git a/lix/libstore/build/local-derivation-goal.cc b/lix/libstore/build/local-derivation-goal.cc index 4f1f277d6..f499aedd9 100644 --- a/lix/libstore/build/local-derivation-goal.cc +++ b/lix/libstore/build/local-derivation-goal.cc @@ -33,7 +33,9 @@ #include "lix/libutil/thread-name.hh" #include "lix/libstore/platform/linux.hh" #include "lix/libstore/path-tree.hh" +#include "request.capnp.h" +#include #include #include #include @@ -921,8 +923,14 @@ try { builder = drv->builder; } + capnp::MallocMessageBuilder requestBuilder; + + auto request = requestBuilder.initRoot(); + + fillBuilderConfig(request); + /* Fork a child to build the package. */ - pg = ProcessGroup{startChild(builder, envStrs, args, std::move(builderOut))}; + pg = ProcessGroup{startChild(request.asReader(), builder, envStrs, args, std::move(builderOut))}; /* Check if setting up the build environment failed. */ std::vector msgs; @@ -956,7 +964,11 @@ try { } Pid LocalDerivationGoal::startChild( - const Path & builder, const Strings & envStrs, const Strings & args, AutoCloseFD logPTY + build::Request::Reader request, + const Path & builder, + const Strings & envStrs, + const Strings & args, + AutoCloseFD logPTY ) { return startProcess([&]() { @@ -964,7 +976,7 @@ Pid LocalDerivationGoal::startChild( throw SysError("failed to redirect build output to log file"); } closeOnExec(STDERR_FILENO, false); - runChild(builder, envStrs, args); + runChild(request, builder, envStrs, args); }); } @@ -1245,7 +1257,9 @@ static void closeExtraFDs() } } -void LocalDerivationGoal::runChild(const Path & builder, const Strings & envStrs, const Strings & args) +void LocalDerivationGoal::runChild( + build::Request::Reader request, const Path & builder, const Strings & envStrs, const Strings & args +) { /* Warning: in the child we should absolutely not make any SQLite calls! */ @@ -1286,7 +1300,7 @@ void LocalDerivationGoal::runChild(const Path & builder, const Strings & envStrs throw SysError("cannot dup null device into stdin"); } - const bool setUser = prepareChildSetup(); + const bool setUser = prepareChildSetup(request); if (sys::chdir(tmpDirInSandbox) == -1) { throw SysError("changing into '%1%'", tmpDir); @@ -1328,7 +1342,7 @@ void LocalDerivationGoal::runChild(const Path & builder, const Strings & envStrs throw SysError("setuid failed"); } - finishChildSetup(); + finishChildSetup(request); /* Indicate that we managed to set up the build environment. */ writeFull(STDERR_FILENO, std::string("\2\n")); @@ -1336,7 +1350,7 @@ void LocalDerivationGoal::runChild(const Path & builder, const Strings & envStrs sendException = false; /* Execute the program. This should not return. */ - execBuilder(builder, args, envStrs); + execBuilder(request, builder, args, envStrs); throw SysError("executing '%1%'", drv->builder); @@ -1352,7 +1366,9 @@ void LocalDerivationGoal::runChild(const Path & builder, const Strings & envStrs } } -void LocalDerivationGoal::execBuilder(std::string builder, Strings args, Strings envStrs) +void LocalDerivationGoal::execBuilder( + build::Request::Reader request, std::string builder, Strings args, Strings envStrs +) { sys::execve(builder, args, envStrs); } diff --git a/lix/libstore/build/local-derivation-goal.hh b/lix/libstore/build/local-derivation-goal.hh index 0e8ce6f03..173d24261 100644 --- a/lix/libstore/build/local-derivation-goal.hh +++ b/lix/libstore/build/local-derivation-goal.hh @@ -2,6 +2,7 @@ ///@file #include "lix/libstore/build/derivation-goal.hh" +#include "lix/libstore/build/request.capnp.h" #include "lix/libstore/local-store.hh" #include "lix/libutil/error.hh" #include "lix/libutil/processes.hh" @@ -209,7 +210,9 @@ struct LocalDerivationGoal : public DerivationGoal /** * Run the builder's process. */ - void runChild(const Path & builder, const Strings & envStrs, const Strings & args); + void runChild( + build::Request::Reader request, const Path & builder, const Strings & envStrs, const Strings & args + ); /** * Check that the derivation outputs all exist and register them @@ -291,12 +294,19 @@ protected: * Create a new process that runs `openSlave` and `runChild` * On some platforms this process is created with sandboxing flags. */ - virtual Pid - startChild(const Path & builder, const Strings & envStrs, const Strings & args, AutoCloseFD logPTY); + virtual Pid startChild( + build::Request::Reader request, + const Path & builder, + const Strings & envStrs, + const Strings & args, + AutoCloseFD logPTY + ); kj::Promise> handleRawChild() noexcept; kj::Promise>> handleRawChildStream() noexcept; + virtual void fillBuilderConfig(build::Request::Builder request) {} + /** * Prepare the sandbox. Currently only used on linux to build the sandbox namespace, * write configuration files inside it, and to set up networking with pasta enabled. @@ -304,7 +314,7 @@ protected: * `false` if this step has changed our credentials to the build user/group already. */ [[nodiscard]] - virtual bool prepareChildSetup() + virtual bool prepareChildSetup(build::Request::Reader request) { return true; } @@ -312,7 +322,7 @@ protected: /** * Finish sandbox setup and prepare for actually executing the builder processes. */ - virtual void finishChildSetup() {} + virtual void finishChildSetup(build::Request::Reader request) {} /** * Create a special accessor that can access paths that were built within the sandbox's @@ -327,7 +337,8 @@ protected: * Execute the builder, replacing the current process. * Generally this means an `execve` call. */ - virtual void execBuilder(std::string builder, Strings args, Strings envStrs); + virtual void + execBuilder(build::Request::Reader request, std::string builder, Strings args, Strings envStrs); /** * Whether derivation can be built on current platform with `uid-range` feature diff --git a/lix/libstore/build/meson.build b/lix/libstore/build/meson.build index a5c6a4df0..813148212 100644 --- a/lix/libstore/build/meson.build +++ b/lix/libstore/build/meson.build @@ -1,21 +1,26 @@ -libstore_rpc += custom_target( - command : [ - capnpc_wrapper, - '--language=c++', - '--src-prefix=@CURRENT_SOURCE_DIR@', - '--outdir=@OUTDIR@', - '--depfile=@DEPFILE@', - '-I@SOURCE_ROOT@', - '@INPUT@', - ], - input : files( - # keep-sorted start - 'hook-instance.capnp', - # keep-sorted end - ), - output : [ - '@PLAINNAME@.h', - '@PLAINNAME@.c++', - ], - depfile : '@PLAINNAME@.d', +build_capnp_files = files( + # keep-sorted start + 'hook-instance.capnp', + 'request.capnp', + # keep-sorted end ) + +foreach infile : build_capnp_files + libstore_rpc += custom_target( + command : [ + capnpc_wrapper, + '--language=c++', + '--src-prefix=@CURRENT_SOURCE_DIR@', + '--outdir=@OUTDIR@', + '--depfile=@DEPFILE@', + '-I@SOURCE_ROOT@', + '@INPUT@', + ], + input : infile, + output : [ + '@PLAINNAME@.h', + '@PLAINNAME@.c++', + ], + depfile : '@PLAINNAME@.d', + ) +endforeach diff --git a/lix/libstore/build/request.capnp b/lix/libstore/build/request.capnp new file mode 100644 index 000000000..c74caf7c3 --- /dev/null +++ b/lix/libstore/build/request.capnp @@ -0,0 +1,7 @@ +@0xa7f090bdc7816f8f; + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("nix::build"); + +struct Request { +} diff --git a/lix/libstore/platform/darwin.cc b/lix/libstore/platform/darwin.cc index a078f9f3d..c8d71e4a1 100644 --- a/lix/libstore/platform/darwin.cc +++ b/lix/libstore/platform/darwin.cc @@ -371,7 +371,7 @@ void DarwinLocalDerivationGoal::prepareSandbox() debug("Generated sandbox profile: %1%", sandboxProfile); } -void DarwinLocalDerivationGoal::finishChildSetup() +void DarwinLocalDerivationGoal::finishChildSetup(build::Request::Reader request) { bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); @@ -405,7 +405,9 @@ void DarwinLocalDerivationGoal::finishChildSetup() } } -void DarwinLocalDerivationGoal::execBuilder(std::string builder, Strings args, Strings envStrs) +void DarwinLocalDerivationGoal::execBuilder( + build::Request::Reader request, std::string builder, Strings args, Strings envStrs +) { posix_spawnattr_t attrp; diff --git a/lix/libstore/platform/darwin.hh b/lix/libstore/platform/darwin.hh index 0ac6c8c4f..086b83ff8 100644 --- a/lix/libstore/platform/darwin.hh +++ b/lix/libstore/platform/darwin.hh @@ -44,12 +44,13 @@ private: */ void prepareSandbox() override; - void finishChildSetup() override; + void finishChildSetup(build::Request::Reader request) override; /** * Set process flags to enter or leave rosetta, then execute the builder */ - void execBuilder(std::string builder, Strings args, Strings envStrs) override; + void + execBuilder(build::Request::Reader request, std::string builder, Strings args, Strings envStrs) override; /** * Whether we need to rewrite output hashes. diff --git a/lix/libstore/platform/linux.cc b/lix/libstore/platform/linux.cc index b678fa1ba..831ed1257 100644 --- a/lix/libstore/platform/linux.cc +++ b/lix/libstore/platform/linux.cc @@ -1267,7 +1267,7 @@ static void bindPath(const Path & source, const Path & target, bool optional = f } } -bool LinuxLocalDerivationGoal::prepareChildSetup() +bool LinuxLocalDerivationGoal::prepareChildSetup(build::Request::Reader request) { // Set the NO_NEW_PRIVS prctl flag. // This both makes loading seccomp filters work for unprivileged users, @@ -1551,7 +1551,7 @@ bool LinuxLocalDerivationGoal::prepareChildSetup() return false; } -void LinuxLocalDerivationGoal::finishChildSetup() +void LinuxLocalDerivationGoal::finishChildSetup(build::Request::Reader request) { if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) { throw SysError("setting death signal"); @@ -1562,12 +1562,16 @@ void LinuxLocalDerivationGoal::finishChildSetup() } Pid LinuxLocalDerivationGoal::startChild( - const Path & builder, const Strings & envStrs, const Strings & args, AutoCloseFD logPTY + build::Request::Reader request, + const Path & builder, + const Strings & envStrs, + const Strings & args, + AutoCloseFD logPTY ) { // If we're not sandboxing no need to faff about, use the fallback if (!useChroot) { - return LocalDerivationGoal::startChild(builder, envStrs, args, std::move(logPTY)); + return LocalDerivationGoal::startChild(request, builder, envStrs, args, std::move(logPTY)); } /* Set up private namespaces for the build: @@ -1737,7 +1741,7 @@ Pid LinuxLocalDerivationGoal::startChild( options.cloneFlags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD; - return startProcess([&]() { runChild(builder, envStrs, args); }, options); + return startProcess([&]() { runChild(request, builder, envStrs, args); }, options); }); } diff --git a/lix/libstore/platform/linux.hh b/lix/libstore/platform/linux.hh index 576e76768..0b6a892a5 100644 --- a/lix/libstore/platform/linux.hh +++ b/lix/libstore/platform/linux.hh @@ -81,7 +81,11 @@ private: * create /etc/passwd and /etc/group based on discovered uid/gid */ Pid startChild( - const Path & builder, const Strings & envStrs, const Strings & args, AutoCloseFD logPTY + build::Request::Reader request, + const Path & builder, + const Strings & envStrs, + const Strings & args, + AutoCloseFD logPTY ) override; /** @@ -94,9 +98,9 @@ private: return true; } - bool prepareChildSetup() override; + bool prepareChildSetup(build::Request::Reader request) override; - void finishChildSetup() override; + void finishChildSetup(build::Request::Reader request) override; std::string rewriteResolvConf(std::string fromHost); diff --git a/meson.build b/meson.build index 87915341c..c30f20d08 100644 --- a/meson.build +++ b/meson.build @@ -293,6 +293,7 @@ configdata.set('HAVE_BOEHMGC', boehm.found().to_int()) boost = dependency('boost', required : true, include_type : 'system') kj = dependency('kj-async', required : true, include_type : 'system') +capnp = dependency('capnp', required : true, include_type : 'system') capnp_rpc = dependency('capnp-rpc', required : true, include_type : 'system') # cpuid only makes sense on x86_64