diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2012-06-19T03·01-0400 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2012-06-19T03·01-0400 |
commit | 2f3f413e91620d2314be59870f4bd67292f7d2de (patch) | |
tree | f2c9fce2695e56473662ee579c75f8d57d7cf779 | |
parent | 02fb6323e06502e410dd5d5f8fe10589a7c938d4 (diff) |
Support socket-based, on-demand activation of the Nix daemon with systemd
Systemd can start the Nix daemon on demand when the Nix daemon socket is first accessed. This is signalled through the LISTEN_FDS environment variable, so all we need to do is check for that and then use file descriptor 3 as the listen socket instead of creating one ourselves.
-rw-r--r-- | src/nix-worker/nix-worker.cc | 76 |
1 files changed, 46 insertions, 30 deletions
diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc index b7bce20bd412..6131e73e6c00 100644 --- a/src/nix-worker/nix-worker.cc +++ b/src/nix-worker/nix-worker.cc @@ -695,51 +695,67 @@ static void setSigChldAction(bool autoReap) } +#define SD_LISTEN_FDS_START 3 + + static void daemonLoop() { /* Get rid of children automatically; don't let them become zombies. */ setSigChldAction(true); - - /* Create and bind to a Unix domain socket. */ - AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM, 0); - if (fdSocket == -1) - throw SysError("cannot create Unix domain socket"); - closeOnExec(fdSocket); + AutoCloseFD fdSocket; + + /* Handle socket-based activation by systemd. */ + if (getEnv("LISTEN_FDS") != "") { + if (getEnv("LISTEN_PID") != int2String(getpid()) || getEnv("LISTEN_FDS") != "1") + throw Error("unexpected systemd environment variables"); + fdSocket = SD_LISTEN_FDS_START; + } + + /* Otherwise, create and bind to a Unix domain socket. */ + else { - string socketPath = nixStateDir + DEFAULT_SOCKET_PATH; + /* Create and bind to a Unix domain socket. */ + fdSocket = socket(PF_UNIX, SOCK_STREAM, 0); + if (fdSocket == -1) + throw SysError("cannot create Unix domain socket"); + + string socketPath = nixStateDir + DEFAULT_SOCKET_PATH; - createDirs(dirOf(socketPath)); + createDirs(dirOf(socketPath)); - /* Urgh, sockaddr_un allows path names of only 108 characters. So - chdir to the socket directory so that we can pass a relative - path name. */ - chdir(dirOf(socketPath).c_str()); - Path socketPathRel = "./" + baseNameOf(socketPath); + /* Urgh, sockaddr_un allows path names of only 108 characters. + So chdir to the socket directory so that we can pass a + relative path name. */ + chdir(dirOf(socketPath).c_str()); + Path socketPathRel = "./" + baseNameOf(socketPath); - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - if (socketPathRel.size() >= sizeof(addr.sun_path)) - throw Error(format("socket path `%1%' is too long") % socketPathRel); - strcpy(addr.sun_path, socketPathRel.c_str()); + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + if (socketPathRel.size() >= sizeof(addr.sun_path)) + throw Error(format("socket path `%1%' is too long") % socketPathRel); + strcpy(addr.sun_path, socketPathRel.c_str()); - unlink(socketPath.c_str()); + unlink(socketPath.c_str()); - /* Make sure that the socket is created with 0666 permission - (everybody can connect --- provided they have access to the - directory containing the socket). */ - mode_t oldMode = umask(0111); - int res = bind(fdSocket, (struct sockaddr *) &addr, sizeof(addr)); - umask(oldMode); - if (res == -1) - throw SysError(format("cannot bind to socket `%1%'") % socketPath); + /* Make sure that the socket is created with 0666 permission + (everybody can connect --- provided they have access to the + directory containing the socket). */ + mode_t oldMode = umask(0111); + int res = bind(fdSocket, (struct sockaddr *) &addr, sizeof(addr)); + umask(oldMode); + if (res == -1) + throw SysError(format("cannot bind to socket `%1%'") % socketPath); - chdir("/"); /* back to the root */ + chdir("/"); /* back to the root */ - if (listen(fdSocket, 5) == -1) - throw SysError(format("cannot listen on socket `%1%'") % socketPath); + if (listen(fdSocket, 5) == -1) + throw SysError(format("cannot listen on socket `%1%'") % socketPath); + } + closeOnExec(fdSocket); + /* Loop accepting connections. */ while (1) { |