libutil: transfer bind/connect errors from libexec helper
this should improve error messages when connecting to long socket paths, and make it at all possible to detect ENOTDIR from connect helpers. this will be needed to handle daemon sockets that live in directories we have not previously considered like the protocol name directories we need for rpc purposes, all of which would have resulted in hard errors previously Change-Id: I4e16cf09fedd07c93cfdf7b0f151106984507315
This commit is contained in:
@@ -2,7 +2,17 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
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<char *> args) noexcept
|
||||
{
|
||||
@@ -10,8 +20,12 @@ int helperMain(const char *, std::span<char *> args) noexcept
|
||||
std::string_view method = args[1];
|
||||
const auto dir = args[2];
|
||||
const auto name = args[3];
|
||||
resultFd = argToInt<int>("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<char *> args) noexcept
|
||||
}
|
||||
|
||||
if (method == "bind") {
|
||||
DIE_UNLESS_SYS("bind", bind(socket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)));
|
||||
auto result = bind(socket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) ? errno : 0;
|
||||
sendResult(result);
|
||||
} else if (method == "connect") {
|
||||
DIE_UNLESS_SYS("connect", connect(socket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)));
|
||||
auto result = connect(socket, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)) ? errno : 0;
|
||||
sendResult(result);
|
||||
} else {
|
||||
die(std::format("invalid method %s", method));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -64,13 +64,35 @@ static void bindConnectProcHelper(
|
||||
// special case.
|
||||
auto * psaddr = reinterpret_cast<struct sockaddr *>(&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)
|
||||
|
||||
Reference in New Issue
Block a user