Fixes included: * exposed gtest in the package set, required for protobuf * pinned SBCL to version 2.0.8: The channel moved it to >2.1, and a bunch of warnings seemed to be killing our builds - we should investigate this later. * removed kernel patches from //users/tazjin/frog: this machine is currently out of service anyways, not worth fixing while it's offline * removed steam & lutris from frog (they're currently broken) * removed Haskell overrides for hedgehog-classes & hgeometry-combinatorial * use gRPC sources from upstream and inject Abseil via Nix instead * fix for renamed grpc import in //third_party/nix * use libfprint-tod from upstream nixpkgs in glittershark/yeren and delete glittershark/pkgs/fprintd entirely, since all of the patches used there are available and working from upstream now (and stopped working here after the bump) Change-Id: Ia90e6f774f7b88bc9e60d28351b900ca43ee2695 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2901 Reviewed-by: glittershark <grfn@gws.fyi> Reviewed-by: tazjin <mail@tazj.in> Reviewed-by: sterni <sternenseemann@systemli.org> Reviewed-by: lukegb <lukegb@tvl.fyi> Tested-by: BuildkiteCI
201 lines
6.1 KiB
C++
201 lines
6.1 KiB
C++
#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.h>
|
|
#include <grpcpp/server_posix.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <systemd/sd-daemon.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::ServerBuilder;
|
|
|
|
namespace {
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetNonBlocking(int fd) {
|
|
int flags = fcntl(fd, F_GETFL); // NOLINT
|
|
PCHECK(flags != 0) << "Error getting socket flags";
|
|
PCHECK(fcntl( // NOLINT
|
|
fd, F_SETFL, flags | O_NONBLOCK) == 0)
|
|
<< "Could not set socket flags";
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int RunServer() {
|
|
Store::Params params;
|
|
params["path-info-cache-size"] = "0";
|
|
auto store = openStore(settings.storeUri, params);
|
|
auto worker = NewWorkerService(*store);
|
|
ServerBuilder builder;
|
|
builder.RegisterService(worker);
|
|
|
|
auto n_fds = sd_listen_fds(0);
|
|
|
|
if (n_fds > 1) {
|
|
LOG(FATAL) << "Too many file descriptors (" << n_fds
|
|
<< ") received from systemd socket activation";
|
|
}
|
|
|
|
std::filesystem::path socket_path;
|
|
|
|
if (n_fds == 0) {
|
|
socket_path = settings.nixDaemonSocketFile;
|
|
std::filesystem::create_directories(socket_path.parent_path());
|
|
auto socket_addr = absl::StrFormat("unix://%s", socket_path);
|
|
builder.AddListeningPort(socket_addr, grpc::InsecureServerCredentials());
|
|
}
|
|
|
|
std::unique_ptr<Server> server(builder.BuildAndStart());
|
|
|
|
if (!server) {
|
|
LOG(FATAL) << "Error building server";
|
|
return 1;
|
|
}
|
|
|
|
// We have been systemd socket-activated - instead of asking grpc to make the
|
|
// socket path for us, start our own accept loop and pass file descriptors to
|
|
// grpc.
|
|
//
|
|
// This approach was *somewhat* adapted from
|
|
// https://gist.github.com/yorickvP/8d523a4df2b10c5812fa7789e82b7c1b - at some
|
|
// point we'd like gRPC to do it for us, though - see
|
|
// https://github.com/grpc/grpc/issues/19133
|
|
if (n_fds == 1) {
|
|
int socket_fd = SD_LISTEN_FDS_START;
|
|
// Only used for logging
|
|
socket_path = readLink(absl::StrFormat("/proc/self/fd/%d", socket_fd));
|
|
|
|
PCHECK(sd_notify(0, "READY=1") == 0) << "Error notifying systemd";
|
|
for (;;) {
|
|
try {
|
|
struct sockaddr_un remote_addr {};
|
|
socklen_t remote_addr_len = sizeof(remote_addr);
|
|
int remote_fd =
|
|
accept(socket_fd,
|
|
reinterpret_cast<struct sockaddr*>(&remote_addr), // NOLINT
|
|
&remote_addr_len);
|
|
checkInterrupt();
|
|
if (!remote_fd) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
PCHECK(false) << "error accepting connection";
|
|
}
|
|
|
|
LOG(INFO) << "Accepted remote connection on fd " << remote_fd;
|
|
SetNonBlocking(remote_fd);
|
|
grpc::AddInsecureChannelFromFd(server.get(), remote_fd);
|
|
} catch (Interrupted& e) {
|
|
return -1;
|
|
} catch (Error& e) {
|
|
LOG(ERROR) << "error processing connection: " << e.msg();
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG(INFO) << "Nix daemon listening at " << socket_path;
|
|
server->Wait();
|
|
return 0;
|
|
}
|
|
|
|
} // namespace nix::daemon
|
|
|
|
int main(int argc, char** argv) { // NOLINT
|
|
FLAGS_logtostderr = true;
|
|
google::InitGoogleLogging(argv[0]); // NOLINT
|
|
|
|
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();
|
|
}
|