diff --git a/meson.build b/meson.build index 0a24cca436b1..fba9bfc530f2 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,7 @@ project( # Internal Libraries subproject('libutil') +subproject('libroots') subproject('libstore') subproject('libfetchers') subproject('libexpr') diff --git a/packaging/components.nix b/packaging/components.nix index 6757323c428e..e3ab9dd2bae0 100644 --- a/packaging/components.nix +++ b/packaging/components.nix @@ -411,6 +411,8 @@ in nix-flake-c = callPackage ../src/libflake-c/package.nix { }; nix-flake-tests = callPackage ../src/libflake-tests/package.nix { }; + nix-roots = callPackage ../src/libroots/package.nix { }; + nix-main = callPackage ../src/libmain/package.nix { }; nix-main-c = callPackage ../src/libmain-c/package.nix { }; diff --git a/packaging/hydra.nix b/packaging/hydra.nix index 8bc9a7a7dc8b..a5a884b133ad 100644 --- a/packaging/hydra.nix +++ b/packaging/hydra.nix @@ -59,6 +59,7 @@ let "nix-flake-tests" "nix-main" "nix-main-c" + "nix-roots" "nix-cmd" "nix-cli" "nix-functional-tests" diff --git a/src/libroots/.version b/src/libroots/.version new file mode 120000 index 000000000000..b7badcd0cc85 --- /dev/null +++ b/src/libroots/.version @@ -0,0 +1 @@ +../../.version \ No newline at end of file diff --git a/src/libroots/include/nix/roots/meson.build b/src/libroots/include/nix/roots/meson.build new file mode 100644 index 000000000000..72ea130fa3bb --- /dev/null +++ b/src/libroots/include/nix/roots/meson.build @@ -0,0 +1,5 @@ +# Public headers directory + +include_dirs = [ include_directories('../..') ] + +headers = files('roots.hh') diff --git a/src/libroots/include/nix/roots/roots.hh b/src/libroots/include/nix/roots/roots.hh new file mode 100644 index 000000000000..0e9a3576ba5b --- /dev/null +++ b/src/libroots/include/nix/roots/roots.hh @@ -0,0 +1,31 @@ +#pragma once + +#include "nix/util/strings.hh" +#include +#include +#include + +namespace nix::roots_tracer { + +struct TracerConfig +{ + const std::filesystem::path storeDir = "/nix/store"; + const std::filesystem::path stateDir = "/nix/var/nix"; + const std::filesystem::path socketPath = "/nix/var/nix/gc-socket/socket"; +}; + +/** + * A value of type `Roots` is a mapping from a store path to the set of roots that keep it alive + */ +typedef boost::unordered_flat_map< + std::string, + boost::unordered_flat_set>, + StringViewHash, + std::equal_to<>> + UncheckedRoots; + +void findRuntimeRoots(const TracerConfig & opts, UncheckedRoots & unchecked, bool censor); + +void findRoots(const TracerConfig & opts, const Path & path, std::filesystem::file_type type, UncheckedRoots & roots); + +} // namespace nix::roots_tracer diff --git a/src/libroots/meson.build b/src/libroots/meson.build new file mode 100644 index 000000000000..beb67a040e42 --- /dev/null +++ b/src/libroots/meson.build @@ -0,0 +1,73 @@ +project( + 'nix-roots', + 'cpp', + version : files('.version'), + default_options : [ + 'cpp_std=c++23', + # TODO(Qyriad): increase the warning level + 'warning_level=1', + 'errorlogs=true', # Please print logs for tests that fail + ], + meson_version : '>= 1.1', + license : 'LGPL-2.1-or-later', +) + +cxx = meson.get_compiler('cpp') + +subdir('nix-meson-build-support/deps-lists') + +deps_private_maybe_subproject = [] +deps_public_maybe_subproject = [ dependency('nix-util') ] +subdir('nix-meson-build-support/subprojects') + +subdir('nix-meson-build-support/common') + +boost = dependency( + 'boost', + modules : [ + 'container', + ], + include_type : 'system', +) +deps_other += boost + +configdata_priv = configuration_data() + +lsof = find_program('lsof', required : false) +configdata_priv.set_quoted( + 'LSOF', + lsof.found() ? lsof.full_path() + # Just look up on the PATH +: 'lsof', +) + +config_priv_h = configure_file( + configuration : configdata_priv, + output : 'roots-config-private.hh', +) + +sources = files( + 'roots.cc', +) + +subdir('include/nix/roots') + +subdir('nix-meson-build-support/export-all-symbols') +subdir('nix-meson-build-support/windows-version') + +this_library = library( + 'nixroots', + sources, + config_priv_h, + soversion : nix_soversion, + dependencies : deps_public + deps_private + deps_other, + include_directories : include_dirs, + link_args : linker_export_flags, + install : true, +) + +install_headers(headers, subdir : 'nix/roots', preserve_path : true) + +libraries_private = [] + +subdir('nix-meson-build-support/export') diff --git a/src/libroots/nix-meson-build-support b/src/libroots/nix-meson-build-support new file mode 120000 index 000000000000..0b140f56bdee --- /dev/null +++ b/src/libroots/nix-meson-build-support @@ -0,0 +1 @@ +../../nix-meson-build-support \ No newline at end of file diff --git a/src/libroots/package.nix b/src/libroots/package.nix new file mode 100644 index 000000000000..4765563c3ffc --- /dev/null +++ b/src/libroots/package.nix @@ -0,0 +1,40 @@ +{ + lib, + mkMesonLibrary, + + nix-util, + + # Configuration Options + + version, +}: + +let + inherit (lib) fileset; +in + +mkMesonLibrary (finalAttrs: { + pname = "nix-roots"; + inherit version; + + workDir = ./.; + fileset = fileset.unions [ + ../../nix-meson-build-support + ./nix-meson-build-support + ../../.version + ./.version + ./meson.build + ./include/nix/roots/meson.build + (fileset.fileFilter (file: file.hasExt "cc") ./.) + (fileset.fileFilter (file: file.hasExt "hh") ./.) + ]; + + propagatedBuildInputs = [ + nix-util + ]; + + meta = { + platforms = lib.platforms.unix ++ lib.platforms.windows; + }; + +}) diff --git a/src/libroots/roots.cc b/src/libroots/roots.cc new file mode 100644 index 000000000000..395a828a509a --- /dev/null +++ b/src/libroots/roots.cc @@ -0,0 +1,259 @@ +/** + * @file + * + * A very simple utility to trace all the gc roots through the file-system + * The reason for this program is that tracing these roots is the only part of + * Nix that requires to run as root (because it requires reading through the + * user home directories to resolve the indirect roots) + */ + +#include "nix/roots/roots.hh" +#include "nix/util/environment-variables.hh" +#include "nix/util/file-system.hh" +#include "nix/util/processes.hh" +#include "nix/util/signals.hh" +#include "nix/util/strings.hh" + +#include "roots-config-private.hh" + +#include +#include +#include +#include +#include +#include + +namespace nix::roots_tracer { +static std::string censored = "{censored}"; + +static bool isInStore(std::filesystem::path storeDir, std::filesystem::path dir) +{ + return (std::search(dir.begin(), dir.end(), storeDir.begin(), storeDir.end()) == dir.begin()); +} + +static void readProcLink(const std::filesystem::path & file, UncheckedRoots & roots) +{ + std::filesystem::path buf; + try { + buf = std::filesystem::read_symlink(file); + } catch (std::filesystem::filesystem_error & e) { + if (e.code() == std::errc::no_such_file_or_directory || e.code() == std::errc::permission_denied + || e.code() == std::errc::no_such_process) + return; + throw; + } + if (buf.is_absolute()) + roots[buf.string()].emplace(file.string()); +} + +static std::string quoteRegexChars(const std::string & raw) +{ + static auto specialRegex = boost::regex(R"([.^$\\*+?()\[\]{}|])"); + return boost::regex_replace(raw, specialRegex, R"(\$&)"); +} + +static boost::regex makeStorePathRegex(const std::filesystem::path storeDir) +{ + return boost::regex(quoteRegexChars(std::string(storeDir) + "/") + R"((?!\.\.?(-|$))[0-9a-zA-Z\+\-\._\?=]+)"); +} + +static bool isStorePath(const boost::regex & storePathRegex, const std::string & path) +{ + // On Windows, `/nix/store` is not a canonical path. More broadly it + // is unclear whether this function should be using the native + // notion of a canonical path at all. For example, it makes to + // support remote stores whose store dir is a non-native path (e.g. + // Windows <-> Unix ssh-ing). + auto p = +#ifdef _WIN32 + path +#else + canonPath(path) +#endif + ; + + return boost::regex_match(p, storePathRegex); +} + +#ifdef __linux__ +static void readFileRoots(const std::filesystem::path & path, UncheckedRoots & roots) +{ + try { + roots[readFile(path)].emplace(path.string()); + } catch (SystemError & e) { + if (!e.is(std::errc::no_such_file_or_directory) && !e.is(std::errc::permission_denied)) + throw; + } +} +#endif + +void findRuntimeRoots(const TracerConfig & opts, UncheckedRoots & roots, bool censor) +{ + UncheckedRoots unchecked; + +#ifdef __linux__ + // The /proc directory either doesn't exist or looks very different on other OSes, + // so only bother attempting on linux. + auto procDir = AutoCloseDir{opendir("/proc")}; + if (procDir) { + struct dirent * ent; + static const auto digitsRegex = boost::regex(R"(^\d+$)"); + static const auto mapRegex = boost::regex(R"(^\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(/\S+)\s*$)"); + auto storePathRegex = makeStorePathRegex(opts.storeDir); + while (errno = 0, ent = readdir(procDir.get())) { + checkInterrupt(); + if (boost::regex_match(ent->d_name, digitsRegex)) { + try { + readProcLink(fmt("/proc/%s/exe", ent->d_name), unchecked); + readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked); + + auto fdStr = fmt("/proc/%s/fd", ent->d_name); + auto fdDir = AutoCloseDir(opendir(fdStr.c_str())); + if (!fdDir) { + if (errno == ENOENT || errno == EACCES) + continue; + throw SysError("opening %1%", fdStr); + } + struct dirent * fd_ent; + while (errno = 0, fd_ent = readdir(fdDir.get())) { + if (fd_ent->d_name[0] != '.') + readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked); + } + if (errno) { + if (errno == ESRCH) + continue; + throw SysError("iterating /proc/%1%/fd", ent->d_name); + } + fdDir.reset(); + + std::filesystem::path mapFile = fmt("/proc/%s/maps", ent->d_name); + auto mapLines = tokenizeString>(readFile(mapFile.string()), "\n"); + for (const auto & line : mapLines) { + auto match = boost::smatch{}; + if (boost::regex_match(line, match, mapRegex)) + unchecked[match[1]].emplace(mapFile.string()); + } + + auto envFile = fmt("/proc/%s/environ", ent->d_name); + auto envString = readFile(envFile); + auto env_end = boost::sregex_iterator{}; + for (auto i = boost::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; + i != env_end; + ++i) + unchecked[i->str()].emplace(envFile); + } catch (SystemError & e) { + if (errno == ENOENT || errno == EACCES || errno == ESRCH) + continue; + throw; + } + } + } + if (errno) + throw SysError("iterating /proc"); + } + readFileRoots("/proc/sys/kernel/modprobe", unchecked); + readFileRoots("/proc/sys/kernel/fbsplash", unchecked); + readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked); +#else + // lsof is really slow on OS X. This actually causes the gc-concurrent.sh test to fail. + // See: https://github.com/NixOS/nix/issues/3011 + // Because of this we disable lsof when running the tests. + if (getEnv("_NIX_TEST_NO_LSOF") != "1") { + try { + boost::regex lsofRegex(R"(^n(/.*)$)"); + auto lsofLines = + tokenizeString>(runProgram(LSOF, true, {"-n", "-w", "-F", "n"}), "\n"); + for (const auto & line : lsofLines) { + boost::smatch match; + if (boost::regex_match(line, match, lsofRegex)) + unchecked[match[1].str()].emplace("{lsof}"); + } + } catch (ExecError & e) { + /* lsof not installed, lsof failed */ + } + } +#endif + + for (auto & [target, links] : unchecked) { + if (!isInStore(opts.storeDir, target)) + continue; + if (censor) + roots[target].insert(censored); + else + roots[target].insert(links.begin(), links.end()); + } +} + +void findRoots(const TracerConfig & opts, const Path & path, std::filesystem::file_type type, UncheckedRoots & roots) +{ + auto storePathRegex = makeStorePathRegex(opts.storeDir); + + auto foundRoot = [&](const Path & path, const Path & target) { + boost::smatch match; + if (boost::regex_match(target, match, storePathRegex)) + roots[target].emplace(path); + }; + + try { + + if (type == std::filesystem::file_type::unknown) + type = std::filesystem::symlink_status(path).type(); + + if (type == std::filesystem::file_type::directory) { + for (auto & i : DirectoryIterator{path}) { + checkInterrupt(); + findRoots(opts, i.path().string(), i.symlink_status().type(), roots); + } + } + + else if (type == std::filesystem::file_type::symlink) { + Path target = readLink(path); + if (isInStore(opts.storeDir, target)) + foundRoot(path, target); + + /* Handle indirect roots. */ + else { + target = absPath(target, dirOf(path)); + if (!pathExists(target)) { + if (isInDir(path, opts.stateDir / "gcroots" / "auto")) { + printInfo("removing stale link from '%1%' to '%2%'", path, target); + unlink(path.c_str()); + } + } else { + if (!std::filesystem::is_symlink(target)) + return; + Path target2 = readLink(target); + if (isInStore(opts.storeDir, target2)) + foundRoot(target, target2); + } + } + } + + else if (type == std::filesystem::file_type::regular) { + auto storePath = std::string(opts.storeDir / std::string(baseNameOf(path))); + if (isStorePath(storePathRegex, storePath)) + roots[storePath].emplace(path); + } + + } + + catch (std::filesystem::filesystem_error & e) { + /* We only ignore permanent failures. */ + if (e.code() == std::errc::permission_denied || e.code() == std::errc::no_such_file_or_directory + || e.code() == std::errc::not_a_directory) + printInfo("cannot read potential root '%1%'", path); + else + throw; + } + + catch (SystemError & e) { + /* We only ignore permanent failures. */ + if (e.is(std::errc::permission_denied) || e.is(std::errc::no_such_file_or_directory) + || e.is(std::errc::not_a_directory)) + printInfo("cannot read potential root '%1%'", path); + else + throw; + } +} + +} // namespace nix::roots_tracer diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 669977f52304..4239c178a824 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -1,3 +1,4 @@ +#include "nix/roots/roots.hh" #include "nix/store/derivations.hh" #include "nix/store/globals.hh" #include "nix/store/local-store.hh" @@ -215,235 +216,36 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) } } -void LocalStore::findRoots(const Path & path, std::filesystem::file_type type, Roots & roots) +void LocalStore::findRootsNoTemp(Roots & roots, bool censor) { - auto foundRoot = [&](const Path & path, const Path & target) { - try { - auto storePath = toStorePath(target).first; - if (isValidPath(storePath)) - roots[std::move(storePath)].emplace(path); - else - printInfo("skipping invalid root from '%1%' to '%2%'", path, target); - } catch (BadStorePath &) { - } - }; - - try { + const roots_tracer::TracerConfig opts{ + .storeDir = std::filesystem::path(storeDir), .stateDir = std::filesystem::path(config->stateDir.get())}; - if (type == std::filesystem::file_type::unknown) - type = std::filesystem::symlink_status(path).type(); - - if (type == std::filesystem::file_type::directory) { - for (auto & i : DirectoryIterator{path}) { - checkInterrupt(); - findRoots(i.path().string(), i.symlink_status().type(), roots); - } - } - - else if (type == std::filesystem::file_type::symlink) { - Path target = readLink(path); - if (isInStore(target)) - foundRoot(path, target); - - /* Handle indirect roots. */ - else { - target = absPath(target, dirOf(path)); - if (!pathExists(target)) { - if (isInDir(path, std::filesystem::path{config->stateDir.get()} / gcRootsDir / "auto")) { - printInfo("removing stale link from '%1%' to '%2%'", path, target); - unlink(path.c_str()); - } - } else { - if (!std::filesystem::is_symlink(target)) - return; - Path target2 = readLink(target); - if (isInStore(target2)) - foundRoot(target, target2); - } - } - } + roots_tracer::UncheckedRoots profile; + /* Process direct roots in {gcroots,profiles}. */ + roots_tracer::findRoots(opts, config->stateDir + "/" + gcRootsDir, std::filesystem::file_type::unknown, profile); + roots_tracer::findRoots(opts, config->stateDir + "/profiles", std::filesystem::file_type::unknown, profile); - else if (type == std::filesystem::file_type::regular) { - auto storePath = maybeParseStorePath(storeDir + "/" + std::string(baseNameOf(path))); - if (storePath && isValidPath(*storePath)) - roots[std::move(*storePath)].emplace(path); + for (auto & [target, links] : profile) { + if (!isInStore(target)) + continue; + try { + auto path = toStorePath(target).first; + if (!isValidPath(path)) + continue; + debug("got additional root '%1%'", printStorePath(path)); + // No need to censor these roots, profiles are publicly readable + roots[path].insert(links.begin(), links.end()); + } catch (BadStorePath &) { } - - } - - catch (std::filesystem::filesystem_error & e) { - /* We only ignore permanent failures. */ - if (e.code() == std::errc::permission_denied || e.code() == std::errc::no_such_file_or_directory - || e.code() == std::errc::not_a_directory) - printInfo("cannot read potential root '%1%'", path); - else - throw; - } - - catch (SystemError & e) { - /* We only ignore permanent failures. */ - if (e.is(std::errc::permission_denied) || e.is(std::errc::no_such_file_or_directory) - || e.is(std::errc::not_a_directory)) - printInfo("cannot read potential root '%1%'", path); - else - throw; } -} - -void LocalStore::findRootsNoTemp(Roots & roots, bool censor) -{ - /* Process direct roots in {gcroots,profiles}. */ - findRoots(config->stateDir + "/" + gcRootsDir, std::filesystem::file_type::unknown, roots); - findRoots(config->stateDir + "/profiles", std::filesystem::file_type::unknown, roots); /* Add additional roots returned by different platforms-specific heuristics. This is typically used to add running programs to the set of roots (to prevent them from being garbage collected). */ - findRuntimeRoots(roots, censor); -} - -Roots LocalStore::findRoots(bool censor) -{ - Roots roots; - findRootsNoTemp(roots, censor); - - findTempRoots(roots, censor); - - return roots; -} - -/** - * Key is a mere string because cannot has path with macOS's libc++ - */ -typedef boost::unordered_flat_map< - std::string, - boost::unordered_flat_set>, - StringViewHash, - std::equal_to<>> - UncheckedRoots; - -static void readProcLink(const std::filesystem::path & file, UncheckedRoots & roots) -{ - std::filesystem::path buf; - try { - buf = std::filesystem::read_symlink(file); - } catch (std::filesystem::filesystem_error & e) { - if (e.code() == std::errc::no_such_file_or_directory || e.code() == std::errc::permission_denied - || e.code() == std::errc::no_such_process) - return; - throw; - } - if (buf.is_absolute()) - roots[buf.string()].emplace(file.string()); -} - -static std::string quoteRegexChars(const std::string & raw) -{ - static auto specialRegex = boost::regex(R"([.^$\\*+?()\[\]{}|])"); - return boost::regex_replace(raw, specialRegex, R"(\$&)"); -} - -#ifdef __linux__ -static void readFileRoots(const std::filesystem::path & path, UncheckedRoots & roots) -{ - try { - roots[readFile(path)].emplace(path.string()); - } catch (SystemError & e) { - if (!e.is(std::errc::no_such_file_or_directory) && !e.is(std::errc::permission_denied)) - throw; - } -} -#endif - -void LocalStore::findRuntimeRoots(Roots & roots, bool censor) -{ - UncheckedRoots unchecked; - - auto procDir = AutoCloseDir{opendir("/proc")}; - if (procDir) { - struct dirent * ent; - static const auto digitsRegex = boost::regex(R"(^\d+$)"); - static const auto mapRegex = boost::regex(R"(^\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(/\S+)\s*$)"); - auto storePathRegex = boost::regex(quoteRegexChars(storeDir) + R"(/[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*)"); - while (errno = 0, ent = readdir(procDir.get())) { - checkInterrupt(); - if (boost::regex_match(ent->d_name, digitsRegex)) { - try { - readProcLink(fmt("/proc/%s/exe", ent->d_name), unchecked); - readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked); - - auto fdStr = fmt("/proc/%s/fd", ent->d_name); - auto fdDir = AutoCloseDir(opendir(fdStr.c_str())); - if (!fdDir) { - if (errno == ENOENT || errno == EACCES) - continue; - throw SysError("opening %1%", fdStr); - } - struct dirent * fd_ent; - while (errno = 0, fd_ent = readdir(fdDir.get())) { - if (fd_ent->d_name[0] != '.') - readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked); - } - if (errno) { - if (errno == ESRCH) - continue; - throw SysError("iterating /proc/%1%/fd", ent->d_name); - } - fdDir.reset(); - - std::filesystem::path mapFile = fmt("/proc/%s/maps", ent->d_name); - auto mapLines = tokenizeString>(readFile(mapFile.string()), "\n"); - for (const auto & line : mapLines) { - auto match = boost::smatch{}; - if (boost::regex_match(line, match, mapRegex)) - unchecked[match[1]].emplace(mapFile.string()); - } - - auto envFile = fmt("/proc/%s/environ", ent->d_name); - auto envString = readFile(envFile); - auto env_end = boost::sregex_iterator{}; - for (auto i = boost::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; - i != env_end; - ++i) - unchecked[i->str()].emplace(envFile); - } catch (SystemError & e) { - if (errno == ENOENT || errno == EACCES || errno == ESRCH) - continue; - throw; - } - } - } - if (errno) - throw SysError("iterating /proc"); - } - -#if !defined(__linux__) - // lsof is really slow on OS X. This actually causes the gc-concurrent.sh test to fail. - // See: https://github.com/NixOS/nix/issues/3011 - // Because of this we disable lsof when running the tests. - if (getEnv("_NIX_TEST_NO_LSOF") != "1") { - try { - boost::regex lsofRegex(R"(^n(/.*)$)"); - auto lsofLines = - tokenizeString>(runProgram(LSOF, true, {"-n", "-w", "-F", "n"}), "\n"); - for (const auto & line : lsofLines) { - boost::smatch match; - if (boost::regex_match(line, match, lsofRegex)) - unchecked[match[1].str()].emplace("{lsof}"); - } - } catch (ExecError & e) { - /* lsof not installed, lsof failed */ - } - } -#endif - -#ifdef __linux__ - readFileRoots("/proc/sys/kernel/modprobe", unchecked); - readFileRoots("/proc/sys/kernel/fbsplash", unchecked); - readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked); -#endif - - for (auto & [target, links] : unchecked) { + roots_tracer::UncheckedRoots runtime; + findRuntimeRoots(opts, runtime, censor); + for (auto & [target, links] : runtime) { if (!isInStore(target)) continue; try { @@ -460,6 +262,16 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor) } } +Roots LocalStore::findRoots(bool censor) +{ + Roots roots; + findRootsNoTemp(roots, censor); + + findTempRoots(roots, censor); + + return roots; +} + struct GCLimitReached {}; diff --git a/src/libstore/include/nix/store/local-store.hh b/src/libstore/include/nix/store/local-store.hh index adbf2b26efe1..a9fb55771228 100644 --- a/src/libstore/include/nix/store/local-store.hh +++ b/src/libstore/include/nix/store/local-store.hh @@ -434,12 +434,8 @@ private: PathSet queryValidPathsOld(); ValidPathInfo queryPathInfoOld(const Path & path); - void findRoots(const Path & path, std::filesystem::file_type type, Roots & roots); - void findRootsNoTemp(Roots & roots, bool censor); - void findRuntimeRoots(Roots & roots, bool censor); - std::pair createTempDirInStore(); typedef boost::unordered_flat_set InodeHash; diff --git a/src/libstore/meson.build b/src/libstore/meson.build index c0732d22de0a..9443f71d5c78 100644 --- a/src/libstore/meson.build +++ b/src/libstore/meson.build @@ -35,6 +35,7 @@ configdata_pub.set_quoted( deps_private_maybe_subproject = [] deps_public_maybe_subproject = [ + dependency('nix-roots'), dependency('nix-util'), ] subdir('nix-meson-build-support/subprojects') @@ -263,14 +264,6 @@ if host_machine.system() != 'windows' endif configdata_priv.set_quoted('NIX_MAN_DIR', mandir) -lsof = find_program('lsof', required : false) -configdata_priv.set_quoted( - 'LSOF', - lsof.found() ? lsof.full_path() - # Just look up on the PATH -: 'lsof', -) - config_priv_h = configure_file( configuration : configdata_priv, output : 'store-config-private.hh', diff --git a/src/libstore/package.nix b/src/libstore/package.nix index 968c4e3eb91d..02262757d067 100644 --- a/src/libstore/package.nix +++ b/src/libstore/package.nix @@ -6,6 +6,7 @@ unixtools, darwin, + nix-roots, nix-util, boost, curl, @@ -68,6 +69,7 @@ mkMesonLibrary (finalAttrs: { ++ lib.optional withAWS aws-crt-cpp; propagatedBuildInputs = [ + nix-roots nix-util nlohmann_json ];