mirror of
https://github.com/NixOS/nix.git
synced 2025-12-03 07:31:00 +01:00
Merge remote-tracking branch 'origin/master' into best-effort-supplementary-groups
This commit is contained in:
commit
25b20b4ad2
236 changed files with 5449 additions and 2033 deletions
|
|
@ -9,6 +9,7 @@
|
|||
#include "archive.hh"
|
||||
#include "compression.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "worker-protocol-impl.hh"
|
||||
#include "topo-sort.hh"
|
||||
#include "callback.hh"
|
||||
#include "local-store.hh" // TODO remove, along with remaining downcasts
|
||||
|
|
@ -1150,9 +1151,11 @@ HookReply DerivationGoal::tryBuildHook()
|
|||
throw;
|
||||
}
|
||||
|
||||
WorkerProto::WriteConn conn { hook->sink };
|
||||
|
||||
/* Tell the hook all the inputs that have to be copied to the
|
||||
remote system. */
|
||||
worker_proto::write(worker.store, hook->sink, inputPaths);
|
||||
WorkerProto::write(worker.store, conn, inputPaths);
|
||||
|
||||
/* Tell the hooks the missing outputs that have to be copied back
|
||||
from the remote system. */
|
||||
|
|
@ -1163,7 +1166,7 @@ HookReply DerivationGoal::tryBuildHook()
|
|||
if (buildMode != bmCheck && status.known && status.known->isValid()) continue;
|
||||
missingOutputs.insert(outputName);
|
||||
}
|
||||
worker_proto::write(worker.store, hook->sink, missingOutputs);
|
||||
WorkerProto::write(worker.store, conn, missingOutputs);
|
||||
}
|
||||
|
||||
hook->sink = FdSink();
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod
|
|||
}
|
||||
|
||||
if (failed.size() == 1 && ex) {
|
||||
ex->status = worker.exitStatus();
|
||||
ex->status = worker.failingExitStatus();
|
||||
throw std::move(*ex);
|
||||
} else if (!failed.empty()) {
|
||||
if (ex) logError(ex->info());
|
||||
throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed));
|
||||
throw Error(worker.failingExitStatus(), "build of %s failed", showPaths(failed));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,15 +102,15 @@ void Store::ensurePath(const StorePath & path)
|
|||
|
||||
if (goal->exitCode != Goal::ecSuccess) {
|
||||
if (goal->ex) {
|
||||
goal->ex->status = worker.exitStatus();
|
||||
goal->ex->status = worker.failingExitStatus();
|
||||
throw std::move(*goal->ex);
|
||||
} else
|
||||
throw Error(worker.exitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
|
||||
throw Error(worker.failingExitStatus(), "path '%s' does not exist and cannot be created", printStorePath(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LocalStore::repairPath(const StorePath & path)
|
||||
void Store::repairPath(const StorePath & path)
|
||||
{
|
||||
Worker worker(*this, *this);
|
||||
GoalPtr goal = worker.makePathSubstitutionGoal(path, Repair);
|
||||
|
|
@ -128,7 +128,7 @@ void LocalStore::repairPath(const StorePath & path)
|
|||
goals.insert(worker.makeDerivationGoal(*info->deriver, OutputsSpec::All { }, bmRepair));
|
||||
worker.run(goals);
|
||||
} else
|
||||
throw Error(worker.exitStatus(), "cannot repair path '%s'", printStorePath(path));
|
||||
throw Error(worker.failingExitStatus(), "cannot repair path '%s'", printStorePath(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@ namespace nix {
|
|||
|
||||
HookInstance::HookInstance()
|
||||
{
|
||||
debug("starting build hook '%s'", settings.buildHook);
|
||||
debug("starting build hook '%s'", concatStringsSep(" ", settings.buildHook.get()));
|
||||
|
||||
auto buildHookArgs = tokenizeString<std::list<std::string>>(settings.buildHook.get());
|
||||
auto buildHookArgs = settings.buildHook.get();
|
||||
|
||||
if (buildHookArgs.empty())
|
||||
throw Error("'build-hook' setting is empty");
|
||||
|
||||
auto buildHook = buildHookArgs.front();
|
||||
auto buildHook = canonPath(buildHookArgs.front());
|
||||
buildHookArgs.pop_front();
|
||||
|
||||
Strings args;
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@
|
|||
#include "worker.hh"
|
||||
#include "builtins.hh"
|
||||
#include "builtins/buildenv.hh"
|
||||
#include "references.hh"
|
||||
#include "path-references.hh"
|
||||
#include "finally.hh"
|
||||
#include "util.hh"
|
||||
#include "archive.hh"
|
||||
#include "compression.hh"
|
||||
#include "daemon.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "topo-sort.hh"
|
||||
#include "callback.hh"
|
||||
#include "json-utils.hh"
|
||||
|
|
@ -65,8 +64,9 @@ void handleDiffHook(
|
|||
const Path & tryA, const Path & tryB,
|
||||
const Path & drvPath, const Path & tmpDir)
|
||||
{
|
||||
auto diffHook = settings.diffHook;
|
||||
if (diffHook != "" && settings.runDiffHook) {
|
||||
auto & diffHookOpt = settings.diffHook.get();
|
||||
if (diffHookOpt && settings.runDiffHook) {
|
||||
auto & diffHook = *diffHookOpt;
|
||||
try {
|
||||
auto diffRes = runProgram(RunOptions {
|
||||
.program = diffHook,
|
||||
|
|
@ -357,7 +357,7 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull()
|
|||
for (auto & [_, status] : initialOutputs) {
|
||||
if (!status.known) continue;
|
||||
if (buildMode != bmCheck && status.known->isValid()) continue;
|
||||
auto p = worker.store.printStorePath(status.known->path);
|
||||
auto p = worker.store.toRealPath(status.known->path);
|
||||
if (pathExists(chrootRootDir + p))
|
||||
renameFile((chrootRootDir + p), p);
|
||||
}
|
||||
|
|
@ -395,8 +395,9 @@ static void linkOrCopy(const Path & from, const Path & to)
|
|||
bind-mount in this case?
|
||||
|
||||
It can also fail with EPERM in BeegFS v7 and earlier versions
|
||||
or fail with EXDEV in OpenAFS
|
||||
which don't allow hard-links to other directories */
|
||||
if (errno != EMLINK && errno != EPERM)
|
||||
if (errno != EMLINK && errno != EPERM && errno != EXDEV)
|
||||
throw SysError("linking '%s' to '%s'", to, from);
|
||||
copyPath(from, to);
|
||||
}
|
||||
|
|
@ -1423,7 +1424,8 @@ void LocalDerivationGoal::startDaemon()
|
|||
Store::Params params;
|
||||
params["path-info-cache-size"] = "0";
|
||||
params["store"] = worker.store.storeDir;
|
||||
params["root"] = getLocalStore().rootDir;
|
||||
if (auto & optRoot = getLocalStore().rootDir.get())
|
||||
params["root"] = *optRoot;
|
||||
params["state"] = "/no-such-path";
|
||||
params["log"] = "/no-such-path";
|
||||
auto store = make_ref<RestrictedStore>(params,
|
||||
|
|
@ -1452,7 +1454,7 @@ void LocalDerivationGoal::startDaemon()
|
|||
(struct sockaddr *) &remoteAddr, &remoteAddrLen);
|
||||
if (!remote) {
|
||||
if (errno == EINTR || errno == EAGAIN) continue;
|
||||
if (errno == EINVAL) break;
|
||||
if (errno == EINVAL || errno == ECONNABORTED) break;
|
||||
throw SysError("accepting connection");
|
||||
}
|
||||
|
||||
|
|
@ -1482,8 +1484,22 @@ void LocalDerivationGoal::startDaemon()
|
|||
|
||||
void LocalDerivationGoal::stopDaemon()
|
||||
{
|
||||
if (daemonSocket && shutdown(daemonSocket.get(), SHUT_RDWR) == -1)
|
||||
throw SysError("shutting down daemon socket");
|
||||
if (daemonSocket && shutdown(daemonSocket.get(), SHUT_RDWR) == -1) {
|
||||
// According to the POSIX standard, the 'shutdown' function should
|
||||
// return an ENOTCONN error when attempting to shut down a socket that
|
||||
// hasn't been connected yet. This situation occurs when the 'accept'
|
||||
// function is called on a socket without any accepted connections,
|
||||
// leaving the socket unconnected. While Linux doesn't seem to produce
|
||||
// an error for sockets that have only been accepted, more
|
||||
// POSIX-compliant operating systems like OpenBSD, macOS, and others do
|
||||
// return the ENOTCONN error. Therefore, we handle this error here to
|
||||
// avoid raising an exception for compliant behaviour.
|
||||
if (errno == ENOTCONN) {
|
||||
daemonSocket.close();
|
||||
} else {
|
||||
throw SysError("shutting down daemon socket");
|
||||
}
|
||||
}
|
||||
|
||||
if (daemonThread.joinable())
|
||||
daemonThread.join();
|
||||
|
|
@ -1494,7 +1510,8 @@ void LocalDerivationGoal::stopDaemon()
|
|||
thread.join();
|
||||
daemonWorkerThreads.clear();
|
||||
|
||||
daemonSocket = -1;
|
||||
// release the socket.
|
||||
daemonSocket.close();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1771,6 +1788,9 @@ void LocalDerivationGoal::runChild()
|
|||
for (auto & path : { "/etc/resolv.conf", "/etc/services", "/etc/hosts" })
|
||||
if (pathExists(path))
|
||||
ss.push_back(path);
|
||||
|
||||
if (settings.caFile != "")
|
||||
dirsInChroot.try_emplace("/etc/ssl/certs/ca-certificates.crt", settings.caFile, true);
|
||||
}
|
||||
|
||||
for (auto & i : ss) dirsInChroot.emplace(i, i);
|
||||
|
|
@ -2371,18 +2391,21 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
continue;
|
||||
auto references = *referencesOpt;
|
||||
|
||||
auto rewriteOutput = [&]() {
|
||||
auto rewriteOutput = [&](const StringMap & rewrites) {
|
||||
/* Apply hash rewriting if necessary. */
|
||||
if (!outputRewrites.empty()) {
|
||||
if (!rewrites.empty()) {
|
||||
debug("rewriting hashes in '%1%'; cross fingers", actualPath);
|
||||
|
||||
/* FIXME: this is in-memory. */
|
||||
StringSink sink;
|
||||
dumpPath(actualPath, sink);
|
||||
/* FIXME: Is this actually streaming? */
|
||||
auto source = sinkToSource([&](Sink & nextSink) {
|
||||
RewritingSink rsink(rewrites, nextSink);
|
||||
dumpPath(actualPath, rsink);
|
||||
rsink.flush();
|
||||
});
|
||||
Path tmpPath = actualPath + ".tmp";
|
||||
restorePath(tmpPath, *source);
|
||||
deletePath(actualPath);
|
||||
sink.s = rewriteStrings(sink.s, outputRewrites);
|
||||
StringSource source(sink.s);
|
||||
restorePath(actualPath, source);
|
||||
movePath(tmpPath, actualPath);
|
||||
|
||||
/* FIXME: set proper permissions in restorePath() so
|
||||
we don't have to do another traversal. */
|
||||
|
|
@ -2431,7 +2454,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
"since recursive hashing is not enabled (one of outputHashMode={flat,text} is true)",
|
||||
actualPath);
|
||||
}
|
||||
rewriteOutput();
|
||||
rewriteOutput(outputRewrites);
|
||||
/* FIXME optimize and deduplicate with addToStore */
|
||||
std::string oldHashPart { scratchPath->hashPart() };
|
||||
HashModuloSink caSink { outputHash.hashType, oldHashPart };
|
||||
|
|
@ -2469,16 +2492,14 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
Hash::dummy,
|
||||
};
|
||||
if (*scratchPath != newInfo0.path) {
|
||||
// Also rewrite the output path
|
||||
auto source = sinkToSource([&](Sink & nextSink) {
|
||||
RewritingSink rsink2(oldHashPart, std::string(newInfo0.path.hashPart()), nextSink);
|
||||
dumpPath(actualPath, rsink2);
|
||||
rsink2.flush();
|
||||
});
|
||||
Path tmpPath = actualPath + ".tmp";
|
||||
restorePath(tmpPath, *source);
|
||||
deletePath(actualPath);
|
||||
movePath(tmpPath, actualPath);
|
||||
// If the path has some self-references, we need to rewrite
|
||||
// them.
|
||||
// (note that this doesn't invalidate the ca hash we calculated
|
||||
// above because it's computed *modulo the self-references*, so
|
||||
// it already takes this rewrite into account).
|
||||
rewriteOutput(
|
||||
StringMap{{oldHashPart,
|
||||
std::string(newInfo0.path.hashPart())}});
|
||||
}
|
||||
|
||||
HashResult narHashAndSize = hashPath(htSHA256, actualPath);
|
||||
|
|
@ -2500,7 +2521,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
outputRewrites.insert_or_assign(
|
||||
std::string { scratchPath->hashPart() },
|
||||
std::string { requiredFinalPath.hashPart() });
|
||||
rewriteOutput();
|
||||
rewriteOutput(outputRewrites);
|
||||
auto narHashAndSize = hashPath(htSHA256, actualPath);
|
||||
ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first };
|
||||
newInfo0.narSize = narHashAndSize.second;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ void setPersonality(std::string_view system)
|
|||
&& (std::string_view(SYSTEM) == "x86_64-linux"
|
||||
|| (!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64"))))
|
||||
|| system == "armv7l-linux"
|
||||
|| system == "armv6l-linux")
|
||||
|| system == "armv6l-linux"
|
||||
|| system == "armv5tel-linux")
|
||||
{
|
||||
if (personality(PER_LINUX32) == -1)
|
||||
throw SysError("cannot set 32-bit personality");
|
||||
|
|
|
|||
|
|
@ -468,16 +468,9 @@ void Worker::waitForInput()
|
|||
}
|
||||
|
||||
|
||||
unsigned int Worker::exitStatus()
|
||||
unsigned int Worker::failingExitStatus()
|
||||
{
|
||||
/*
|
||||
* 1100100
|
||||
* ^^^^
|
||||
* |||`- timeout
|
||||
* ||`-- output hash mismatch
|
||||
* |`--- build failure
|
||||
* `---- not deterministic
|
||||
*/
|
||||
// See API docs in header for explanation
|
||||
unsigned int mask = 0;
|
||||
bool buildFailure = permanentFailure || timedOut || hashMismatch;
|
||||
if (buildFailure)
|
||||
|
|
|
|||
|
|
@ -280,7 +280,28 @@ public:
|
|||
*/
|
||||
void waitForInput();
|
||||
|
||||
unsigned int exitStatus();
|
||||
/***
|
||||
* The exit status in case of failure.
|
||||
*
|
||||
* In the case of a build failure, returned value follows this
|
||||
* bitmask:
|
||||
*
|
||||
* ```
|
||||
* 0b1100100
|
||||
* ^^^^
|
||||
* |||`- timeout
|
||||
* ||`-- output hash mismatch
|
||||
* |`--- build failure
|
||||
* `---- not deterministic
|
||||
* ```
|
||||
*
|
||||
* In other words, the failure code is at least 100 (0b1100100), but
|
||||
* might also be greater.
|
||||
*
|
||||
* Otherwise (no build failure, but some other sort of failure by
|
||||
* assumption), this returned value is 1.
|
||||
*/
|
||||
unsigned int failingExitStatus();
|
||||
|
||||
/**
|
||||
* Check whether the given valid path exists and has the right
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue