aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/build.cc97
-rw-r--r--src/libstore/daemon.cc23
-rw-r--r--src/libstore/daemon.hh2
-rw-r--r--src/libstore/derivations.hh2
-rw-r--r--src/libstore/dummy-store.cc5
-rw-r--r--src/libstore/filetransfer.cc2
-rw-r--r--src/libstore/gc.cc1
-rw-r--r--src/libstore/globals.cc2
-rw-r--r--src/libstore/http-binary-cache-store.cc2
-rw-r--r--src/libstore/legacy-ssh-store.cc2
-rw-r--r--src/libstore/local-binary-cache-store.cc2
-rw-r--r--src/libstore/local-fs-store.cc1
-rw-r--r--src/libstore/local-fs-store.hh48
-rw-r--r--src/libstore/local-store.hh1
-rw-r--r--src/libstore/optimise-store.cc12
-rw-r--r--src/libstore/parsed-derivations.hh2
-rw-r--r--src/libstore/profiles.cc1
-rw-r--r--src/libstore/remote-store.cc85
-rw-r--r--src/libstore/remote-store.hh44
-rw-r--r--src/libstore/s3-binary-cache-store.cc2
-rw-r--r--src/libstore/ssh-store.cc2
-rw-r--r--src/libstore/store-api.cc2
-rw-r--r--src/libstore/store-api.hh43
-rw-r--r--src/libstore/uds-remote-store.cc81
-rw-r--r--src/libstore/uds-remote-store.hh52
-rw-r--r--src/libstore/worker-protocol.hh50
26 files changed, 310 insertions, 256 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 12ce6f2ec..48e123f36 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -831,6 +831,10 @@ private:
paths to the sandbox as a result of recursive Nix calls. */
AutoCloseFD sandboxMountNamespace;
+ /* On Linux, whether we're doing the build in its own user
+ namespace. */
+ bool usingUserNamespace = true;
+
/* The build hook. */
std::unique_ptr<HookInstance> hook;
@@ -920,8 +924,8 @@ private:
result. */
std::map<Path, ValidPathInfo> prevInfos;
- const uid_t sandboxUid = 1000;
- const gid_t sandboxGid = 100;
+ uid_t sandboxUid() { return usingUserNamespace ? 1000 : buildUser->getUID(); }
+ gid_t sandboxGid() { return usingUserNamespace ? 100 : buildUser->getGID(); }
const static Path homeDir;
@@ -2355,7 +2359,8 @@ void DerivationGoal::startBuilder()
worker.store.computeFSClosure(worker.store.toStorePath(i.second.source).first, closure);
} catch (InvalidPath & e) {
} catch (Error & e) {
- throw Error("while processing 'sandbox-paths': %s", e.what());
+ e.addTrace({}, "while processing 'sandbox-paths'");
+ throw;
}
for (auto & i : closure) {
auto p = worker.store.printStorePath(i);
@@ -2423,15 +2428,14 @@ void DerivationGoal::startBuilder()
"root:x:0:0:Nix build user:%3%:/noshell\n"
"nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n"
"nobody:x:65534:65534:Nobody:/:/noshell\n",
- sandboxUid, sandboxGid, settings.sandboxBuildDir));
+ sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
/* Declare the build user's group so that programs get a consistent
view of the system (e.g., "id -gn"). */
writeFile(chrootRootDir + "/etc/group",
- (format(
- "root:x:0:\n"
+ fmt("root:x:0:\n"
"nixbld:!:%1%:\n"
- "nogroup:x:65534:\n") % sandboxGid).str());
+ "nogroup:x:65534:\n", sandboxGid()));
/* Create /etc/hosts with localhost entry. */
if (!(derivationIsImpure(derivationType)))
@@ -2628,6 +2632,13 @@ void DerivationGoal::startBuilder()
options.allowVfork = false;
+ Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces";
+ static bool userNamespacesEnabled =
+ pathExists(maxUserNamespaces)
+ && trim(readFile(maxUserNamespaces)) != "0";
+
+ usingUserNamespace = userNamespacesEnabled;
+
Pid helper = startProcess([&]() {
/* Drop additional groups here because we can't do it
@@ -2646,9 +2657,11 @@ void DerivationGoal::startBuilder()
PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
if (stack == MAP_FAILED) throw SysError("allocating stack");
- int flags = CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
+ int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD;
if (privateNetwork)
flags |= CLONE_NEWNET;
+ if (usingUserNamespace)
+ flags |= CLONE_NEWUSER;
pid_t child = clone(childEntry, stack + stackSize, flags, this);
if (child == -1 && errno == EINVAL) {
@@ -2657,11 +2670,12 @@ void DerivationGoal::startBuilder()
flags &= ~CLONE_NEWPID;
child = clone(childEntry, stack + stackSize, flags, this);
}
- if (child == -1 && (errno == EPERM || errno == EINVAL)) {
+ if (usingUserNamespace && child == -1 && (errno == EPERM || errno == EINVAL)) {
/* Some distros patch Linux to not allow unprivileged
* user namespaces. If we get EPERM or EINVAL, try
* without CLONE_NEWUSER and see if that works.
*/
+ usingUserNamespace = false;
flags &= ~CLONE_NEWUSER;
child = clone(childEntry, stack + stackSize, flags, this);
}
@@ -2672,7 +2686,8 @@ void DerivationGoal::startBuilder()
_exit(1);
if (child == -1) throw SysError("cloning builder process");
- writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n");
+ writeFull(builderOut.writeSide.get(),
+ fmt("%d %d\n", usingUserNamespace, child));
_exit(0);
}, options);
@@ -2686,23 +2701,38 @@ void DerivationGoal::startBuilder()
userNamespaceSync.readSide = -1;
+ /* Close the write side to prevent runChild() from hanging
+ reading from this. */
+ Finally cleanup([&]() {
+ userNamespaceSync.writeSide = -1;
+ });
+
pid_t tmp;
- if (!string2Int<pid_t>(readLine(builderOut.readSide.get()), tmp)) abort();
+ auto ss = tokenizeString<std::vector<std::string>>(readLine(builderOut.readSide.get()));
+ assert(ss.size() == 2);
+ usingUserNamespace = ss[0] == "1";
+ if (!string2Int<pid_t>(ss[1], tmp)) abort();
pid = tmp;
- /* Set the UID/GID mapping of the builder's user namespace
- such that the sandbox user maps to the build user, or to
- the calling user (if build users are disabled). */
- uid_t hostUid = buildUser ? buildUser->getUID() : getuid();
- uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
+ if (usingUserNamespace) {
+ /* Set the UID/GID mapping of the builder's user namespace
+ such that the sandbox user maps to the build user, or to
+ the calling user (if build users are disabled). */
+ uid_t hostUid = buildUser ? buildUser->getUID() : getuid();
+ uid_t hostGid = buildUser ? buildUser->getGID() : getgid();
- writeFile("/proc/" + std::to_string(pid) + "/uid_map",
- (format("%d %d 1") % sandboxUid % hostUid).str());
+ writeFile("/proc/" + std::to_string(pid) + "/uid_map",
+ fmt("%d %d 1", sandboxUid(), hostUid));
- writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
+ writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny");
- writeFile("/proc/" + std::to_string(pid) + "/gid_map",
- (format("%d %d 1") % sandboxGid % hostGid).str());
+ writeFile("/proc/" + std::to_string(pid) + "/gid_map",
+ fmt("%d %d 1", sandboxGid(), hostGid));
+ } else {
+ debug("note: not using a user namespace");
+ if (!buildUser)
+ throw Error("cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces");
+ }
/* Save the mount namespace of the child. We have to do this
*before* the child does a chroot. */
@@ -2712,7 +2742,6 @@ void DerivationGoal::startBuilder()
/* Signal the builder that we've updated its user namespace. */
writeFull(userNamespaceSync.writeSide.get(), "1");
- userNamespaceSync.writeSide = -1;
} else
#endif
@@ -2732,11 +2761,14 @@ void DerivationGoal::startBuilder()
/* Check if setting up the build environment failed. */
while (true) {
string msg = readLine(builderOut.readSide.get());
+ if (string(msg, 0, 1) == "\2") break;
if (string(msg, 0, 1) == "\1") {
- if (msg.size() == 1) break;
- throw Error(string(msg, 1));
+ FdSource source(builderOut.readSide.get());
+ auto ex = readError(source);
+ ex.addTrace({}, "while setting up the build environment");
+ throw ex;
}
- debug(msg);
+ debug("sandbox setup: " + msg);
}
}
@@ -3560,9 +3592,9 @@ void DerivationGoal::runChild()
/* Switch to the sandbox uid/gid in the user namespace,
which corresponds to the build user or calling user in
the parent namespace. */
- if (setgid(sandboxGid) == -1)
+ if (setgid(sandboxGid()) == -1)
throw SysError("setgid failed");
- if (setuid(sandboxUid) == -1)
+ if (setuid(sandboxUid()) == -1)
throw SysError("setuid failed");
setUser = false;
@@ -3780,7 +3812,7 @@ void DerivationGoal::runChild()
args.push_back(rewriteStrings(i, inputRewrites));
/* Indicate that we managed to set up the build environment. */
- writeFull(STDERR_FILENO, string("\1\n"));
+ writeFull(STDERR_FILENO, string("\2\n"));
/* Execute the program. This should not return. */
if (drv->isBuiltin()) {
@@ -3801,7 +3833,7 @@ void DerivationGoal::runChild()
throw Error("unsupported builtin function '%1%'", string(drv->builder, 8));
_exit(0);
} catch (std::exception & e) {
- writeFull(STDERR_FILENO, "error: " + string(e.what()) + "\n");
+ writeFull(STDERR_FILENO, e.what() + std::string("\n"));
_exit(1);
}
}
@@ -3810,8 +3842,11 @@ void DerivationGoal::runChild()
throw SysError("executing '%1%'", drv->builder);
- } catch (std::exception & e) {
- writeFull(STDERR_FILENO, "\1while setting up the build environment: " + string(e.what()) + "\n");
+ } catch (Error & e) {
+ writeFull(STDERR_FILENO, "\1\n");
+ FdSink sink(STDERR_FILENO);
+ sink << e;
+ sink.flush();
_exit(1);
}
}
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 36953975a..7ae88b49a 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -101,17 +101,20 @@ struct TunnelLogger : public Logger
/* stopWork() means that we're done; stop sending stderr to the
client. */
- void stopWork(bool success = true, const string & msg = "", unsigned int status = 0)
+ void stopWork(const Error * ex = nullptr)
{
auto state(state_.lock());
state->canSendStderr = false;
- if (success)
+ if (!ex)
to << STDERR_LAST;
else {
- to << STDERR_ERROR << msg;
- if (status != 0) to << status;
+ if (GET_PROTOCOL_MINOR(clientVersion) >= 26) {
+ to << STDERR_ERROR << *ex;
+ } else {
+ to << STDERR_ERROR << ex->what() << ex->status;
+ }
}
}
@@ -935,10 +938,11 @@ void processConnection(
during addTextToStore() / importPath(). If that
happens, just send the error message and exit. */
bool errorAllowed = tunnelLogger->state_.lock()->canSendStderr;
- tunnelLogger->stopWork(false, e.msg(), e.status);
+ tunnelLogger->stopWork(&e);
if (!errorAllowed) throw;
} catch (std::bad_alloc & e) {
- tunnelLogger->stopWork(false, "Nix daemon out of memory", 1);
+ auto ex = Error("Nix daemon out of memory");
+ tunnelLogger->stopWork(&ex);
throw;
}
@@ -947,8 +951,13 @@ void processConnection(
assert(!tunnelLogger->state_.lock()->canSendStderr);
};
+ } catch (Error & e) {
+ tunnelLogger->stopWork(&e);
+ to.flush();
+ return;
} catch (std::exception & e) {
- tunnelLogger->stopWork(false, e.what(), 1);
+ auto ex = Error(e.what());
+ tunnelLogger->stopWork(&ex);
to.flush();
return;
}
diff --git a/src/libstore/daemon.hh b/src/libstore/daemon.hh
index 841ace316..67755d54e 100644
--- a/src/libstore/daemon.hh
+++ b/src/libstore/daemon.hh
@@ -1,3 +1,5 @@
+#pragma once
+
#include "serialise.hh"
#include "store-api.hh"
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index be19aa300..e2e5578a8 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -61,8 +61,6 @@ typedef std::map<string, DerivationOutput> DerivationOutputs;
also contains, for each output, the (optional) store path in which it would
be written. To calculate values of these types, see the corresponding
functions in BasicDerivation */
-typedef std::map<string, std::pair<DerivationOutput, StorePath>>
- DerivationOutputsAndPaths;
typedef std::map<string, std::pair<DerivationOutput, std::optional<StorePath>>>
DerivationOutputsAndOptPaths;
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index 49641c2ac..98b745c3a 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -18,8 +18,7 @@ struct DummyStore : public Store, public virtual DummyStoreConfig
DummyStore(const Params & params)
: StoreConfig(params)
, Store(params)
- {
- }
+ { }
string getUri() override
{
@@ -63,6 +62,6 @@ struct DummyStore : public Store, public virtual DummyStoreConfig
{ unsupported("buildDerivation"); }
};
-static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regStore;
+static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regDummyStore;
}
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index cd619672f..c2c65af05 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -31,7 +31,7 @@ namespace nix {
FileTransferSettings fileTransferSettings;
-static GlobalConfig::Register r1(&fileTransferSettings);
+static GlobalConfig::Register rFileTransferSettings(&fileTransferSettings);
std::string resolveUri(const std::string & uri)
{
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 518a357ef..7a04b2f89 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -1,6 +1,7 @@
#include "derivations.hh"
#include "globals.hh"
#include "local-store.hh"
+#include "local-fs-store.hh"
#include "finally.hh"
#include <functional>
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index c5734852d..1238dc530 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -25,7 +25,7 @@ namespace nix {
Settings settings;
-static GlobalConfig::Register r1(&settings);
+static GlobalConfig::Register rSettings(&settings);
Settings::Settings()
: nixPrefix(NIX_PREFIX)
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 3d3d91e5e..9d2a89f96 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -181,6 +181,6 @@ protected:
};
-static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regStore;
+static RegisterStoreImplementation<HttpBinaryCacheStore, HttpBinaryCacheStoreConfig> regHttpBinaryCacheStore;
}
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index 17d9dd1df..e440536df 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -334,6 +334,6 @@ public:
}
};
-static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regStore;
+static RegisterStoreImplementation<LegacySSHStore, LegacySSHStoreConfig> regLegacySSHStore;
}
diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc
index b5744448e..7d979c5c2 100644
--- a/src/libstore/local-binary-cache-store.cc
+++ b/src/libstore/local-binary-cache-store.cc
@@ -105,6 +105,6 @@ std::set<std::string> LocalBinaryCacheStore::uriSchemes()
return {"file"};
}
-static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regStore;
+static RegisterStoreImplementation<LocalBinaryCacheStore, LocalBinaryCacheStoreConfig> regLocalBinaryCacheStore;
}
diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc
index 2f1d9663a..e7c3dae92 100644
--- a/src/libstore/local-fs-store.cc
+++ b/src/libstore/local-fs-store.cc
@@ -1,6 +1,7 @@
#include "archive.hh"
#include "fs-accessor.hh"
#include "store-api.hh"
+#include "local-fs-store.hh"
#include "globals.hh"
#include "compression.hh"
#include "derivations.hh"
diff --git a/src/libstore/local-fs-store.hh b/src/libstore/local-fs-store.hh
new file mode 100644
index 000000000..8eccd8236
--- /dev/null
+++ b/src/libstore/local-fs-store.hh
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "store-api.hh"
+
+namespace nix {
+
+struct LocalFSStoreConfig : virtual StoreConfig
+{
+ using StoreConfig::StoreConfig;
+ // FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
+ // it to omit the call to the Setting constructor. Clang works fine
+ // either way.
+ const PathSetting rootDir{(StoreConfig*) this, true, "",
+ "root", "directory prefixed to all other paths"};
+ const PathSetting stateDir{(StoreConfig*) this, false,
+ rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
+ "state", "directory where Nix will store state"};
+ const PathSetting logDir{(StoreConfig*) this, false,
+ rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
+ "log", "directory where Nix will store state"};
+};
+
+class LocalFSStore : public virtual Store, public virtual LocalFSStoreConfig
+{
+public:
+
+ const static string drvsLogDir;
+
+ LocalFSStore(const Params & params);
+
+ void narFromPath(const StorePath & path, Sink & sink) override;
+ ref<FSAccessor> getFSAccessor() override;
+
+ /* Register a permanent GC root. */
+ Path addPermRoot(const StorePath & storePath, const Path & gcRoot);
+
+ virtual Path getRealStoreDir() { return storeDir; }
+
+ Path toRealPath(const Path & storePath) override
+ {
+ assert(isInStore(storePath));
+ return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
+ }
+
+ std::shared_ptr<std::string> getBuildLog(const StorePath & path) override;
+};
+
+}
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index e7c9d1605..f1e2ab7f9 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -4,6 +4,7 @@
#include "pathlocks.hh"
#include "store-api.hh"
+#include "local-fs-store.hh"
#include "sync.hh"
#include "util.hh"
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index c032a5e22..a0d482ddf 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -276,21 +276,15 @@ void LocalStore::optimiseStore(OptimiseStats & stats)
}
}
-static string showBytes(uint64_t bytes)
-{
- return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
-}
-
void LocalStore::optimiseStore()
{
OptimiseStats stats;
optimiseStore(stats);
- printInfo(
- format("%1% freed by hard-linking %2% files")
- % showBytes(stats.bytesFreed)
- % stats.filesLinked);
+ printInfo("%s freed by hard-linking %d files",
+ showBytes(stats.bytesFreed),
+ stats.filesLinked);
}
void LocalStore::optimisePath(const Path & path)
diff --git a/src/libstore/parsed-derivations.hh b/src/libstore/parsed-derivations.hh
index 3fa09f34f..c9fbe68c4 100644
--- a/src/libstore/parsed-derivations.hh
+++ b/src/libstore/parsed-derivations.hh
@@ -1,3 +1,5 @@
+#pragma once
+
#include "store-api.hh"
#include <nlohmann/json_fwd.hpp>
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index c3809bad7..ed10dd519 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -1,5 +1,6 @@
#include "profiles.hh"
#include "store-api.hh"
+#include "local-fs-store.hh"
#include "util.hh"
#include <sys/types.h>
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 04b80d750..5ff787ed2 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -12,16 +12,6 @@
#include "logging.hh"
#include "callback.hh"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <cstring>
-
namespace nix {
namespace worker_proto {
@@ -125,69 +115,6 @@ ref<RemoteStore::Connection> RemoteStore::openConnectionWrapper()
}
-UDSRemoteStore::UDSRemoteStore(const Params & params)
- : StoreConfig(params)
- , Store(params)
- , LocalFSStore(params)
- , RemoteStore(params)
-{
-}
-
-
-UDSRemoteStore::UDSRemoteStore(
- const std::string scheme,
- std::string socket_path,
- const Params & params)
- : UDSRemoteStore(params)
-{
- path.emplace(socket_path);
-}
-
-
-std::string UDSRemoteStore::getUri()
-{
- if (path) {
- return std::string("unix://") + *path;
- } else {
- return "daemon";
- }
-}
-
-
-ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
-{
- auto conn = make_ref<Connection>();
-
- /* Connect to a daemon that does the privileged work for us. */
- conn->fd = socket(PF_UNIX, SOCK_STREAM
- #ifdef SOCK_CLOEXEC
- | SOCK_CLOEXEC
- #endif
- , 0);
- if (!conn->fd)
- throw SysError("cannot create Unix domain socket");
- closeOnExec(conn->fd.get());
-
- string socketPath = path ? *path : settings.nixDaemonSocketFile;
-
- struct sockaddr_un addr;
- addr.sun_family = AF_UNIX;
- if (socketPath.size() + 1 >= sizeof(addr.sun_path))
- throw Error("socket path '%1%' is too long", socketPath);
- strcpy(addr.sun_path, socketPath.c_str());
-
- if (::connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
- throw SysError("cannot connect to daemon at '%1%'", socketPath);
-
- conn->from.fd = conn->fd.get();
- conn->to.fd = conn->fd.get();
-
- conn->startTime = std::chrono::steady_clock::now();
-
- return conn;
-}
-
-
void RemoteStore::initConnection(Connection & conn)
{
/* Send the magic greeting, check for the reply. */
@@ -926,9 +853,13 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source *
}
else if (msg == STDERR_ERROR) {
- string error = readString(from);
- unsigned int status = readInt(from);
- return std::make_exception_ptr(Error(status, error));
+ if (GET_PROTOCOL_MINOR(daemonVersion) >= 26) {
+ return std::make_exception_ptr(readError(from));
+ } else {
+ string error = readString(from);
+ unsigned int status = readInt(from);
+ return std::make_exception_ptr(Error(status, error));
+ }
}
else if (msg == STDERR_NEXT)
@@ -1009,6 +940,4 @@ void ConnectionHandle::withFramedSink(std::function<void(Sink &sink)> fun)
}
-static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regStore;
-
}
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index ec04be985..9f78fcb02 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -155,49 +155,5 @@ private:
};
-struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig
-{
- UDSRemoteStoreConfig(const Store::Params & params)
- : StoreConfig(params)
- , LocalFSStoreConfig(params)
- , RemoteStoreConfig(params)
- {
- }
-
- UDSRemoteStoreConfig()
- : UDSRemoteStoreConfig(Store::Params({}))
- {
- }
-
- const std::string name() override { return "Local Daemon Store"; }
-};
-
-class UDSRemoteStore : public LocalFSStore, public RemoteStore, public virtual UDSRemoteStoreConfig
-{
-public:
-
- UDSRemoteStore(const Params & params);
- UDSRemoteStore(const std::string scheme, std::string path, const Params & params);
-
- std::string getUri() override;
-
- static std::set<std::string> uriSchemes()
- { return {"unix"}; }
-
- bool sameMachine() override
- { return true; }
-
- ref<FSAccessor> getFSAccessor() override
- { return LocalFSStore::getFSAccessor(); }
-
- void narFromPath(const StorePath & path, Sink & sink) override
- { LocalFSStore::narFromPath(path, sink); }
-
-private:
-
- ref<RemoteStore::Connection> openConnection() override;
- std::optional<std::string> path;
-};
-
}
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index d43f267e0..552c4aac7 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -439,7 +439,7 @@ struct S3BinaryCacheStoreImpl : public S3BinaryCacheStore, virtual S3BinaryCache
};
-static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regStore;
+static RegisterStoreImplementation<S3BinaryCacheStoreImpl, S3BinaryCacheStoreConfig> regS3BinaryCacheStore;
}
diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc
index 6d6eca98d..08d0bd565 100644
--- a/src/libstore/ssh-store.cc
+++ b/src/libstore/ssh-store.cc
@@ -83,6 +83,6 @@ ref<RemoteStore::Connection> SSHStore::openConnection()
return conn;
}
-static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regStore;
+static RegisterStoreImplementation<SSHStore, SSHStoreConfig> regSSHStore;
}
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 5d63b8e3c..c2696f7a5 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -1077,7 +1077,7 @@ Derivation Store::readDerivation(const StorePath & drvPath)
#include "local-store.hh"
-#include "remote-store.hh"
+#include "uds-remote-store.hh"
namespace nix {
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index e6a6053a3..dba6198eb 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -196,6 +196,8 @@ struct StoreConfig : public Config
*/
StoreConfig() { assert(false); }
+ virtual ~StoreConfig() { }
+
virtual const std::string name() = 0;
const PathSetting storeDir_{this, false, settings.nixStore,
@@ -709,47 +711,6 @@ protected:
};
-struct LocalFSStoreConfig : virtual StoreConfig
-{
- using StoreConfig::StoreConfig;
- // FIXME: the (StoreConfig*) cast works around a bug in gcc that causes
- // it to omit the call to the Setting constructor. Clang works fine
- // either way.
- const PathSetting rootDir{(StoreConfig*) this, true, "",
- "root", "directory prefixed to all other paths"};
- const PathSetting stateDir{(StoreConfig*) this, false,
- rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir,
- "state", "directory where Nix will store state"};
- const PathSetting logDir{(StoreConfig*) this, false,
- rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir,
- "log", "directory where Nix will store state"};
-};
-
-class LocalFSStore : public virtual Store, public virtual LocalFSStoreConfig
-{
-public:
-
- const static string drvsLogDir;
-
- LocalFSStore(const Params & params);
-
- void narFromPath(const StorePath & path, Sink & sink) override;
- ref<FSAccessor> getFSAccessor() override;
-
- /* Register a permanent GC root. */
- Path addPermRoot(const StorePath & storePath, const Path & gcRoot);
-
- virtual Path getRealStoreDir() { return storeDir; }
-
- Path toRealPath(const Path & storePath) override
- {
- assert(isInStore(storePath));
- return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1);
- }
-
- std::shared_ptr<std::string> getBuildLog(const StorePath & path) override;
-};
-
/* Copy a path from one store to another. */
void copyStorePath(ref<Store> srcStore, ref<Store> dstStore,
diff --git a/src/libstore/uds-remote-store.cc b/src/libstore/uds-remote-store.cc
new file mode 100644
index 000000000..24f3e9c6d
--- /dev/null
+++ b/src/libstore/uds-remote-store.cc
@@ -0,0 +1,81 @@
+#include "uds-remote-store.hh"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cstring>
+
+
+namespace nix {
+
+UDSRemoteStore::UDSRemoteStore(const Params & params)
+ : StoreConfig(params)
+ , Store(params)
+ , LocalFSStore(params)
+ , RemoteStore(params)
+{
+}
+
+
+UDSRemoteStore::UDSRemoteStore(
+ const std::string scheme,
+ std::string socket_path,
+ const Params & params)
+ : UDSRemoteStore(params)
+{
+ path.emplace(socket_path);
+}
+
+
+std::string UDSRemoteStore::getUri()
+{
+ if (path) {
+ return std::string("unix://") + *path;
+ } else {
+ return "daemon";
+ }
+}
+
+
+ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
+{
+ auto conn = make_ref<Connection>();
+
+ /* Connect to a daemon that does the privileged work for us. */
+ conn->fd = socket(PF_UNIX, SOCK_STREAM
+ #ifdef SOCK_CLOEXEC
+ | SOCK_CLOEXEC
+ #endif
+ , 0);
+ if (!conn->fd)
+ throw SysError("cannot create Unix domain socket");
+ closeOnExec(conn->fd.get());
+
+ string socketPath = path ? *path : settings.nixDaemonSocketFile;
+
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ if (socketPath.size() + 1 >= sizeof(addr.sun_path))
+ throw Error("socket path '%1%' is too long", socketPath);
+ strcpy(addr.sun_path, socketPath.c_str());
+
+ if (::connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ throw SysError("cannot connect to daemon at '%1%'", socketPath);
+
+ conn->from.fd = conn->fd.get();
+ conn->to.fd = conn->fd.get();
+
+ conn->startTime = std::chrono::steady_clock::now();
+
+ return conn;
+}
+
+
+static RegisterStoreImplementation<UDSRemoteStore, UDSRemoteStoreConfig> regUDSRemoteStore;
+
+}
diff --git a/src/libstore/uds-remote-store.hh b/src/libstore/uds-remote-store.hh
new file mode 100644
index 000000000..e5de104c9
--- /dev/null
+++ b/src/libstore/uds-remote-store.hh
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "remote-store.hh"
+#include "local-fs-store.hh"
+
+namespace nix {
+
+struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreConfig
+{
+ UDSRemoteStoreConfig(const Store::Params & params)
+ : StoreConfig(params)
+ , LocalFSStoreConfig(params)
+ , RemoteStoreConfig(params)
+ {
+ }
+
+ UDSRemoteStoreConfig()
+ : UDSRemoteStoreConfig(Store::Params({}))
+ {
+ }
+
+ const std::string name() override { return "Local Daemon Store"; }
+};
+
+class UDSRemoteStore : public LocalFSStore, public RemoteStore, public virtual UDSRemoteStoreConfig
+{
+public:
+
+ UDSRemoteStore(const Params & params);
+ UDSRemoteStore(const std::string scheme, std::string path, const Params & params);
+
+ std::string getUri() override;
+
+ static std::set<std::string> uriSchemes()
+ { return {"unix"}; }
+
+ bool sameMachine() override
+ { return true; }
+
+ ref<FSAccessor> getFSAccessor() override
+ { return LocalFSStore::getFSAccessor(); }
+
+ void narFromPath(const StorePath & path, Sink & sink) override
+ { LocalFSStore::narFromPath(path, sink); }
+
+private:
+
+ ref<RemoteStore::Connection> openConnection() override;
+ std::optional<std::string> path;
+};
+
+}
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index 2934c1d67..b3705578e 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -6,7 +6,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f
-#define PROTOCOL_VERSION 0x119
+#define PROTOCOL_VERSION 0x11a
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
@@ -83,7 +83,6 @@ MAKE_WORKER_PROTO(, StorePath);
MAKE_WORKER_PROTO(, ContentAddress);
MAKE_WORKER_PROTO(template<typename T>, std::set<T>);
-MAKE_WORKER_PROTO(template<typename T>, std::optional<T>);
#define X_ template<typename K, typename V>
#define Y_ std::map<K, V>
@@ -91,6 +90,22 @@ MAKE_WORKER_PROTO(X_, Y_);
#undef X_
#undef Y_
+/* These use the empty string for the null case, relying on the fact
+ that the underlying types never serialize to the empty string.
+
+ We do this instead of a generic std::optional<T> instance because
+ ordinal tags (0 or 1, here) are a bit of a compatability hazard. For
+ the same reason, we don't have a std::variant<T..> instances (ordinal
+ tags 0...n).
+
+ We could the generic instances and then these as specializations for
+ compatability, but that's proven a bit finnicky, and also makes the
+ worker protocol harder to implement in other languages where such
+ specializations may not be allowed.
+ */
+MAKE_WORKER_PROTO(, std::optional<StorePath>);
+MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
+
template<typename T>
std::set<T> read(const Store & store, Source & from, Phantom<std::set<T>> _)
{
@@ -134,37 +149,6 @@ void write(const Store & store, Sink & out, const std::map<K, V> & resMap)
}
}
-template<typename T>
-std::optional<T> read(const Store & store, Source & from, Phantom<std::optional<T>> _)
-{
- auto tag = readNum<uint8_t>(from);
- switch (tag) {
- case 0:
- return std::nullopt;
- case 1:
- return read(store, from, Phantom<T> {});
- default:
- throw Error("got an invalid tag bit for std::optional: %#04x", (size_t)tag);
- }
-}
-
-template<typename T>
-void write(const Store & store, Sink & out, const std::optional<T> & optVal)
-{
- out << (uint64_t) (optVal ? 1 : 0);
- if (optVal)
- worker_proto::write(store, out, *optVal);
-}
-
-/* Specialization which uses and empty string for the empty case, taking
- advantage of the fact these types always serialize to non-empty strings.
- This is done primarily for backwards compatability, so that T <=
- std::optional<T>, where <= is the compatability partial order, T is one of
- the types below.
- */
-MAKE_WORKER_PROTO(, std::optional<StorePath>);
-MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
-
}
}