aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2021-10-05 17:36:07 +0200
committerGitHub <noreply@github.com>2021-10-05 17:36:07 +0200
commitfd57e7074f2f7189bce0b525073ea507857ca44e (patch)
tree33c04ec5c803d8be86e7b9902dee2ff53d34a49f /src
parent3b7f4c7d9d124283cec7f7d42e0eca3e2de64d5a (diff)
parent223ab254c29313fff2a9af463baa2f0b68d7d83f (diff)
Merge pull request #5335 from edolstra/socket-paths
Support arbitrary-length socket paths
Diffstat (limited to 'src')
-rw-r--r--src/libstore/uds-remote-store.cc11
-rw-r--r--src/libutil/util.cc73
-rw-r--r--src/libutil/util.hh8
-rw-r--r--src/nix/daemon.cc6
4 files changed, 73 insertions, 25 deletions
diff --git a/src/libstore/uds-remote-store.cc b/src/libstore/uds-remote-store.cc
index cfadccf68..02e81b022 100644
--- a/src/libstore/uds-remote-store.cc
+++ b/src/libstore/uds-remote-store.cc
@@ -65,16 +65,7 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
throw SysError("cannot create Unix domain socket");
closeOnExec(conn->fd.get());
- string socketPath = path ? *path : settings.nixDaemonSocketFile;
-
- struct sockaddr_un addr;
- addr.sun_family = AF_UNIX;
- if (socketPath.size() + 1 >= sizeof(addr.sun_path))
- throw Error("socket path '%1%' is too long", socketPath);
- strcpy(addr.sun_path, socketPath.c_str());
-
- if (::connect(conn->fd.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
- throw SysError("cannot connect to daemon at '%1%'", socketPath);
+ nix::connect(conn->fd.get(), path ? *path : settings.nixDaemonSocketFile);
conn->from.fd = conn->fd.get();
conn->to.fd = conn->fd.get();
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index bc841f425..0b261ca60 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -903,7 +903,7 @@ int Pid::wait()
return status;
}
if (errno != EINTR)
- throw SysError("cannot get child exit status");
+ throw SysError("cannot get exit status of PID %d", pid);
checkInterrupt();
}
}
@@ -1686,16 +1686,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
closeOnExec(fdSocket.get());
- struct sockaddr_un addr;
- addr.sun_family = AF_UNIX;
- if (path.size() + 1 >= sizeof(addr.sun_path))
- throw Error("socket path '%1%' is too long", path);
- strcpy(addr.sun_path, path.c_str());
-
- unlink(path.c_str());
-
- if (bind(fdSocket.get(), (struct sockaddr *) &addr, sizeof(addr)) == -1)
- throw SysError("cannot bind to socket '%1%'", path);
+ bind(fdSocket.get(), path);
if (chmod(path.c_str(), mode) == -1)
throw SysError("changing permissions on '%1%'", path);
@@ -1707,6 +1698,66 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
}
+void bind(int fd, const std::string & path)
+{
+ unlink(path.c_str());
+
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+
+ if (path.size() + 1 >= sizeof(addr.sun_path)) {
+ Pid pid = startProcess([&]() {
+ auto dir = dirOf(path);
+ if (chdir(dir.c_str()) == -1)
+ throw SysError("chdir to '%s' failed", dir);
+ std::string base(baseNameOf(path));
+ if (base.size() + 1 >= sizeof(addr.sun_path))
+ throw Error("socket path '%s' is too long", base);
+ strcpy(addr.sun_path, base.c_str());
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ throw SysError("cannot bind to socket '%s'", path);
+ _exit(0);
+ });
+ int status = pid.wait();
+ if (status != 0)
+ throw Error("cannot bind to socket '%s'", path);
+ } else {
+ strcpy(addr.sun_path, path.c_str());
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ throw SysError("cannot bind to socket '%s'", path);
+ }
+}
+
+
+void connect(int fd, const std::string & path)
+{
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+
+ if (path.size() + 1 >= sizeof(addr.sun_path)) {
+ Pid pid = startProcess([&]() {
+ auto dir = dirOf(path);
+ if (chdir(dir.c_str()) == -1)
+ throw SysError("chdir to '%s' failed", dir);
+ std::string base(baseNameOf(path));
+ if (base.size() + 1 >= sizeof(addr.sun_path))
+ throw Error("socket path '%s' is too long", base);
+ strcpy(addr.sun_path, base.c_str());
+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ throw SysError("cannot connect to socket at '%s'", path);
+ _exit(0);
+ });
+ int status = pid.wait();
+ if (status != 0)
+ throw Error("cannot connect to socket at '%s'", path);
+ } else {
+ strcpy(addr.sun_path, path.c_str());
+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+ throw SysError("cannot connect to socket at '%s'", path);
+ }
+}
+
+
string showBytes(uint64_t bytes)
{
return fmt("%.2f MiB", bytes / (1024.0 * 1024.0));
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index bee77b53f..6d3e64949 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -259,7 +259,7 @@ void killUser(uid_t uid);
pid to the caller. */
struct ProcessOptions
{
- string errorPrefix = "error: ";
+ string errorPrefix = "";
bool dieWithParent = true;
bool runExitHandlers = false;
bool allowVfork = true;
@@ -574,6 +574,12 @@ void commonChildInit(Pipe & logPipe);
/* Create a Unix domain socket in listen mode. */
AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode);
+/* Bind a Unix domain socket to a path. */
+void bind(int fd, const std::string & path);
+
+/* Connect to a Unix domain socket. */
+void connect(int fd, const std::string & path);
+
// A Rust/Python-like enumerate() iterator adapter.
// Borrowed from http://reedbeta.com/blog/python-like-enumerate-in-cpp17.
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index 2cf2a04c9..6a40a0bd3 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -156,9 +156,6 @@ static void daemonLoop()
if (chdir("/") == -1)
throw SysError("cannot change current directory");
- // Get rid of children automatically; don't let them become zombies.
- setSigChldAction(true);
-
AutoCloseFD fdSocket;
// Handle socket-based activation by systemd.
@@ -176,6 +173,9 @@ static void daemonLoop()
fdSocket = createUnixDomainSocket(settings.nixDaemonSocketFile, 0666);
}
+ // Get rid of children automatically; don't let them become zombies.
+ setSigChldAction(true);
+
// Loop accepting connections.
while (1) {