diff --git a/lix/libexec/unix-bind-connect.cc b/lix/libexec/unix-bind-connect.cc index 0d6d8f022..8e5ddc95a 100644 --- a/lix/libexec/unix-bind-connect.cc +++ b/lix/libexec/unix-bind-connect.cc @@ -2,7 +2,17 @@ #include #include -LIBEXEC_HELPER(4) +LIBEXEC_HELPER(5) + +static int resultFd = -1; + +static void sendResult(int result) +{ + // NOTE posix says pipe writes smaller than PIPE_BUF must be atomic, so this either + // succeeds or fails (pipe bufs of four bytes make no sense at all for our systems) + int error = result; + DIE_UNLESS_SYS("writing result", ::write(resultFd, &error, sizeof(error))); +} int helperMain(const char *, std::span args) noexcept { @@ -10,8 +20,12 @@ int helperMain(const char *, std::span args) noexcept std::string_view method = args[1]; const auto dir = args[2]; const auto name = args[3]; + resultFd = argToInt("result-fd", args[4]); - DIE_UNLESS_SYS("chdir", chdir(dir)); + if (chdir(dir)) { + sendResult(errno); + return 0; + } struct sockaddr_un addr; addr.sun_family = AF_UNIX; @@ -23,9 +37,11 @@ int helperMain(const char *, std::span args) noexcept } if (method == "bind") { - DIE_UNLESS_SYS("bind", bind(socket, reinterpret_cast(&addr), sizeof(addr))); + auto result = bind(socket, reinterpret_cast(&addr), sizeof(addr)) ? errno : 0; + sendResult(result); } else if (method == "connect") { - DIE_UNLESS_SYS("connect", connect(socket, reinterpret_cast(&addr), sizeof(addr))); + auto result = connect(socket, reinterpret_cast(&addr), sizeof(addr)) ? errno : 0; + sendResult(result); } else { die(std::format("invalid method %s", method)); } diff --git a/lix/libstore/uds-remote-store.cc b/lix/libstore/uds-remote-store.cc index fb76b0fae..1929aa50f 100644 --- a/lix/libstore/uds-remote-store.cc +++ b/lix/libstore/uds-remote-store.cc @@ -66,7 +66,9 @@ static void connectToFirstAvailableSocket(AutoCloseFD & sockFD, const std::list< nix::connect(sockFD.get(), socket); return; } catch (SysError & e) { - if (e.errNo == EACCES || e.errNo == EPERM || e.errNo == ECONNREFUSED || e.errNo == ENOENT) { + if (e.errNo == EACCES || e.errNo == EPERM || e.errNo == ECONNREFUSED || e.errNo == ENOENT + || e.errNo == ENOTDIR) + { debug("skipping socket %s: %s", socket, strerror(e.errNo)); } else { throw; diff --git a/lix/libutil/unix-domain-socket.cc b/lix/libutil/unix-domain-socket.cc index 3adc601a2..9f098fffd 100644 --- a/lix/libutil/unix-domain-socket.cc +++ b/lix/libutil/unix-domain-socket.cc @@ -64,13 +64,35 @@ static void bindConnectProcHelper( // special case. auto * psaddr = reinterpret_cast(&addr); + Pipe resultFd; + resultFd.create(); + if (path.size() + 1 >= sizeof(addr.sun_path)) { runHelper( "unix-bind-connect", {.args = - {std::to_string(fd), std::string(operationName), dirOf(path), std::string(baseNameOf(path))}, - .redirections = {{.dup = fd, .from = fd}}} + { + std::to_string(fd), + std::string(operationName), + dirOf(path), + std::string(baseNameOf(path)), + std::to_string(resultFd.writeSide.get()), + }, + .redirections = { + {.dup = fd, .from = fd}, + {.dup = resultFd.writeSide.get(), .from = resultFd.writeSide.get()}, + }} ).waitAndCheck(); + resultFd.writeSide.close(); + auto resultRaw = drainFD(resultFd.readSide.get()); + int result; + if (resultRaw.size() != sizeof(result)) { + throw Error("bind-connect helper returned bad result! bailing"); + } + memcpy(&result, resultRaw.data(), sizeof(result)); + if (result != 0) { + throw SysError(result, "cannot %s to socket at '%s'", operationName, path); + } } else { memcpy(addr.sun_path, path.c_str(), path.size() + 1); if (operation(fd, psaddr, sizeof(addr)) == -1)