From 137a55122c8d2044ad6d5cc701865e65eec6b3b0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 9 Sep 2025 13:33:32 +0200 Subject: [PATCH 1/4] Remove support for daemon protocol version < 18 Version 18 was introduced in November 2016 (4b8f1b0ec066a5b994747b1afd050f5f62d857f6). --- src/libstore/daemon.cc | 49 ++++------ src/libstore/remote-store.cc | 173 +++++++++++------------------------ 2 files changed, 74 insertions(+), 148 deletions(-) diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index 4f28a1e0d..87bfe5187 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -572,21 +572,19 @@ static void performOp( case WorkerProto::Op::BuildPaths: { auto drvs = WorkerProto::Serialise::read(*store, rconn); BuildMode mode = bmNormal; - if (GET_PROTOCOL_MINOR(conn.protoVersion) >= 15) { - mode = WorkerProto::Serialise::read(*store, rconn); + mode = WorkerProto::Serialise::read(*store, rconn); - /* Repairing is not atomic, so disallowed for "untrusted" - clients. + /* Repairing is not atomic, so disallowed for "untrusted" + clients. - FIXME: layer violation in this message: the daemon code (i.e. - this file) knows whether a client/connection is trusted, but it - does not how how the client was authenticated. The mechanism - need not be getting the UID of the other end of a Unix Domain - Socket. - */ - if (mode == bmRepair && !trusted) - throw Error("repairing is not allowed because you are not in 'trusted-users'"); - } + FIXME: layer violation in this message: the daemon code (i.e. + this file) knows whether a client/connection is trusted, but it + does not how how the client was authenticated. The mechanism + need not be getting the UID of the other end of a Unix Domain + Socket. + */ + if (mode == bmRepair && !trusted) + throw Error("repairing is not allowed because you are not in 'trusted-users'"); logger->startWork(); store->buildPaths(drvs, mode); logger->stopWork(); @@ -805,13 +803,11 @@ static void performOp( clientSettings.buildCores = readInt(conn.from); clientSettings.useSubstitutes = readInt(conn.from); - if (GET_PROTOCOL_MINOR(conn.protoVersion) >= 12) { - unsigned int n = readInt(conn.from); - for (unsigned int i = 0; i < n; i++) { - auto name = readString(conn.from); - auto value = readString(conn.from); - clientSettings.overrides.emplace(name, value); - } + unsigned int n = readInt(conn.from); + for (unsigned int i = 0; i < n; i++) { + auto name = readString(conn.from); + auto value = readString(conn.from); + clientSettings.overrides.emplace(name, value); } logger->startWork(); @@ -876,19 +872,12 @@ static void performOp( auto path = store->parseStorePath(readString(conn.from)); std::shared_ptr info; logger->startWork(); - try { - info = store->queryPathInfo(path); - } catch (InvalidPath &) { - if (GET_PROTOCOL_MINOR(conn.protoVersion) < 17) - throw; - } + info = store->queryPathInfo(path); logger->stopWork(); if (info) { - if (GET_PROTOCOL_MINOR(conn.protoVersion) >= 17) - conn.to << 1; + conn.to << 1; WorkerProto::write(*store, wconn, static_cast(*info)); } else { - assert(GET_PROTOCOL_MINOR(conn.protoVersion) >= 17); conn.to << 0; } break; @@ -1063,7 +1052,7 @@ void processConnection(ref store, FdSource && from, FdSink && to, Trusted auto [protoVersion, features] = WorkerProto::BasicServerConnection::handshake(to, from, PROTOCOL_VERSION, WorkerProto::allFeatures); - if (protoVersion < 0x10a) + if (protoVersion < 256 + 18) throw Error("the Nix client version is too old"); WorkerProto::BasicServerConnection conn; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 5694fa466..8f11af91f 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -73,6 +73,8 @@ void RemoteStore::initConnection(Connection & conn) try { auto [protoVersion, features] = WorkerProto::BasicClientConnection::handshake(conn.to, tee, PROTOCOL_VERSION, WorkerProto::allFeatures); + if (protoVersion < 256 + 18) + throw Error("the Nix daemon version is too old"); conn.protoVersion = protoVersion; conn.features = features; } catch (SerialisationError & e) { @@ -109,24 +111,22 @@ void RemoteStore::setOptions(Connection & conn) << 0 /* obsolete print build trace */ << settings.buildCores << settings.useSubstitutes; - if (GET_PROTOCOL_MINOR(conn.protoVersion) >= 12) { - std::map overrides; - settings.getSettings(overrides, true); // libstore settings - fileTransferSettings.getSettings(overrides, true); - overrides.erase(settings.keepFailed.name); - overrides.erase(settings.keepGoing.name); - overrides.erase(settings.tryFallback.name); - overrides.erase(settings.maxBuildJobs.name); - overrides.erase(settings.maxSilentTime.name); - overrides.erase(settings.buildCores.name); - overrides.erase(settings.useSubstitutes.name); - overrides.erase(loggerSettings.showTrace.name); - overrides.erase(experimentalFeatureSettings.experimentalFeatures.name); - overrides.erase("plugin-files"); - conn.to << overrides.size(); - for (auto & i : overrides) - conn.to << i.first << i.second.value; - } + std::map overrides; + settings.getSettings(overrides, true); // libstore settings + fileTransferSettings.getSettings(overrides, true); + overrides.erase(settings.keepFailed.name); + overrides.erase(settings.keepGoing.name); + overrides.erase(settings.tryFallback.name); + overrides.erase(settings.maxBuildJobs.name); + overrides.erase(settings.maxSilentTime.name); + overrides.erase(settings.buildCores.name); + overrides.erase(settings.useSubstitutes.name); + overrides.erase(loggerSettings.showTrace.name); + overrides.erase(experimentalFeatureSettings.experimentalFeatures.name); + overrides.erase("plugin-files"); + conn.to << overrides.size(); + for (auto & i : overrides) + conn.to << i.first << i.second.value; auto ex = conn.processStderrReturn(); if (ex) @@ -167,15 +167,7 @@ bool RemoteStore::isValidPathUncached(const StorePath & path) StorePathSet RemoteStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute) { auto conn(getConnection()); - if (GET_PROTOCOL_MINOR(conn->protoVersion) < 12) { - StorePathSet res; - for (auto & i : paths) - if (isValidPath(i)) - res.insert(i); - return res; - } else { - return conn->queryValidPaths(*this, &conn.daemonException, paths, maybeSubstitute); - } + return conn->queryValidPaths(*this, &conn.daemonException, paths, maybeSubstitute); } StorePathSet RemoteStore::queryAllValidPaths() @@ -189,21 +181,10 @@ StorePathSet RemoteStore::queryAllValidPaths() StorePathSet RemoteStore::querySubstitutablePaths(const StorePathSet & paths) { auto conn(getConnection()); - if (GET_PROTOCOL_MINOR(conn->protoVersion) < 12) { - StorePathSet res; - for (auto & i : paths) { - conn->to << WorkerProto::Op::HasSubstitutes << printStorePath(i); - conn.processStderr(); - if (readInt(conn->from)) - res.insert(i); - } - return res; - } else { - conn->to << WorkerProto::Op::QuerySubstitutablePaths; - WorkerProto::write(*this, *conn, paths); - conn.processStderr(); - return WorkerProto::Serialise::read(*this, *conn); - } + conn->to << WorkerProto::Op::QuerySubstitutablePaths; + WorkerProto::write(*this, *conn, paths); + conn.processStderr(); + return WorkerProto::Serialise::read(*this, *conn); } void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, SubstitutablePathInfos & infos) @@ -213,45 +194,24 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S auto conn(getConnection()); - if (GET_PROTOCOL_MINOR(conn->protoVersion) < 12) { - - for (auto & i : pathsMap) { - SubstitutablePathInfo info; - conn->to << WorkerProto::Op::QuerySubstitutablePathInfo << printStorePath(i.first); - conn.processStderr(); - unsigned int reply = readInt(conn->from); - if (reply == 0) - continue; - auto deriver = readString(conn->from); - if (deriver != "") - info.deriver = parseStorePath(deriver); - info.references = WorkerProto::Serialise::read(*this, *conn); - info.downloadSize = readLongLong(conn->from); - info.narSize = readLongLong(conn->from); - infos.insert_or_assign(i.first, std::move(info)); - } - - } else { - - conn->to << WorkerProto::Op::QuerySubstitutablePathInfos; - if (GET_PROTOCOL_MINOR(conn->protoVersion) < 22) { - StorePathSet paths; - for (auto & path : pathsMap) - paths.insert(path.first); - WorkerProto::write(*this, *conn, paths); - } else - WorkerProto::write(*this, *conn, pathsMap); - conn.processStderr(); - size_t count = readNum(conn->from); - for (size_t n = 0; n < count; n++) { - SubstitutablePathInfo & info(infos[parseStorePath(readString(conn->from))]); - auto deriver = readString(conn->from); - if (deriver != "") - info.deriver = parseStorePath(deriver); - info.references = WorkerProto::Serialise::read(*this, *conn); - info.downloadSize = readLongLong(conn->from); - info.narSize = readLongLong(conn->from); - } + conn->to << WorkerProto::Op::QuerySubstitutablePathInfos; + if (GET_PROTOCOL_MINOR(conn->protoVersion) < 22) { + StorePathSet paths; + for (auto & path : pathsMap) + paths.insert(path.first); + WorkerProto::write(*this, *conn, paths); + } else + WorkerProto::write(*this, *conn, pathsMap); + conn.processStderr(); + size_t count = readNum(conn->from); + for (size_t n = 0; n < count; n++) { + SubstitutablePathInfo & info(infos[parseStorePath(readString(conn->from))]); + auto deriver = readString(conn->from); + if (deriver != "") + info.deriver = parseStorePath(deriver); + info.references = WorkerProto::Serialise::read(*this, *conn); + info.downloadSize = readLongLong(conn->from); + info.narSize = readLongLong(conn->from); } } @@ -466,36 +426,20 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source, Repair { auto conn(getConnection()); - if (GET_PROTOCOL_MINOR(conn->protoVersion) < 18) { - auto source2 = sinkToSource([&](Sink & sink) { - sink << 1 // == path follows - ; - copyNAR(source, sink); - sink << exportMagic << printStorePath(info.path); - WorkerProto::write(*this, *conn, info.references); - sink << (info.deriver ? printStorePath(*info.deriver) : "") << 0 // == no legacy signature - << 0 // == no path follows - ; - }); - conn->importPaths(*this, &conn.daemonException, *source2); - } + conn->to << WorkerProto::Op::AddToStoreNar << printStorePath(info.path) + << (info.deriver ? printStorePath(*info.deriver) : "") + << info.narHash.to_string(HashFormat::Base16, false); + WorkerProto::write(*this, *conn, info.references); + conn->to << info.registrationTime << info.narSize << info.ultimate << info.sigs << renderContentAddress(info.ca) + << repair << !checkSigs; - else { - conn->to << WorkerProto::Op::AddToStoreNar << printStorePath(info.path) - << (info.deriver ? printStorePath(*info.deriver) : "") - << info.narHash.to_string(HashFormat::Base16, false); - WorkerProto::write(*this, *conn, info.references); - conn->to << info.registrationTime << info.narSize << info.ultimate << info.sigs << renderContentAddress(info.ca) - << repair << !checkSigs; - - if (GET_PROTOCOL_MINOR(conn->protoVersion) >= 23) { - conn.withFramedSink([&](Sink & sink) { copyNAR(source, sink); }); - } else if (GET_PROTOCOL_MINOR(conn->protoVersion) >= 21) { - conn.processStderr(0, &source); - } else { - copyNAR(source, conn->to); - conn.processStderr(0, nullptr); - } + if (GET_PROTOCOL_MINOR(conn->protoVersion) >= 23) { + conn.withFramedSink([&](Sink & sink) { copyNAR(source, sink); }); + } else if (GET_PROTOCOL_MINOR(conn->protoVersion) >= 21) { + conn.processStderr(0, &source); + } else { + copyNAR(source, conn->to); + conn.processStderr(0, nullptr); } } @@ -618,15 +562,8 @@ void RemoteStore::buildPaths( auto conn(getConnection()); conn->to << WorkerProto::Op::BuildPaths; - assert(GET_PROTOCOL_MINOR(conn->protoVersion) >= 13); WorkerProto::write(*this, *conn, drvPaths); - if (GET_PROTOCOL_MINOR(conn->protoVersion) >= 15) - conn->to << buildMode; - else - /* Old daemons did not take a 'buildMode' parameter, so we - need to validate it here on the client side. */ - if (buildMode != bmNormal) - throw Error("repairing or checking is not supported when building through the Nix daemon"); + conn->to << buildMode; conn.processStderr(); readInt(conn->from); } From 4fb61bc5afabe671b6a7b5d615f2572390fa5bd0 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 9 Sep 2025 13:36:01 +0200 Subject: [PATCH 2/4] Remove WorkerProto::Op::ExportPath This was obsoleted in May 2016 (538a64e8c314f23ba0c5d76201f1c20e71884a21). --- src/libstore/daemon.cc | 11 ----------- src/libstore/include/nix/store/worker-protocol.hh | 1 - 2 files changed, 12 deletions(-) diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index 87bfe5187..ebe0c2ab4 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -546,17 +546,6 @@ static void performOp( break; } - case WorkerProto::Op::ExportPath: { - auto path = store->parseStorePath(readString(conn.from)); - readInt(conn.from); // obsolete - logger->startWork(); - TunnelSink sink(conn.to); - store->exportPath(path, sink); - logger->stopWork(); - conn.to << 1; - break; - } - case WorkerProto::Op::ImportPaths: { logger->startWork(); TunnelSource source(conn.from, conn.to); diff --git a/src/libstore/include/nix/store/worker-protocol.hh b/src/libstore/include/nix/store/worker-protocol.hh index c7f8d5891..3920089fa 100644 --- a/src/libstore/include/nix/store/worker-protocol.hh +++ b/src/libstore/include/nix/store/worker-protocol.hh @@ -152,7 +152,6 @@ enum struct WorkerProto::Op : uint64_t { AddIndirectRoot = 12, SyncWithGC = 13, FindRoots = 14, - ExportPath = 16, // obsolete QueryDeriver = 18, // obsolete SetOptions = 19, CollectGarbage = 20, From 86d19956f25db21919ac0afabca01cd7399ff238 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 9 Sep 2025 13:44:07 +0200 Subject: [PATCH 3/4] Remove WorkerProto::Op::ImportPaths This was obsoleted in May 2016 (538a64e8c314f23ba0c5d76201f1c20e71884a21). --- src/libstore/daemon.cc | 12 ------------ .../include/nix/store/worker-protocol-connection.hh | 2 -- src/libstore/include/nix/store/worker-protocol.hh | 1 - src/libstore/worker-protocol-connection.cc | 8 -------- 4 files changed, 23 deletions(-) diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index ebe0c2ab4..2bd0698a0 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -546,18 +546,6 @@ static void performOp( break; } - case WorkerProto::Op::ImportPaths: { - logger->startWork(); - TunnelSource source(conn.from, conn.to); - auto paths = store->importPaths(source, trusted ? NoCheckSigs : CheckSigs); - logger->stopWork(); - Strings paths2; - for (auto & i : paths) - paths2.push_back(store->printStorePath(i)); - conn.to << paths2; - break; - } - case WorkerProto::Op::BuildPaths: { auto drvs = WorkerProto::Serialise::read(*store, rconn); BuildMode mode = bmNormal; diff --git a/src/libstore/include/nix/store/worker-protocol-connection.hh b/src/libstore/include/nix/store/worker-protocol-connection.hh index 73dd50719..31436395f 100644 --- a/src/libstore/include/nix/store/worker-protocol-connection.hh +++ b/src/libstore/include/nix/store/worker-protocol-connection.hh @@ -130,8 +130,6 @@ struct WorkerProto::BasicClientConnection : WorkerProto::BasicConnection bool * daemonException, const StorePath & path, std::function fun); - - void importPaths(const StoreDirConfig & store, bool * daemonException, Source & source); }; struct WorkerProto::BasicServerConnection : WorkerProto::BasicConnection diff --git a/src/libstore/include/nix/store/worker-protocol.hh b/src/libstore/include/nix/store/worker-protocol.hh index 3920089fa..29d4828c2 100644 --- a/src/libstore/include/nix/store/worker-protocol.hh +++ b/src/libstore/include/nix/store/worker-protocol.hh @@ -161,7 +161,6 @@ enum struct WorkerProto::Op : uint64_t { QueryFailedPaths = 24, ClearFailedPaths = 25, QueryPathInfo = 26, - ImportPaths = 27, // obsolete QueryDerivationOutputNames = 28, // obsolete QueryPathFromHashPart = 29, QuerySubstitutablePathInfos = 30, diff --git a/src/libstore/worker-protocol-connection.cc b/src/libstore/worker-protocol-connection.cc index 987d0c8dd..8a3766290 100644 --- a/src/libstore/worker-protocol-connection.cc +++ b/src/libstore/worker-protocol-connection.cc @@ -313,12 +313,4 @@ void WorkerProto::BasicClientConnection::narFromPath( fun(from); } -void WorkerProto::BasicClientConnection::importPaths( - const StoreDirConfig & store, bool * daemonException, Source & source) -{ - to << WorkerProto::Op::ImportPaths; - processStderr(daemonException, 0, &source); - auto importedPaths = WorkerProto::Serialise::read(store, *this); - assert(importedPaths.size() <= importedPaths.size()); -} } // namespace nix From d1d3ed62410d56f6a6b316dfe47147a4d3b13820 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 10 Sep 2025 10:20:37 +0200 Subject: [PATCH 4/4] Add release note --- doc/manual/rl-next/dropped-compat.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 doc/manual/rl-next/dropped-compat.md diff --git a/doc/manual/rl-next/dropped-compat.md b/doc/manual/rl-next/dropped-compat.md new file mode 100644 index 000000000..d6cc7704a --- /dev/null +++ b/doc/manual/rl-next/dropped-compat.md @@ -0,0 +1,6 @@ +--- +synopsis: "Removed support for daemons and clients older than Nix 2.0" +prs: [13951] +--- + +We have dropped support in the daemon worker protocol for daemons and clients that don't speak at least version 18 of the protocol. This first Nix release that supports this version is Nix 2.0, released in February 2018.