about summary refs log tree commit diff
path: root/src/nix-daemon/nix-daemon.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-daemon/nix-daemon.cc')
-rw-r--r--src/nix-daemon/nix-daemon.cc107
1 files changed, 106 insertions, 1 deletions
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 0e4bcb525a37..c8fa81df13c8 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -22,6 +22,7 @@
 #include <errno.h>
 #include <pwd.h>
 #include <grp.h>
+#include <fcntl.h>
 
 #if __APPLE__ || __FreeBSD__
 #include <sys/ucred.h>
@@ -29,6 +30,25 @@
 
 using namespace nix;
 
+#ifndef __linux__
+#define SPLICE_F_MOVE 0
+static ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)
+{
+    /* We ignore most parameters, we just have them for conformance with the linux syscall */
+    char buf[8192];
+    auto read_count = read(fd_in, buf, sizeof(buf));
+    if (read_count == -1)
+        return read_count;
+    auto write_count = decltype<read_count>(0);
+    while (write_count < read_count) {
+        auto res = write(fd_out, buf + write_count, read_count - write_count);
+        if (res == -1)
+            return res;
+        write_count += res;
+    }
+    return read_count;
+}
+#endif
 
 static FdSource from(STDIN_FILENO);
 static FdSink to(STDOUT_FILENO);
@@ -556,6 +576,37 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
         break;
     }
 
+    case wopNarFromPath: {
+        auto path = readStorePath(*store, from);
+        startWork();
+        stopWork();
+        dumpPath(path, to);
+        break;
+    }
+
+    case wopAddToStoreNar: {
+        ValidPathInfo info;
+        info.path = readStorePath(*store, from);
+        info.deriver = readString(from);
+        if (!info.deriver.empty())
+            store->assertStorePath(info.deriver);
+        info.narHash = parseHash(htSHA256, readString(from));
+        info.references = readStorePaths<PathSet>(*store, from);
+        info.registrationTime = readInt(from);
+        info.narSize = readLongLong(from);
+        info.ultimate = readLongLong(from);
+        info.sigs = readStrings<StringSet>(from);
+        auto nar = make_ref<std::string>(readString(from));
+        auto repair = readInt(from) ? true : false;
+        auto dontCheckSigs = readInt(from) ? true : false;
+        if (!trusted && dontCheckSigs)
+            dontCheckSigs = false;
+        startWork();
+        store->addToStore(info, nar, repair, dontCheckSigs, nullptr);
+        stopWork();
+        break;
+    }
+
     default:
         throw Error(format("invalid operation %1%") % op);
     }
@@ -885,6 +936,8 @@ int main(int argc, char * * argv)
     return handleExceptions(argv[0], [&]() {
         initNix();
 
+        auto stdio = false;
+
         parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
             if (*arg == "--daemon")
                 ; /* ignored for backwards compatibility */
@@ -892,10 +945,62 @@ int main(int argc, char * * argv)
                 showManPage("nix-daemon");
             else if (*arg == "--version")
                 printVersion("nix-daemon");
+            else if (*arg == "--stdio")
+                stdio = true;
             else return false;
             return true;
         });
 
-        daemonLoop(argv);
+        if (stdio) {
+            if (getStoreType() == tDaemon) {
+                /* Forward on this connection to the real daemon */
+                auto socketPath = settings.nixDaemonSocketFile;
+                auto s = socket(PF_UNIX, SOCK_STREAM, 0);
+                if (s == -1)
+                    throw SysError("creating Unix domain socket");
+
+                auto socketDir = dirOf(socketPath);
+                if (chdir(socketDir.c_str()) == -1)
+                    throw SysError(format("changing to socket directory ‘%1%’") % socketDir);
+
+                auto socketName = baseNameOf(socketPath);
+                auto addr = sockaddr_un{};
+                addr.sun_family = AF_UNIX;
+                if (socketName.size() + 1 >= sizeof(addr.sun_path))
+                    throw Error(format("socket name %1% is too long") % socketName);
+                strcpy(addr.sun_path, socketName.c_str());
+
+                if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+                    throw SysError(format("cannot connect to daemon at %1%") % socketPath);
+
+                auto nfds = (s > STDIN_FILENO ? s : STDIN_FILENO) + 1;
+                while (true) {
+                    fd_set fds;
+                    FD_ZERO(&fds);
+                    FD_SET(s, &fds);
+                    FD_SET(STDIN_FILENO, &fds);
+                    if (select(nfds, &fds, nullptr, nullptr, nullptr) == -1)
+                        throw SysError("waiting for data from client or server");
+                    if (FD_ISSET(s, &fds)) {
+                        auto res = splice(s, nullptr, STDOUT_FILENO, nullptr, SIZE_MAX, SPLICE_F_MOVE);
+                        if (res == -1)
+                            throw SysError("splicing data from daemon socket to stdout");
+                        else if (res == 0)
+                            throw EndOfFile("unexpected EOF from daemon socket");
+                    }
+                    if (FD_ISSET(STDIN_FILENO, &fds)) {
+                        auto res = splice(STDIN_FILENO, nullptr, s, nullptr, SIZE_MAX, SPLICE_F_MOVE);
+                        if (res == -1)
+                            throw SysError("splicing data from stdin to daemon socket");
+                        else if (res == 0)
+                            return;
+                    }
+                }
+            } else {
+                processConnection(true);
+            }
+        } else {
+            daemonLoop(argv);
+        }
     });
 }