mirror of
https://github.com/NixOS/nix.git
synced 2025-11-17 16:02:43 +01:00
For example, instead of doing
#include "nix/store-config.hh"
#include "nix/derived-path.hh"
Now do
#include "nix/store/config.hh"
#include "nix/store/derived-path.hh"
This was originally planned in the issue, and also recent requested by
Eelco.
Most of the change is purely mechanical. There is just one small
additional issue. See how, in the example above, we took this
opportunity to also turn `<comp>-config.hh` into `<comp>/config.hh`.
Well, there was already a `nix/util/config.{cc,hh}`. Even though there
is not a public configuration header for libutil (which also would be
called `nix/util/config.{cc,hh}`) that's still confusing, To avoid any
such confusion, we renamed that to `nix/util/configuration.{cc,hh}`.
Finally, note that the libflake headers already did this, so we didn't
need to do anything to them. We wouldn't want to mistakenly get
`nix/flake/flake/flake.hh`!
Progress on #7876
117 lines
3.5 KiB
C++
117 lines
3.5 KiB
C++
#include "nix/util/file-system.hh"
|
|
#include "nix/util/unix-domain-socket.hh"
|
|
#include "nix/util/util.hh"
|
|
|
|
#ifdef _WIN32
|
|
# include <winsock2.h>
|
|
# include <afunix.h>
|
|
#else
|
|
# include <sys/socket.h>
|
|
# include <sys/un.h>
|
|
# include "nix/util/processes.hh"
|
|
#endif
|
|
#include <unistd.h>
|
|
|
|
namespace nix {
|
|
|
|
AutoCloseFD createUnixDomainSocket()
|
|
{
|
|
AutoCloseFD fdSocket = toDescriptor(socket(PF_UNIX, SOCK_STREAM
|
|
#ifdef SOCK_CLOEXEC
|
|
| SOCK_CLOEXEC
|
|
#endif
|
|
, 0));
|
|
if (!fdSocket)
|
|
throw SysError("cannot create Unix domain socket");
|
|
#ifndef _WIN32
|
|
unix::closeOnExec(fdSocket.get());
|
|
#endif
|
|
return fdSocket;
|
|
}
|
|
|
|
|
|
AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode)
|
|
{
|
|
auto fdSocket = nix::createUnixDomainSocket();
|
|
|
|
bind(fdSocket.get(), path);
|
|
|
|
if (chmod(path.c_str(), mode) == -1)
|
|
throw SysError("changing permissions on '%1%'", path);
|
|
|
|
if (listen(toSocket(fdSocket.get()), 100) == -1)
|
|
throw SysError("cannot listen on socket '%1%'", path);
|
|
|
|
return fdSocket;
|
|
}
|
|
|
|
static void bindConnectProcHelper(
|
|
std::string_view operationName, auto && operation,
|
|
Socket fd, const std::string & path)
|
|
{
|
|
struct sockaddr_un addr;
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
// Casting between types like these legacy C library interfaces
|
|
// require is forbidden in C++. To maintain backwards
|
|
// compatibility, the implementation of the bind/connect functions
|
|
// contains some hints to the compiler that allow for this
|
|
// special case.
|
|
auto * psaddr = reinterpret_cast<struct sockaddr *>(&addr);
|
|
|
|
if (path.size() + 1 >= sizeof(addr.sun_path)) {
|
|
#ifdef _WIN32
|
|
throw Error("cannot %s to socket at '%s': path is too long", operationName, path);
|
|
#else
|
|
Pipe pipe;
|
|
pipe.create();
|
|
Pid pid = startProcess([&] {
|
|
try {
|
|
pipe.readSide.close();
|
|
Path 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);
|
|
memcpy(addr.sun_path, base.c_str(), base.size() + 1);
|
|
if (operation(fd, psaddr, sizeof(addr)) == -1)
|
|
throw SysError("cannot %s to socket at '%s'", operationName, path);
|
|
writeFull(pipe.writeSide.get(), "0\n");
|
|
} catch (SysError & e) {
|
|
writeFull(pipe.writeSide.get(), fmt("%d\n", e.errNo));
|
|
} catch (...) {
|
|
writeFull(pipe.writeSide.get(), "-1\n");
|
|
}
|
|
});
|
|
pipe.writeSide.close();
|
|
auto errNo = string2Int<int>(chomp(drainFD(pipe.readSide.get())));
|
|
if (!errNo || *errNo == -1)
|
|
throw Error("cannot %s to socket at '%s'", operationName, path);
|
|
else if (*errNo > 0) {
|
|
errno = *errNo;
|
|
throw SysError("cannot %s to socket at '%s'", operationName, path);
|
|
}
|
|
#endif
|
|
} else {
|
|
memcpy(addr.sun_path, path.c_str(), path.size() + 1);
|
|
if (operation(fd, psaddr, sizeof(addr)) == -1)
|
|
throw SysError("cannot %s to socket at '%s'", operationName, path);
|
|
}
|
|
}
|
|
|
|
|
|
void bind(Socket fd, const std::string & path)
|
|
{
|
|
unlink(path.c_str());
|
|
|
|
bindConnectProcHelper("bind", ::bind, fd, path);
|
|
}
|
|
|
|
|
|
void connect(Socket fd, const std::string & path)
|
|
{
|
|
bindConnectProcHelper("connect", ::connect, fd, path);
|
|
}
|
|
|
|
}
|