mirror of
https://github.com/NixOS/nix.git
synced 2025-11-12 21:46:01 +01:00
Always throw the right exception in connect
When `nix::connect` is called with a socket path that's too long, it forks a process that will `chdir` to the directory of the socket path and call `::connect` with the relative path (which is hopefully short-enough). That works fairly well, except that an exception raised in this subprocess won't be forwarded to the parent process. Instead the logic will just notice that the subprocess exited with a non-zero error code, and throw a generic `Error`. In particular, any failure in the `::connect` call should throw a `SysError` with the correct error code, but that's not the case. Some places try to catch this `SysError` and look at its error code (to potentially restart for example). But this doesn't work since the actual error that gets thrown isn't a `SysError`. Fix that by forwarding the `errno` in case something gets wrong (by setting the subprocess exit code to it), and throwing a `SysError` with the right error code in the parent process.
This commit is contained in:
parent
6c0e7450de
commit
2d651ad2d0
1 changed files with 24 additions and 11 deletions
|
|
@ -1817,6 +1817,7 @@ void connect(int fd, const std::string & path)
|
||||||
|
|
||||||
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
||||||
Pid pid = startProcess([&]() {
|
Pid pid = startProcess([&]() {
|
||||||
|
try {
|
||||||
Path dir = dirOf(path);
|
Path dir = dirOf(path);
|
||||||
if (chdir(dir.c_str()) == -1)
|
if (chdir(dir.c_str()) == -1)
|
||||||
throw SysError("chdir to '%s' failed", dir);
|
throw SysError("chdir to '%s' failed", dir);
|
||||||
|
|
@ -1827,9 +1828,21 @@ void connect(int fd, const std::string & path)
|
||||||
if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
||||||
throw SysError("cannot connect to socket at '%s'", path);
|
throw SysError("cannot connect to socket at '%s'", path);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
|
} catch (SysError & e) {
|
||||||
|
// If this raised a `SysError`, we want to rethrow it in the
|
||||||
|
// parent process.
|
||||||
|
// For that, we need to transmit the associated error code,
|
||||||
|
// which we do by setting it as the return code for the process.
|
||||||
|
_exit(e.errNo);
|
||||||
|
} catch (std::exception &) {
|
||||||
|
_exit(-1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
int status = pid.wait();
|
int status = pid.wait();
|
||||||
if (status != 0)
|
if (status > 0) {
|
||||||
|
errno = status;
|
||||||
|
throw SysError("cannot connect to socket at '%s'", path);
|
||||||
|
} else if (status < 0)
|
||||||
throw Error("cannot connect to socket at '%s'", path);
|
throw Error("cannot connect to socket at '%s'", path);
|
||||||
} else {
|
} else {
|
||||||
memcpy(addr.sun_path, path.c_str(), path.size() + 1);
|
memcpy(addr.sun_path, path.c_str(), path.size() + 1);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue