1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
#include <filesystem>
#include <absl/flags/flag.h>
#include <absl/flags/parse.h>
#include <absl/flags/usage_config.h>
#include <absl/strings/str_format.h>
#include <fcntl.h>
#include <glog/logging.h>
#include <grpcpp/security/server_credentials.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder_impl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "libmain/shared.hh" // TODO(tazjin): can this be removed?
#include "libstore/globals.hh"
#include "libstore/store-api.hh"
#include "libutil/util.hh"
#include "nix-daemon-proto.hh"
#include "nix-daemon/nix-daemon-proto.hh"
#include "nix/legacy.hh"
ABSL_FLAG(bool, pipe, false, "Use pipes for daemon communication");
namespace nix::daemon {
using grpc::Server;
using grpc_impl::ServerBuilder;
// TODO(grfn): There has to be a better way to do this - this was ported
// verbatim from the old daemon implementation without much critical evaluation.
static int ForwardToSocket(nix::Path socket_path) {
// Forward on this connection to the real daemon
int sockfd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1) {
throw SysError("creating Unix domain socket");
}
auto socketDir = dirOf(socket_path);
if (chdir(socketDir.c_str()) == -1) {
throw SysError(format("changing to socket directory '%1%'") % socketDir);
}
auto socketName = baseNameOf(socket_path);
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);
}
strncpy(addr.sun_path, socketName.c_str(), sizeof(addr.sun_family));
if (connect(sockfd, reinterpret_cast<struct sockaddr*>(&addr),
sizeof(addr)) == -1) {
throw SysError(format("cannot connect to daemon at %1%") % socket_path);
}
auto nfds = (sockfd > STDIN_FILENO ? sockfd : STDIN_FILENO) + 1;
while (true) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(sockfd, &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(sockfd, &fds)) {
auto res = splice(sockfd, nullptr, STDOUT_FILENO, nullptr, SSIZE_MAX,
SPLICE_F_MOVE);
if (res == -1) {
throw SysError("splicing data from daemon socket to stdout");
}
if (res == 0) {
throw EndOfFile("unexpected EOF from daemon socket");
}
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
auto res = splice(STDIN_FILENO, nullptr, sockfd, nullptr, SSIZE_MAX,
SPLICE_F_MOVE);
if (res == -1) {
throw SysError("splicing data from stdin to daemon socket");
}
if (res == 0) {
return 0;
}
}
}
}
int RunServer() {
Store::Params params;
params["path-info-cache-size"] = "0";
auto store = openStore(settings.storeUri, params);
auto worker = NewWorkerService(*store);
std::filesystem::path socket_path(settings.nixDaemonSocketFile);
std::filesystem::create_directories(socket_path.parent_path());
auto socket_addr = absl::StrFormat("unix://%s", socket_path);
ServerBuilder builder;
builder.AddListeningPort(socket_addr, grpc::InsecureServerCredentials());
builder.RegisterService(worker);
std::unique_ptr<Server> server(builder.BuildAndStart());
if (server) {
LOG(INFO) << "Nix daemon listening at " << socket_addr;
server->Wait();
return 0;
} else {
return 1;
}
}
} // namespace nix::daemon
int main(int argc, char** argv) {
absl::SetFlagsUsageConfig({.version_string = [] { return nix::nixVersion; }});
absl::ParseCommandLine(argc, argv);
if (absl::GetFlag(FLAGS_pipe)) {
if (nix::getStoreType() == nix::tDaemon) {
return nix::daemon::ForwardToSocket(nix::settings.nixDaemonSocketFile);
} else {
// TODO(grfn): Need to launch a server on stdin here - upstream calls
// processConnection(true, "root", 0);
LOG(ERROR) << "not implemented";
return 1;
}
}
return nix::daemon::RunServer();
}
|