Add 'nix daemon' command
This commit is contained in:
parent
28ef6ebf91
commit
7a472a76d4
5 changed files with 98 additions and 44 deletions
|
@ -13,6 +13,8 @@ namespace nix {
|
|||
|
||||
extern std::string programPath;
|
||||
|
||||
extern char * * savedArgv;
|
||||
|
||||
class EvalState;
|
||||
struct Pos;
|
||||
class Store;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "command.hh"
|
||||
#include "shared.hh"
|
||||
#include "local-store.hh"
|
||||
#include "remote-store.hh"
|
||||
|
@ -150,7 +151,7 @@ static ref<Store> openUncachedStore()
|
|||
}
|
||||
|
||||
|
||||
static void daemonLoop(char * * argv)
|
||||
static void daemonLoop()
|
||||
{
|
||||
if (chdir("/") == -1)
|
||||
throw SysError("cannot change current directory");
|
||||
|
@ -232,9 +233,9 @@ static void daemonLoop(char * * argv)
|
|||
setSigChldAction(false);
|
||||
|
||||
// For debugging, stuff the pid into argv[1].
|
||||
if (peer.pidKnown && argv[1]) {
|
||||
if (peer.pidKnown && savedArgv[1]) {
|
||||
string processName = std::to_string(peer.pid);
|
||||
strncpy(argv[1], processName.c_str(), strlen(argv[1]));
|
||||
strncpy(savedArgv[1], processName.c_str(), strlen(savedArgv[1]));
|
||||
}
|
||||
|
||||
// Handle the connection.
|
||||
|
@ -264,6 +265,48 @@ static void daemonLoop(char * * argv)
|
|||
}
|
||||
}
|
||||
|
||||
static void runDaemon(bool stdio)
|
||||
{
|
||||
if (stdio) {
|
||||
if (auto store = openUncachedStore().dynamic_pointer_cast<RemoteStore>()) {
|
||||
auto conn = store->openConnectionWrapper();
|
||||
int from = conn->from.fd;
|
||||
int to = conn->to.fd;
|
||||
|
||||
auto nfds = std::max(from, STDIN_FILENO) + 1;
|
||||
while (true) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(from, &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(from, &fds)) {
|
||||
auto res = splice(from, nullptr, STDOUT_FILENO, nullptr, SSIZE_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, to, nullptr, SSIZE_MAX, SPLICE_F_MOVE);
|
||||
if (res == -1)
|
||||
throw SysError("splicing data from stdin to daemon socket");
|
||||
else if (res == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FdSource from(STDIN_FILENO);
|
||||
FdSink to(STDOUT_FILENO);
|
||||
/* Auth hook is empty because in this mode we blindly trust the
|
||||
standard streams. Limiting access to those is explicitly
|
||||
not `nix-daemon`'s responsibility. */
|
||||
processConnection(openUncachedStore(), from, to, Trusted, NotRecursive, [&](Store & _){});
|
||||
}
|
||||
} else
|
||||
daemonLoop();
|
||||
}
|
||||
|
||||
static int main_nix_daemon(int argc, char * * argv)
|
||||
{
|
||||
|
@ -285,49 +328,34 @@ static int main_nix_daemon(int argc, char * * argv)
|
|||
|
||||
initPlugins();
|
||||
|
||||
if (stdio) {
|
||||
if (auto store = openUncachedStore().dynamic_pointer_cast<RemoteStore>()) {
|
||||
auto conn = store->openConnectionWrapper();
|
||||
int from = conn->from.fd;
|
||||
int to = conn->to.fd;
|
||||
|
||||
auto nfds = std::max(from, STDIN_FILENO) + 1;
|
||||
while (true) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(from, &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(from, &fds)) {
|
||||
auto res = splice(from, nullptr, STDOUT_FILENO, nullptr, SSIZE_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, to, nullptr, SSIZE_MAX, SPLICE_F_MOVE);
|
||||
if (res == -1)
|
||||
throw SysError("splicing data from stdin to daemon socket");
|
||||
else if (res == 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
FdSource from(STDIN_FILENO);
|
||||
FdSink to(STDOUT_FILENO);
|
||||
/* Auth hook is empty because in this mode we blindly trust the
|
||||
standard streams. Limiting access to those is explicitly
|
||||
not `nix-daemon`'s responsibility. */
|
||||
processConnection(openUncachedStore(), from, to, Trusted, NotRecursive, [&](Store & _){});
|
||||
}
|
||||
} else {
|
||||
daemonLoop(argv);
|
||||
}
|
||||
runDaemon(stdio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterLegacyCommand r_nix_daemon("nix-daemon", main_nix_daemon);
|
||||
|
||||
struct CmdDaemon : StoreCommand
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "daemon to perform store operations on behalf of non-root clients";
|
||||
}
|
||||
|
||||
Category category() override { return catUtility; }
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "daemon.md"
|
||||
;
|
||||
}
|
||||
|
||||
void run(ref<Store> store) override
|
||||
{
|
||||
runDaemon(false);
|
||||
}
|
||||
};
|
||||
|
||||
static auto rCmdDaemon = registerCommand2<CmdDaemon>({"daemon"});
|
21
src/nix/daemon.md
Normal file
21
src/nix/daemon.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
R""(
|
||||
|
||||
# Example
|
||||
|
||||
* Run the daemon in the foreground:
|
||||
|
||||
```console
|
||||
# nix daemon
|
||||
```
|
||||
|
||||
# Description
|
||||
|
||||
This command runs the Nix daemon, which is a required component in
|
||||
multi-user Nix installations. It performs build actions and other
|
||||
operations on the Nix store on behalf of non-root users. Usually you
|
||||
don't run the daemon directly; instead it's managed by a service
|
||||
management framework such as `systemd`.
|
||||
|
||||
Note that this daemon does not fork into the background.
|
||||
|
||||
)""
|
|
@ -52,6 +52,7 @@ static bool haveInternet()
|
|||
}
|
||||
|
||||
std::string programPath;
|
||||
char * * savedArgv;
|
||||
|
||||
struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||
{
|
||||
|
@ -232,6 +233,8 @@ static auto rCmdHelp = registerCommand<CmdHelp>("help");
|
|||
|
||||
void mainWrapped(int argc, char * * argv)
|
||||
{
|
||||
savedArgv = argv;
|
||||
|
||||
/* The chroot helper needs to be run before any threads have been
|
||||
started. */
|
||||
if (argc > 0 && argv[0] == chrootHelperName) {
|
||||
|
|
|
@ -73,7 +73,7 @@ startDaemon() {
|
|||
# Start the daemon, wait for the socket to appear. !!!
|
||||
# ‘nix-daemon’ should have an option to fork into the background.
|
||||
rm -f $NIX_STATE_DIR/daemon-socket/socket
|
||||
nix-daemon &
|
||||
nix daemon &
|
||||
for ((i = 0; i < 30; i++)); do
|
||||
if [ -e $NIX_DAEMON_SOCKET_PATH ]; then break; fi
|
||||
sleep 1
|
||||
|
|
Loading…
Reference in a new issue