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.hh971
1 files changed, 0 insertions, 971 deletions
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
deleted file mode 100644
index 14868776c..000000000
--- a/src/libutil/util.hh
+++ /dev/null
@@ -1,971 +0,0 @@
-#pragma once
-///@file
-
-#include "types.hh"
-#include "error.hh"
-#include "logging.hh"
-#include "ansicolor.hh"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <signal.h>
-
-#include <boost/lexical_cast.hpp>
-
-#include <atomic>
-#include <functional>
-#include <map>
-#include <sstream>
-#include <optional>
-
-#ifndef HAVE_STRUCT_DIRENT_D_TYPE
-#define DT_UNKNOWN 0
-#define DT_REG 1
-#define DT_LNK 2
-#define DT_DIR 3
-#endif
-
-namespace nix {
-
-struct Sink;
-struct Source;
-
-/**
- * The system for which Nix is compiled.
- */
-extern const std::string nativeSystem;
-
-
-/**
- * @return an environment variable.
- */
-std::optional<std::string> getEnv(const std::string & key);
-
-/**
- * @return a non empty environment variable. Returns nullopt if the env
- * variable is set to ""
- */
-std::optional<std::string> getEnvNonEmpty(const std::string & key);
-
-/**
- * Get the entire environment.
- */
-std::map<std::string, std::string> getEnv();
-
-/**
- * Clear the environment.
- */
-void clearEnv();
-
-/**
- * @return An absolutized path, resolving paths relative to the
- * specified directory, or the current directory otherwise. The path
- * is also canonicalised.
- */
-Path absPath(Path path,
- 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(PathView path, bool resolveSymlinks = false);
-
-/**
- * Change the permissions of a path
- * Not called `chmod` as it shadows and could be confused with
- * `int chmod(char *, mode_t)`, which does not handle errors
- */
-void chmodPath(const Path & path, mode_t mode);
-
-/**
- * @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 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);
-
-/**
- * Perform tilde expansion on a path.
- */
-std::string expandTilde(std::string_view path);
-
-/**
- * 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'. Both paths must be canonicalized.
- */
-bool isDirOrInDir(std::string_view path, std::string_view dir);
-
-/**
- * Get status of `path`.
- */
-struct stat stat(const Path & path);
-struct stat lstat(const Path & path);
-
-/**
- * `lstat` the given path if it exists.
- * @return std::nullopt if the path doesn't exist, or an optional containing the result of `lstat` otherwise
- */
-std::optional<struct stat> maybeLstat(const Path & path);
-
-/**
- * @return true iff the given path exists.
- */
-bool pathExists(const Path & path);
-
-/**
- * A version of pathExists that returns false on a permission error.
- * Useful for inferring default paths across directories that might not
- * be readable.
- * @return true iff the given path can be accessed and exists
- */
-bool pathAccessible(const Path & path);
-
-/**
- * Read the contents (target) of a symbolic link. The result is not
- * in any way canonicalised.
- */
-Path readLink(const Path & path);
-
-bool isLink(const Path & path);
-
-/**
- * Read the contents of a directory. The entries `.` and `..` are
- * removed.
- */
-struct DirEntry
-{
- std::string name;
- ino_t ino;
- /**
- * one of DT_*
- */
- unsigned char type;
- DirEntry(std::string name, ino_t ino, unsigned char type)
- : name(std::move(name)), ino(ino), type(type) { }
-};
-
-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.
- */
-std::string readFile(int fd);
-std::string readFile(const Path & path);
-void readFile(const Path & path, Sink & sink);
-
-/**
- * Write a string to a file.
- */
-void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
-
-void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
-
-/**
- * Flush a file's parent directory to disk
- */
-void syncParent(const Path & path);
-
-/**
- * Read a line from a file descriptor.
- */
-std::string readLine(int fd);
-
-/**
- * Write a line to a file descriptor.
- */
-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
- * second variant returns the number of bytes and blocks freed.
- */
-void deletePath(const Path & path);
-
-void deletePath(const Path & path, uint64_t & bytesFreed);
-
-std::string getUserName();
-
-/**
- * @return the given user's home directory from /etc/passwd.
- */
-Path getHomeOf(uid_t userId);
-
-/**
- * @return $HOME or the user's home directory from /etc/passwd.
- */
-Path getHome();
-
-/**
- * @return $XDG_CACHE_HOME or $HOME/.cache.
- */
-Path getCacheDir();
-
-/**
- * @return $XDG_CONFIG_HOME or $HOME/.config.
- */
-Path getConfigDir();
-
-/**
- * @return the directories to search for user configuration files
- */
-std::vector<Path> getConfigDirs();
-
-/**
- * @return $XDG_DATA_HOME or $HOME/.local/share.
- */
-Path getDataDir();
-
-/**
- * @return the path of the current executable.
- */
-std::optional<Path> getSelfExe();
-
-/**
- * @return $XDG_STATE_HOME or $HOME/.local/state.
- *
- * @note Not to be confused with settings.nixStateDir.
- */
-Path getStateDir();
-
-/**
- * Create $XDG_STATE_HOME/nix or $HOME/.local/state/nix, and return
- * the path to it.
- * @note Not to be confused with settings.nixStateDir.
- */
-Path createNixStateDir();
-
-/**
- * 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);
-
-/**
- * Atomically create or replace a symlink.
- */
-void replaceSymlink(const Path & target, const Path & link);
-
-void renameFile(const Path & src, const Path & dst);
-
-/**
- * Similar to 'renameFile', but fallback to a copy+remove if `src` and `dst`
- * are on a different filesystem.
- *
- * Beware that this might not be atomic because of the copy that happens behind
- * the scenes
- */
-void moveFile(const Path & src, const Path & dst);
-
-struct CopyFileFlags
-{
- /**
- * Delete the file after copying.
- */
- bool deleteAfter = false;
-
- /**
- * Follow symlinks and copy the eventual target.
- */
- bool followSymlinks = false;
-};
-
-/**
- * Recursively copy the content of `oldPath` to `newPath`. If `andDelete` is
- * `true`, then also remove `oldPath` (making this equivalent to `moveFile`, but
- * with the guaranty that the destination will be “fresh”, with no stale inode
- * or file descriptor pointing to it).
- */
-void copyFile(const Path & oldPath, const Path & newPath, CopyFileFlags flags);
-
-/**
- * Wrappers arount read()/write() that read/write exactly the
- * requested number of bytes.
- */
-void readFull(int fd, char * buf, size_t count);
-void writeFull(int fd, std::string_view s, bool allowInterrupts = true);
-
-MakeError(EndOfFile, Error);
-
-
-/**
- * Read a file descriptor until EOF occurs.
- */
-std::string drainFD(int fd, bool block = true, const size_t reserveSize=0);
-
-void drainFD(int fd, Sink & sink, bool block = true);
-
-/**
- * If cgroups are active, attempt to calculate the number of CPUs available.
- * If cgroups are unavailable or if cpu.max is set to "max", return 0.
- */
-unsigned int getMaxCPU();
-
-/**
- * Automatic cleanup of resources.
- */
-
-
-class AutoDelete
-{
- Path path;
- bool del;
- bool recursive;
-public:
- AutoDelete();
- AutoDelete(const Path & p, bool recursive = true);
- ~AutoDelete();
- void cancel();
- void reset(const Path & p, bool recursive = true);
- operator Path() const { return path; }
- operator PathView() const { return path; }
-};
-
-
-class AutoCloseFD
-{
- int fd;
-public:
- AutoCloseFD();
- explicit AutoCloseFD(int fd);
- AutoCloseFD(const AutoCloseFD & fd) = delete;
- AutoCloseFD(AutoCloseFD&& fd);
- ~AutoCloseFD();
- AutoCloseFD& operator =(const AutoCloseFD & fd) = delete;
- AutoCloseFD& operator =(AutoCloseFD&& fd) noexcept(false);
- int get() const;
- explicit operator bool() const;
- int release();
- void close();
- void fsync();
- void reset() { *this = {}; }
-};
-
-
-/**
- * Create a temporary directory.
- */
-Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix",
- bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755);
-
-/**
- * Create a temporary file, returning a file handle and its path.
- */
-std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix = "nix");
-
-
-class Pipe
-{
-public:
- AutoCloseFD readSide, writeSide;
- void create();
- void close();
-};
-
-
-struct DIRDeleter
-{
- void operator()(DIR * dir) const {
- closedir(dir);
- }
-};
-
-typedef std::unique_ptr<DIR, DIRDeleter> AutoCloseDir;
-
-
-class Pid
-{
- pid_t pid = -1;
- bool separatePG = false;
- int killSignal = SIGKILL;
-public:
- Pid();
- Pid(pid_t pid);
- ~Pid() noexcept(false);
- void operator =(pid_t pid);
- operator pid_t();
- int kill();
- int wait();
-
- void setSeparatePG(bool separatePG);
- void setKillSignal(int signal);
- pid_t release();
-};
-
-
-/**
- * Kill all processes running under the specified uid by sending them
- * a SIGKILL.
- */
-void killUser(uid_t uid);
-
-
-/**
- * Fork a process that runs the given function, and return the child
- * pid to the caller.
- */
-struct ProcessOptions
-{
- std::string errorPrefix = "";
- bool dieWithParent = true;
- bool runExitHandlers = false;
- /**
- * use clone() with the specified flags (Linux only)
- */
- int cloneFlags = 0;
-};
-
-pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = ProcessOptions());
-
-
-/**
- * Run a program and return its stdout in a string (i.e., like the
- * shell backtick operator).
- */
-std::string runProgram(Path program, bool searchPath = false,
- const Strings & args = Strings(),
- const std::optional<std::string> & input = {}, bool isInteractive = false);
-
-struct RunOptions
-{
- Path program;
- bool searchPath = true;
- Strings args;
- std::optional<uid_t> uid;
- std::optional<uid_t> gid;
- std::optional<Path> chdir;
- std::optional<std::map<std::string, std::string>> environment;
- std::optional<std::string> input;
- Source * standardIn = nullptr;
- Sink * standardOut = nullptr;
- bool mergeStderrToStdout = false;
- bool isInteractive = false;
-};
-
-std::pair<int, std::string> runProgram(RunOptions && options);
-
-void runProgram2(const RunOptions & options);
-
-
-/**
- * Change the stack size.
- */
-void setStackSize(rlim_t stackSize);
-
-
-/**
- * Restore the original inherited Unix process context (such as signal
- * masks, stack size).
-
- * See startSignalHandlerThread(), saveSignalMask().
- */
-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
-{
-public:
- int status;
-
- template<typename... Args>
- ExecError(int status, const Args & ... args)
- : Error(args...), status(status)
- { }
-};
-
-/**
- * Convert a list of strings to a null-terminated vector of `char
- * *`s. The result must not be accessed beyond the lifetime of the
- * list of strings.
- */
-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 std::set<int> & exceptions);
-
-/**
- * Set the close-on-exec flag for the given file descriptor.
- */
-void closeOnExec(int fd);
-
-
-MakeError(FormatError, Error);
-
-
-/**
- * String tokenizer.
- */
-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>
-std::string concatStringsSep(const std::string_view sep, const C & ss)
-{
- 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;
- }
- 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)
-{
- Strings res;
- for (auto & s : c)
- res.push_back("'" + s + "'");
- return res;
-}
-
-/**
- * Remove trailing whitespace from a string.
- *
- * \todo return std::string_view.
- */
-std::string chomp(std::string_view s);
-
-
-/**
- * Remove whitespace from the start and end of a string.
- */
-std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t");
-
-
-/**
- * Replace all occurrences of a string inside another string.
- */
-std::string replaceStrings(
- std::string s,
- std::string_view from,
- std::string_view to);
-
-
-/**
- * Rewrites a string given a map of replacements, applying the replacements in
- * sorted order, only once, considering only the strings appearing in the input
- * string in performing replacement.
- *
- * - Replacements are not performed on intermediate strings. That is, for an input
- * `"abb"` with replacements `{"ab" -> "ba"}`, the result is `"bab"`.
- * - Transitive replacements are not performed. For example, for the input `"abcde"`
- * with replacements `{"a" -> "b", "b" -> "c", "e" -> "b"}`, the result is
- * `"bccdb"`.
- */
-class Rewriter
-{
-private:
- std::string initials;
- std::map<std::string, std::string> rewrites;
-
-public:
- explicit Rewriter(std::map<std::string, std::string> rewrites);
-
- std::string operator()(std::string s);
-};
-
-inline std::string rewriteStrings(std::string s, const StringMap & rewrites)
-{
- return Rewriter(rewrites)(s);
-}
-
-
-/**
- * Convert the exit status of a child as returned by wait() into an
- * error string.
- */
-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_view s)
-{
- if (s.substr(0, 1) == "-" && !std::numeric_limits<N>::is_signed)
- 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_view s)
-{
- N multiplier = 1;
- if (!s.empty()) {
- char u = std::toupper(*s.rbegin());
- if (std::isalpha(u)) {
- if (u == 'K') multiplier = 1ULL << 10;
- else if (u == 'M') multiplier = 1ULL << 20;
- else if (u == 'G') multiplier = 1ULL << 30;
- else if (u == 'T') multiplier = 1ULL << 40;
- else throw UsageError("invalid unit specifier '%1%'", u);
- s.remove_suffix(1);
- }
- }
- if (auto n = string2Int<N>(s))
- return *n * multiplier;
- throw UsageError("'%s' is not an integer", s);
-}
-
-/**
- * Parse a string into a float.
- */
-template<class N>
-std::optional<N> string2Float(const std::string_view s)
-{
- try {
- return boost::lexical_cast<N>(s.data(), s.size());
- } catch (const boost::bad_lexical_cast &) {
- return std::nullopt;
- }
-}
-
-
-/**
- * Convert a little-endian integer to host order.
- */
-template<typename T>
-T readLittleEndian(unsigned char * p)
-{
- T x = 0;
- for (size_t i = 0; i < sizeof(x); ++i, ++p) {
- x |= ((T) *p) << (i * 8);
- }
- return x;
-}
-
-/**
- * Convert a string to lower case.
- */
-std::string toLower(const std::string & s);
-
-
-/**
- * Escape a string as a shell word.
- */
-std::string shellEscape(const std::string_view s);
-
-
-/**
- * Exception handling in destructors: print an error message, then
- * ignore the exception.
- */
-void ignoreException(Verbosity lvl = lvlError);
-
-
-
-/**
- * Tree formatting.
- */
-constexpr char treeConn[] = "├───";
-constexpr char treeLast[] = "└───";
-constexpr char treeLine[] = "│ ";
-constexpr char treeNull[] = " ";
-
-/**
- * Determine whether ANSI escape sequences are appropriate for the
- * present output.
- */
-bool shouldANSI();
-
-/**
- * Truncate a string to 'width' printable characters. If 'filterAll'
- * is true, all ANSI escape sequences are filtered out. Otherwise,
- * some escape sequences (such as colour setting) are copied but not
- * included in the character count. Also, tabs are expanded to
- * spaces.
- */
-std::string filterANSIEscapes(std::string_view s,
- bool filterAll = false,
- unsigned int width = std::numeric_limits<unsigned int>::max());
-
-
-/**
- * Base64 encoding/decoding.
- */
-std::string base64Encode(std::string_view s);
-std::string base64Decode(std::string_view s);
-
-
-/**
- * Remove common leading whitespace from the lines in the string
- * 's'. For example, if every line is indented by at least 3 spaces,
- * then we remove 3 spaces from the start of every line.
- */
-std::string stripIndentation(std::string_view s);
-
-
-/**
- * Get the prefix of 's' up to and excluding the next line break (LF
- * optionally preceded by CR), and the remainder following the line
- * break.
- */
-std::pair<std::string_view, std::string_view> getLine(std::string_view s);
-
-
-/**
- * Get a value for the specified key from an associate container.
- */
-template <class T>
-const typename T::mapped_type * get(const T & map, const typename T::key_type & key)
-{
- auto i = map.find(key);
- if (i == map.end()) return nullptr;
- return &i->second;
-}
-
-template <class T>
-typename T::mapped_type * get(T & map, const typename T::key_type & key)
-{
- auto i = map.find(key);
- if (i == map.end()) return nullptr;
- return &i->second;
-}
-
-/**
- * Get a value for the specified key from an associate container, or a default value if the key isn't present.
- */
-template <class T>
-const typename T::mapped_type & getOr(T & map,
- const typename T::key_type & key,
- const typename T::mapped_type & defaultValue)
-{
- auto i = map.find(key);
- if (i == map.end()) return defaultValue;
- return i->second;
-}
-
-/**
- * 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;
-}
-
-
-/**
- * A RAII helper that increments a counter on construction and
- * decrements it on destruction.
- */
-template<typename T>
-struct MaintainCount
-{
- T & counter;
- long delta;
- MaintainCount(T & counter, long delta = 1) : counter(counter), delta(delta) { counter += delta; }
- ~MaintainCount() { counter -= delta; }
-};
-
-
-/**
- * @return the number of rows and columns of the terminal.
- */
-std::pair<unsigned short, unsigned short> getWindowSize();
-
-void updateWindowSize();
-
-
-/**
- * Used in various places.
- */
-typedef std::function<bool(const Path & path)> PathFilter;
-
-extern PathFilter defaultPathFilter;
-
-/**
- * Common initialisation performed in child processes.
- */
-void commonChildInit();
-
-/**
- * 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.
- */
-template <typename T,
- typename TIter = decltype(std::begin(std::declval<T>())),
- typename = decltype(std::end(std::declval<T>()))>
-constexpr auto enumerate(T && iterable)
-{
- struct iterator
- {
- size_t i;
- TIter iter;
- constexpr bool operator != (const iterator & other) const { return iter != other.iter; }
- constexpr void operator ++ () { ++i; ++iter; }
- constexpr auto operator * () const { return std::tie(i, *iter); }
- };
-
- struct iterable_wrapper
- {
- T iterable;
- constexpr auto begin() { return iterator{ 0, std::begin(iterable) }; }
- constexpr auto end() { return iterator{ 0, std::end(iterable) }; }
- };
-
- return iterable_wrapper{ std::forward<T>(iterable) };
-}
-
-
-/**
- * C++17 std::visit boilerplate
- */
-template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
-template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
-
-
-std::string showBytes(uint64_t bytes);
-
-
-/**
- * Provide an addition operator between strings and string_views
- * inexplicably omitted from the standard library.
- */
-inline std::string operator + (const std::string & s1, std::string_view s2)
-{
- auto s = s1;
- s.append(s2);
- return s;
-}
-
-inline std::string operator + (std::string && s, std::string_view s2)
-{
- s.append(s2);
- return std::move(s);
-}
-
-inline std::string operator + (std::string_view s1, const char * s2)
-{
- std::string s;
- s.reserve(s1.size() + strlen(s2));
- s.append(s1);
- s.append(s2);
- return s;
-}
-
-}