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
This commit is contained in:
eldritch horrors
2026-02-02 18:26:56 +01:00
parent f09ed729b5
commit ced825791a
9 changed files with 97 additions and 46 deletions
+24 -8
View File
@@ -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 <capnp/message.h>
#include <cstddef>
#include <dirent.h>
#include <exception>
@@ -921,8 +923,14 @@ try {
builder = drv->builder;
}
capnp::MallocMessageBuilder requestBuilder;
auto request = requestBuilder.initRoot<build::Request>();
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<std::string> 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);
}
+17 -6
View File
@@ -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<Result<WorkResult>> handleRawChild() noexcept;
kj::Promise<Result<std::optional<WorkResult>>> 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
+25 -20
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
@0xa7f090bdc7816f8f;
using Cxx = import "/capnp/c++.capnp";
$Cxx.namespace("nix::build");
struct Request {
}
+4 -2
View File
@@ -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;
+3 -2
View File
@@ -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.
+9 -5
View File
@@ -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);
});
}
+7 -3
View File
@@ -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);
+1
View File
@@ -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