aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/util.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/util.hh')
-rw-r--r--src/libutil/util.hh166
1 files changed, 117 insertions, 49 deletions
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index bee77b53f..20591952d 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -11,6 +11,9 @@
#include <unistd.h>
#include <signal.h>
+#include <boost/lexical_cast.hpp>
+
+#include <atomic>
#include <functional>
#include <map>
#include <sstream>
@@ -46,30 +49,32 @@ void clearEnv();
specified directory, or the current directory otherwise. The path
is also canonicalised. */
Path absPath(Path path,
- std::optional<Path> dir = {},
+ std::optional<PathView> dir = {},
bool resolveSymlinks = false);
/* Canonicalise a path by removing all `.' or `..' components and
double or trailing slashes. Optionally resolves all symlink
components such that each component of the resulting path is *not*
a symbolic link. */
-Path canonPath(const Path & path, bool resolveSymlinks = false);
+Path canonPath(PathView path, bool resolveSymlinks = false);
/* Return the directory part of the given canonical path, i.e.,
everything before the final `/'. If the path is the root or an
immediate child thereof (e.g., `/foo'), this means `/'
is returned.*/
-Path dirOf(const Path & path);
+Path dirOf(const PathView path);
/* Return the base name of the given canonical path, i.e., everything
following the final `/' (trailing slashes are removed). */
std::string_view baseNameOf(std::string_view path);
-/* Check whether 'path' is a descendant of 'dir'. */
-bool isInDir(const Path & path, const Path & dir);
+/* Check whether 'path' is a descendant of 'dir'. Both paths must be
+ canonicalized. */
+bool isInDir(std::string_view path, std::string_view dir);
-/* Check whether 'path' is equal to 'dir' or a descendant of 'dir'. */
-bool isDirOrInDir(const Path & path, const Path & dir);
+/* Check whether 'path' is equal to 'dir' or a descendant of
+ 'dir'. Both paths must be canonicalized. */
+bool isDirOrInDir(std::string_view path, std::string_view dir);
/* Get status of `path'. */
struct stat lstat(const Path & path);
@@ -87,22 +92,22 @@ bool isLink(const Path & path);
removed. */
struct DirEntry
{
- string name;
+ std::string name;
ino_t ino;
unsigned char type; // one of DT_*
- DirEntry(const string & name, ino_t ino, unsigned char type)
- : name(name), ino(ino), type(type) { }
+ DirEntry(std::string name, ino_t ino, unsigned char type)
+ : name(std::move(name)), ino(ino), type(type) { }
};
-typedef vector<DirEntry> DirEntries;
+typedef std::vector<DirEntry> DirEntries;
DirEntries readDirectory(const Path & path);
unsigned char getFileType(const Path & path);
/* Read the contents of a file into a string. */
-string readFile(int fd);
-string readFile(const Path & path);
+std::string readFile(int fd);
+std::string readFile(const Path & path);
void readFile(const Path & path, Sink & sink);
/* Write a string to a file. */
@@ -111,10 +116,10 @@ void writeFile(const Path & path, std::string_view s, mode_t mode = 0666);
void writeFile(const Path & path, Source & source, mode_t mode = 0666);
/* Read a line from a file descriptor. */
-string readLine(int fd);
+std::string readLine(int fd);
/* Write a line to a file descriptor. */
-void writeLine(int fd, string s);
+void writeLine(int fd, std::string s);
/* Delete a path; i.e., in the case of a directory, it is deleted
recursively. It's not an error if the path does not exist. The
@@ -143,6 +148,9 @@ Path getDataDir();
/* Create a directory and all its parents, if necessary. Returns the
list of created directories, in order of creation. */
Paths createDirs(const Path & path);
+inline Paths createDirs(PathView path) {
+ return createDirs(Path(path));
+}
/* Create a symlink. */
void createSymlink(const Path & target, const Path & link,
@@ -162,7 +170,7 @@ MakeError(EndOfFile, Error);
/* Read a file descriptor until EOF occurs. */
-string drainFD(int fd, bool block = true, const size_t reserveSize=0);
+std::string drainFD(int fd, bool block = true, const size_t reserveSize=0);
void drainFD(int fd, Sink & sink, bool block = true);
@@ -182,6 +190,7 @@ public:
void cancel();
void reset(const Path & p, bool recursive = true);
operator Path() const { return path; }
+ operator PathView() const { return path; }
};
@@ -259,10 +268,10 @@ void killUser(uid_t uid);
pid to the caller. */
struct ProcessOptions
{
- string errorPrefix = "error: ";
+ std::string errorPrefix = "";
bool dieWithParent = true;
bool runExitHandlers = false;
- bool allowVfork = true;
+ bool allowVfork = false;
};
pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = ProcessOptions());
@@ -270,7 +279,7 @@ pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = P
/* Run a program and return its stdout in a string (i.e., like the
shell backtick operator). */
-string runProgram(Path program, bool searchPath = false,
+std::string runProgram(Path program, bool searchPath = false,
const Strings & args = Strings(),
const std::optional<std::string> & input = {});
@@ -299,8 +308,21 @@ void setStackSize(size_t stackSize);
/* Restore the original inherited Unix process context (such as signal
- masks, stack size, CPU affinity). */
-void restoreProcessContext();
+ masks, stack size). */
+void restoreProcessContext(bool restoreMounts = true);
+
+/* Save the current mount namespace. Ignored if called more than
+ once. */
+void saveMountNamespace();
+
+/* Restore the mount namespace saved by saveMountNamespace(). Ignored
+ if saveMountNamespace() was never called. */
+void restoreMountNamespace();
+
+/* Cause this thread to not share any FS attributes with the main
+ thread, because this causes setns() in restoreMountNamespace() to
+ fail. */
+void unshareFilesystem();
class ExecError : public Error
@@ -321,7 +343,7 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss);
/* Close all file descriptors except those listed in the given set.
Good practice in child processes. */
-void closeMostFDs(const set<int> & exceptions);
+void closeMostFDs(const std::set<int> & exceptions);
/* Set the close-on-exec flag for the given file descriptor. */
void closeOnExec(int fd);
@@ -329,7 +351,7 @@ void closeOnExec(int fd);
/* User interruption. */
-extern bool _isInterrupted;
+extern std::atomic<bool> _isInterrupted;
extern thread_local std::function<bool()> interruptCheck;
@@ -350,15 +372,19 @@ MakeError(FormatError, Error);
/* String tokenizer. */
-template<class C> C tokenizeString(std::string_view s, const string & separators = " \t\n\r");
+template<class C> C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r");
/* Concatenate the given strings with a separator between the
elements. */
template<class C>
-string concatStringsSep(const string & sep, const C & ss)
+std::string concatStringsSep(const std::string_view sep, const C & ss)
{
- string s;
+ size_t size = 0;
+ // need a cast to string_view since this is also called with Symbols
+ for (const auto & s : ss) size += sep.size() + std::string_view(s).size();
+ std::string s;
+ s.reserve(size);
for (auto & i : ss) {
if (s.size() != 0) s += sep;
s += i;
@@ -366,6 +392,14 @@ string concatStringsSep(const string & sep, const C & ss)
return s;
}
+template<class ... Parts>
+auto concatStrings(Parts && ... parts)
+ -> std::enable_if_t<(... && std::is_convertible_v<Parts, std::string_view>), std::string>
+{
+ std::string_view views[sizeof...(parts)] = { parts... };
+ return concatStringsSep({}, views);
+}
+
/* Add quotes around a collection of strings. */
template<class C> Strings quoteStrings(const C & c)
@@ -379,45 +413,47 @@ template<class C> Strings quoteStrings(const C & c)
/* Remove trailing whitespace from a string. FIXME: return
std::string_view. */
-string chomp(std::string_view s);
+std::string chomp(std::string_view s);
/* Remove whitespace from the start and end of a string. */
-string trim(const string & s, const string & whitespace = " \n\r\t");
+std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t");
/* Replace all occurrences of a string inside another string. */
-string replaceStrings(std::string_view s,
- const std::string & from, const std::string & to);
+std::string replaceStrings(
+ std::string s,
+ std::string_view from,
+ std::string_view to);
-std::string rewriteStrings(const std::string & s, const StringMap & rewrites);
+std::string rewriteStrings(std::string s, const StringMap & rewrites);
/* Convert the exit status of a child as returned by wait() into an
error string. */
-string statusToString(int status);
+std::string statusToString(int status);
bool statusOk(int status);
/* Parse a string into an integer. */
template<class N>
-std::optional<N> string2Int(const std::string & s)
+std::optional<N> string2Int(const std::string_view s)
{
if (s.substr(0, 1) == "-" && !std::numeric_limits<N>::is_signed)
return std::nullopt;
- std::istringstream str(s);
- N n;
- str >> n;
- if (str && str.get() == EOF) return n;
- return std::nullopt;
+ try {
+ return boost::lexical_cast<N>(s.data(), s.size());
+ } catch (const boost::bad_lexical_cast &) {
+ return std::nullopt;
+ }
}
/* Like string2Int(), but support an optional suffix 'K', 'M', 'G' or
'T' denoting a binary unit prefix. */
template<class N>
-N string2IntWithUnitPrefix(std::string s)
+N string2IntWithUnitPrefix(std::string_view s)
{
N multiplier = 1;
if (!s.empty()) {
@@ -428,7 +464,7 @@ N string2IntWithUnitPrefix(std::string s)
else if (u == 'G') multiplier = 1ULL << 30;
else if (u == 'T') multiplier = 1ULL << 40;
else throw UsageError("invalid unit specifier '%1%'", u);
- s.resize(s.size() - 1);
+ s.remove_suffix(1);
}
}
if (auto n = string2Int<N>(s))
@@ -438,13 +474,13 @@ N string2IntWithUnitPrefix(std::string s)
/* Parse a string into a float. */
template<class N>
-std::optional<N> string2Float(const string & s)
+std::optional<N> string2Float(const std::string_view s)
{
- std::istringstream str(s);
- N n;
- str >> n;
- if (str && str.get() == EOF) return n;
- return std::nullopt;
+ try {
+ return boost::lexical_cast<N>(s.data(), s.size());
+ } catch (const boost::bad_lexical_cast &) {
+ return std::nullopt;
+ }
}
@@ -461,7 +497,7 @@ std::string toLower(const std::string & s);
/* Escape a string as a shell word. */
-std::string shellEscape(const std::string & s);
+std::string shellEscape(const std::string_view s);
/* Exception handling in destructors: print an error message, then
@@ -491,8 +527,8 @@ std::string filterANSIEscapes(const std::string & s,
/* Base64 encoding/decoding. */
-string base64Encode(std::string_view s);
-string base64Decode(std::string_view s);
+std::string base64Encode(std::string_view s);
+std::string base64Decode(std::string_view s);
/* Remove common leading whitespace from the lines in the string
@@ -511,6 +547,29 @@ std::optional<typename T::mapped_type> get(const T & map, const typename T::key_
}
+/* Remove and return the first item from a container. */
+template <class T>
+std::optional<typename T::value_type> remove_begin(T & c)
+{
+ auto i = c.begin();
+ if (i == c.end()) return {};
+ auto v = std::move(*i);
+ c.erase(i);
+ return v;
+}
+
+
+/* Remove and return the first item from a container. */
+template <class T>
+std::optional<typename T::value_type> pop(T & c)
+{
+ if (c.empty()) return {};
+ auto v = std::move(c.front());
+ c.pop();
+ return v;
+}
+
+
template<typename T>
class Callback;
@@ -571,9 +630,18 @@ extern PathFilter defaultPathFilter;
/* Common initialisation performed in child processes. */
void commonChildInit(Pipe & logPipe);
+/* Create a Unix domain socket. */
+AutoCloseFD createUnixDomainSocket();
+
/* Create a Unix domain socket in listen mode. */
AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode);
+/* Bind a Unix domain socket to a path. */
+void bind(int fd, const std::string & path);
+
+/* Connect to a Unix domain socket. */
+void connect(int fd, const std::string & path);
+
// A Rust/Python-like enumerate() iterator adapter.
// Borrowed from http://reedbeta.com/blog/python-like-enumerate-in-cpp17.