diff options
Diffstat (limited to 'src/libutil/util.cc')
-rw-r--r-- | src/libutil/util.cc | 75 |
1 files changed, 57 insertions, 18 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 563a72c12..1b6467eb2 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -512,6 +512,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix) AutoCloseFD fd(mkstemp((char *) tmpl.c_str())); if (!fd) throw SysError("creating temporary file '%s'", tmpl); + closeOnExec(fd.get()); return {std::move(fd), tmpl}; } @@ -562,7 +563,7 @@ Path getConfigDir() std::vector<Path> getConfigDirs() { Path configHome = getConfigDir(); - string configDirs = getEnv("XDG_CONFIG_DIRS").value_or(""); + string configDirs = getEnv("XDG_CONFIG_DIRS").value_or("/etc/xdg"); std::vector<Path> result = tokenizeString<std::vector<string>>(configDirs, ":"); result.insert(result.begin(), configHome); return result; @@ -1205,7 +1206,7 @@ void closeOnExec(int fd) ////////////////////////////////////////////////////////////////////// -bool _isInterrupted = false; +std::atomic<bool> _isInterrupted = false; static thread_local bool interruptThrown = false; thread_local std::function<bool()> interruptCheck; @@ -1436,8 +1437,7 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in } -static char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static std::array<char, 256> base64DecodeChars; +constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; string base64Encode(std::string_view s) { @@ -1462,12 +1462,15 @@ string base64Encode(std::string_view s) string base64Decode(std::string_view s) { - static std::once_flag flag; - std::call_once(flag, [](){ - base64DecodeChars = { (char)-1 }; + constexpr char npos = -1; + constexpr std::array<char, 256> base64DecodeChars = [&]() { + std::array<char, 256> result{}; + for (auto& c : result) + c = npos; for (int i = 0; i < 64; i++) - base64DecodeChars[(int) base64Chars[i]] = i; - }); + result[base64Chars[i]] = i; + return result; + }(); string res; unsigned int d = 0, bits = 0; @@ -1477,7 +1480,7 @@ string base64Decode(std::string_view s) if (c == '\n') continue; char digit = base64DecodeChars[(unsigned char) c]; - if (digit == -1) + if (digit == npos) throw Error("invalid character in Base64 string: '%c'", c); bits += 6; @@ -1630,9 +1633,39 @@ void setStackSize(size_t stackSize) #endif } -void restoreProcessContext() +static AutoCloseFD fdSavedMountNamespace; + +void saveMountNamespace() +{ +#if __linux__ + static std::once_flag done; + std::call_once(done, []() { + AutoCloseFD fd = open("/proc/self/ns/mnt", O_RDONLY); + if (!fd) + throw SysError("saving parent mount namespace"); + fdSavedMountNamespace = std::move(fd); + }); +#endif +} + +void restoreMountNamespace() +{ +#if __linux__ + try { + if (fdSavedMountNamespace && setns(fdSavedMountNamespace.get(), CLONE_NEWNS) == -1) + throw SysError("restoring parent mount namespace"); + } catch (Error & e) { + debug(e.msg()); + } +#endif +} + +void restoreProcessContext(bool restoreMounts) { restoreSignals(); + if (restoreMounts) { + restoreMountNamespace(); + } restoreAffinity(); @@ -1670,7 +1703,7 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> } -AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) +AutoCloseFD createUnixDomainSocket() { AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM #ifdef SOCK_CLOEXEC @@ -1679,8 +1712,14 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) , 0); if (!fdSocket) throw SysError("cannot create Unix domain socket"); - closeOnExec(fdSocket.get()); + return fdSocket; +} + + +AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) +{ + auto fdSocket = nix::createUnixDomainSocket(); bind(fdSocket.get(), path); @@ -1709,7 +1748,7 @@ void bind(int fd, const std::string & path) 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()); + memcpy(addr.sun_path, base.c_str(), base.size() + 1); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) throw SysError("cannot bind to socket '%s'", path); _exit(0); @@ -1718,7 +1757,7 @@ void bind(int fd, const std::string & path) if (status != 0) throw Error("cannot bind to socket '%s'", path); } else { - strcpy(addr.sun_path, path.c_str()); + memcpy(addr.sun_path, path.c_str(), path.size() + 1); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) throw SysError("cannot bind to socket '%s'", path); } @@ -1738,7 +1777,7 @@ void connect(int fd, const std::string & path) 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()); + memcpy(addr.sun_path, base.c_str(), base.size() + 1); if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) throw SysError("cannot connect to socket at '%s'", path); _exit(0); @@ -1747,7 +1786,7 @@ void connect(int fd, const std::string & path) if (status != 0) throw Error("cannot connect to socket at '%s'", path); } else { - strcpy(addr.sun_path, path.c_str()); + memcpy(addr.sun_path, path.c_str(), path.size() + 1); if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) throw SysError("cannot connect to socket at '%s'", path); } @@ -1766,7 +1805,7 @@ void commonChildInit(Pipe & logPipe) logger = makeSimpleLogger(); const static string pathNullDevice = "/dev/null"; - restoreProcessContext(); + restoreProcessContext(false); /* Put the child in a separate session (and thus a separate process group) so that it has no controlling terminal (meaning |