aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/build')
-rw-r--r--src/libstore/build/derivation-goal.cc2
-rw-r--r--src/libstore/build/drv-output-substitution-goal.cc23
-rw-r--r--src/libstore/build/drv-output-substitution-goal.hh12
-rw-r--r--src/libstore/build/goal.cc4
-rw-r--r--src/libstore/build/goal.hh2
-rw-r--r--src/libstore/build/hook-instance.cc2
-rw-r--r--src/libstore/build/local-derivation-goal.cc98
-rw-r--r--src/libstore/build/local-derivation-goal.hh7
8 files changed, 77 insertions, 73 deletions
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 2021d0023..38b73d531 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -732,7 +732,7 @@ void replaceValidPath(const Path & storePath, const Path & tmpPath)
tmpPath (the replacement), so we have to move it out of the
way first. We'd better not be interrupted here, because if
we're repairing (say) Glibc, we end up with a broken system. */
- Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
+ Path oldPath = fmt("%1%.old-%2%-%3%", storePath, getpid(), random());
if (pathExists(storePath))
movePath(storePath, oldPath);
diff --git a/src/libstore/build/drv-output-substitution-goal.cc b/src/libstore/build/drv-output-substitution-goal.cc
index b7f7b5ab1..b30957c84 100644
--- a/src/libstore/build/drv-output-substitution-goal.cc
+++ b/src/libstore/build/drv-output-substitution-goal.cc
@@ -61,20 +61,25 @@ void DrvOutputSubstitutionGoal::tryNext()
// FIXME: Make async
// outputInfo = sub->queryRealisation(id);
- outPipe.create();
- promise = decltype(promise)();
+
+ /* The callback of the curl download below can outlive `this` (if
+ some other error occurs), so it must not touch `this`. So put
+ the shared state in a separate refcounted object. */
+ downloadState = std::make_shared<DownloadState>();
+ downloadState->outPipe.create();
sub->queryRealisation(
- id, { [&](std::future<std::shared_ptr<const Realisation>> res) {
+ id,
+ { [downloadState(downloadState)](std::future<std::shared_ptr<const Realisation>> res) {
try {
- Finally updateStats([this]() { outPipe.writeSide.close(); });
- promise.set_value(res.get());
+ Finally updateStats([&]() { downloadState->outPipe.writeSide.close(); });
+ downloadState->promise.set_value(res.get());
} catch (...) {
- promise.set_exception(std::current_exception());
+ downloadState->promise.set_exception(std::current_exception());
}
} });
- worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
+ worker.childStarted(shared_from_this(), {downloadState->outPipe.readSide.get()}, true, false);
state = &DrvOutputSubstitutionGoal::realisationFetched;
}
@@ -84,7 +89,7 @@ void DrvOutputSubstitutionGoal::realisationFetched()
worker.childTerminated(this);
try {
- outputInfo = promise.get_future().get();
+ outputInfo = downloadState->promise.get_future().get();
} catch (std::exception & e) {
printError(e.what());
substituterFailed = true;
@@ -155,7 +160,7 @@ void DrvOutputSubstitutionGoal::work()
void DrvOutputSubstitutionGoal::handleEOF(int fd)
{
- if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this());
+ if (fd == downloadState->outPipe.readSide.get()) worker.wakeUp(shared_from_this());
}
diff --git a/src/libstore/build/drv-output-substitution-goal.hh b/src/libstore/build/drv-output-substitution-goal.hh
index 948dbda8f..e4b044790 100644
--- a/src/libstore/build/drv-output-substitution-goal.hh
+++ b/src/libstore/build/drv-output-substitution-goal.hh
@@ -16,7 +16,7 @@ class Worker;
// 2. Substitute the corresponding output path
// 3. Register the output info
class DrvOutputSubstitutionGoal : public Goal {
-private:
+
// The drv output we're trying to substitue
DrvOutput id;
@@ -30,9 +30,13 @@ private:
/* The current substituter. */
std::shared_ptr<Store> sub;
- Pipe outPipe;
- std::thread thr;
- std::promise<std::shared_ptr<const Realisation>> promise;
+ struct DownloadState
+ {
+ Pipe outPipe;
+ std::promise<std::shared_ptr<const Realisation>> promise;
+ };
+
+ std::shared_ptr<DownloadState> downloadState;
/* Whether a substituter failed. */
bool substituterFailed = false;
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index 58e805f55..d59b94797 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -78,9 +78,9 @@ void Goal::amDone(ExitCode result, std::optional<Error> ex)
}
-void Goal::trace(const FormatOrString & fs)
+void Goal::trace(std::string_view s)
{
- debug("%1%: %2%", name, fs.s);
+ debug("%1%: %2%", name, s);
}
}
diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh
index 35121c5d9..776eb86bc 100644
--- a/src/libstore/build/goal.hh
+++ b/src/libstore/build/goal.hh
@@ -88,7 +88,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
abort();
}
- void trace(const FormatOrString & fs);
+ void trace(std::string_view s);
std::string getName()
{
diff --git a/src/libstore/build/hook-instance.cc b/src/libstore/build/hook-instance.cc
index cb58a1f02..ea2ae210e 100644
--- a/src/libstore/build/hook-instance.cc
+++ b/src/libstore/build/hook-instance.cc
@@ -35,7 +35,7 @@ HookInstance::HookInstance()
/* Fork the hook. */
pid = startProcess([&]() {
- commonChildInit(fromHook);
+ commonChildInit(fromHook.writeSide.get());
if (chdir("/") == -1) throw SysError("changing into /");
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index a961d8eed..521117c68 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -292,7 +292,7 @@ void LocalDerivationGoal::closeReadPipes()
if (hook) {
DerivationGoal::closeReadPipes();
} else
- builderOut.readSide = -1;
+ builderOut.close();
}
@@ -650,7 +650,7 @@ void LocalDerivationGoal::startBuilder()
/* Clean up the chroot directory automatically. */
autoDelChroot = std::make_shared<AutoDelete>(chrootRootDir);
- printMsg(lvlChatty, format("setting up chroot environment in '%1%'") % chrootRootDir);
+ printMsg(lvlChatty, "setting up chroot environment in '%1%'", chrootRootDir);
// FIXME: make this 0700
if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
@@ -753,8 +753,7 @@ void LocalDerivationGoal::startBuilder()
throw Error("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir);
if (useChroot && settings.preBuildHook != "" && dynamic_cast<Derivation *>(drv.get())) {
- printMsg(lvlChatty, format("executing pre-build hook '%1%'")
- % settings.preBuildHook);
+ printMsg(lvlChatty, "executing pre-build hook '%1%'", settings.preBuildHook);
auto args = useChroot ? Strings({worker.store.printStorePath(drvPath), chrootRootDir}) :
Strings({ worker.store.printStorePath(drvPath) });
enum BuildHookState {
@@ -803,15 +802,13 @@ void LocalDerivationGoal::startBuilder()
/* Create the log file. */
Path logFile = openLogFile();
- /* Create a pipe to get the output of the builder. */
- //builderOut.create();
-
- builderOut.readSide = posix_openpt(O_RDWR | O_NOCTTY);
- if (!builderOut.readSide)
+ /* Create a pseudoterminal to get the output of the builder. */
+ builderOut = posix_openpt(O_RDWR | O_NOCTTY);
+ if (!builderOut)
throw SysError("opening pseudoterminal master");
// FIXME: not thread-safe, use ptsname_r
- std::string slaveName(ptsname(builderOut.readSide.get()));
+ std::string slaveName = ptsname(builderOut.get());
if (buildUser) {
if (chmod(slaveName.c_str(), 0600))
@@ -822,35 +819,14 @@ void LocalDerivationGoal::startBuilder()
}
#if __APPLE__
else {
- if (grantpt(builderOut.readSide.get()))
+ if (grantpt(builderOut.get()))
throw SysError("granting access to pseudoterminal slave");
}
#endif
- #if 0
- // Mount the pt in the sandbox so that the "tty" command works.
- // FIXME: this doesn't work with the new devpts in the sandbox.
- if (useChroot)
- dirsInChroot[slaveName] = {slaveName, false};
- #endif
-
- if (unlockpt(builderOut.readSide.get()))
+ if (unlockpt(builderOut.get()))
throw SysError("unlocking pseudoterminal");
- builderOut.writeSide = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
- if (!builderOut.writeSide)
- throw SysError("opening pseudoterminal slave");
-
- // Put the pt into raw mode to prevent \n -> \r\n translation.
- struct termios term;
- if (tcgetattr(builderOut.writeSide.get(), &term))
- throw SysError("getting pseudoterminal attributes");
-
- cfmakeraw(&term);
-
- if (tcsetattr(builderOut.writeSide.get(), TCSANOW, &term))
- throw SysError("putting pseudoterminal into raw mode");
-
buildResult.startTime = time(0);
/* Fork a child to build the package. */
@@ -898,7 +874,11 @@ void LocalDerivationGoal::startBuilder()
usingUserNamespace = userNamespacesSupported();
+ Pipe sendPid;
+ sendPid.create();
+
Pid helper = startProcess([&]() {
+ sendPid.readSide.close();
/* Drop additional groups here because we can't do it
after we've created the new user namespace. FIXME:
@@ -918,13 +898,14 @@ void LocalDerivationGoal::startBuilder()
if (usingUserNamespace)
options.cloneFlags |= CLONE_NEWUSER;
- pid_t child = startProcess([&]() { runChild(); }, options);
+ pid_t child = startProcess([&]() { runChild(slaveName); }, options);
- writeFull(builderOut.writeSide.get(),
- fmt("%d %d\n", usingUserNamespace, child));
+ writeFull(sendPid.writeSide.get(), fmt("%d\n", child));
_exit(0);
});
+ sendPid.writeSide.close();
+
if (helper.wait() != 0)
throw Error("unable to start build process");
@@ -936,10 +917,9 @@ void LocalDerivationGoal::startBuilder()
userNamespaceSync.writeSide = -1;
});
- auto ss = tokenizeString<std::vector<std::string>>(readLine(builderOut.readSide.get()));
- assert(ss.size() == 2);
- usingUserNamespace = ss[0] == "1";
- pid = string2Int<pid_t>(ss[1]).value();
+ auto ss = tokenizeString<std::vector<std::string>>(readLine(sendPid.readSide.get()));
+ assert(ss.size() == 1);
+ pid = string2Int<pid_t>(ss[0]).value();
if (usingUserNamespace) {
/* Set the UID/GID mapping of the builder's user namespace
@@ -994,21 +974,20 @@ void LocalDerivationGoal::startBuilder()
#endif
{
pid = startProcess([&]() {
- runChild();
+ runChild(slaveName);
});
}
/* parent */
pid.setSeparatePG(true);
- builderOut.writeSide = -1;
- worker.childStarted(shared_from_this(), {builderOut.readSide.get()}, true, true);
+ worker.childStarted(shared_from_this(), {builderOut.get()}, true, true);
/* Check if setting up the build environment failed. */
std::vector<std::string> msgs;
while (true) {
std::string msg = [&]() {
try {
- return readLine(builderOut.readSide.get());
+ return readLine(builderOut.get());
} catch (Error & e) {
auto status = pid.wait();
e.addTrace({}, "while waiting for the build environment for '%s' to initialize (%s, previous messages: %s)",
@@ -1020,7 +999,7 @@ void LocalDerivationGoal::startBuilder()
}();
if (msg.substr(0, 1) == "\2") break;
if (msg.substr(0, 1) == "\1") {
- FdSource source(builderOut.readSide.get());
+ FdSource source(builderOut.get());
auto ex = readError(source);
ex.addTrace({}, "while setting up the build environment");
throw ex;
@@ -1104,7 +1083,7 @@ void LocalDerivationGoal::initEnv()
env["NIX_STORE"] = worker.store.storeDir;
/* The maximum number of cores to utilize for parallel building. */
- env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
+ env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores);
initTmpDir();
@@ -1155,10 +1134,10 @@ void LocalDerivationGoal::writeStructuredAttrs()
writeFile(tmpDir + "/.attrs.sh", rewriteStrings(jsonSh, inputRewrites));
chownToBuilder(tmpDir + "/.attrs.sh");
- env["NIX_ATTRS_SH_FILE"] = tmpDir + "/.attrs.sh";
+ env["NIX_ATTRS_SH_FILE"] = tmpDirInSandbox + "/.attrs.sh";
writeFile(tmpDir + "/.attrs.json", rewriteStrings(json.dump(), inputRewrites));
chownToBuilder(tmpDir + "/.attrs.json");
- env["NIX_ATTRS_JSON_FILE"] = tmpDir + "/.attrs.json";
+ env["NIX_ATTRS_JSON_FILE"] = tmpDirInSandbox + "/.attrs.json";
}
}
@@ -1641,7 +1620,7 @@ void setupSeccomp()
}
-void LocalDerivationGoal::runChild()
+void LocalDerivationGoal::runChild(const Path & slaveName)
{
/* Warning: in the child we should absolutely not make any SQLite
calls! */
@@ -1650,7 +1629,22 @@ void LocalDerivationGoal::runChild()
try { /* child */
- commonChildInit(builderOut);
+ /* Open the slave side of the pseudoterminal. */
+ AutoCloseFD builderOut = open(slaveName.c_str(), O_RDWR | O_NOCTTY);
+ if (!builderOut)
+ throw SysError("opening pseudoterminal slave");
+
+ // Put the pt into raw mode to prevent \n -> \r\n translation.
+ struct termios term;
+ if (tcgetattr(builderOut.get(), &term))
+ throw SysError("getting pseudoterminal attributes");
+
+ cfmakeraw(&term);
+
+ if (tcsetattr(builderOut.get(), TCSANOW, &term))
+ throw SysError("putting pseudoterminal into raw mode");
+
+ commonChildInit(builderOut.get());
try {
setupSeccomp();
@@ -2063,7 +2057,7 @@ void LocalDerivationGoal::runChild()
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms
to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */
- Path globalTmpDir = canonPath(getEnv("TMPDIR").value_or("/tmp"), true);
+ Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true);
/* They don't like trailing slashes on subpath directives */
if (globalTmpDir.back() == '/') globalTmpDir.pop_back();
@@ -2892,7 +2886,7 @@ void LocalDerivationGoal::deleteTmpDir(bool force)
bool LocalDerivationGoal::isReadDesc(int fd)
{
return (hook && DerivationGoal::isReadDesc(fd)) ||
- (!hook && fd == builderOut.readSide.get());
+ (!hook && fd == builderOut.get());
}
diff --git a/src/libstore/build/local-derivation-goal.hh b/src/libstore/build/local-derivation-goal.hh
index 34c4e9187..4d2f1ac28 100644
--- a/src/libstore/build/local-derivation-goal.hh
+++ b/src/libstore/build/local-derivation-goal.hh
@@ -24,8 +24,9 @@ struct LocalDerivationGoal : public DerivationGoal
/* The path of the temporary directory in the sandbox. */
Path tmpDirInSandbox;
- /* Pipe for the builder's standard output/error. */
- Pipe builderOut;
+ /* Master side of the pseudoterminal used for the builder's
+ standard output/error. */
+ AutoCloseFD builderOut;
/* Pipe for synchronising updates to the builder namespaces. */
Pipe userNamespaceSync;
@@ -168,7 +169,7 @@ struct LocalDerivationGoal : public DerivationGoal
int getChildStatus() override;
/* Run the builder's process. */
- void runChild();
+ void runChild(const std::string & slaveName);
/* Check that the derivation outputs all exist and register them
as valid. */