aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtemis Tosini <me@artem.ist>2024-07-20 03:18:39 +0000
committerArtemis Tosini <me@artem.ist>2024-07-23 17:49:33 +0000
commit53f3e39815c3357c6465963359e94a6318b54af7 (patch)
tree3a251fe37ec302e404f50a0fd6bbe6daa0b90646
parent73c013a5df09a9edf7a6d2fa0be8349d89f856cd (diff)
libstore: Add FreeBSD findPlatformRoots
Use libprocstat to find garbage collector roots on FreeBSD. Tested working on a FreeBSD machine, although there is no CI yet Change-Id: Id36bac8c3de6cc4de94e2d76e9663dd4b76068a9
-rw-r--r--meson.build4
-rw-r--r--src/libstore/meson.build35
-rw-r--r--src/libstore/platform.cc10
-rw-r--r--src/libstore/platform/freebsd.cc142
-rw-r--r--src/libstore/platform/freebsd.hh47
5 files changed, 225 insertions, 13 deletions
diff --git a/meson.build b/meson.build
index 0e74520ca..56f447501 100644
--- a/meson.build
+++ b/meson.build
@@ -314,6 +314,10 @@ nlohmann_json = dependency('nlohmann_json', required : true)
# *absolutely* are not going to make it work)
lix_doc = declare_dependency(link_args : [ '-llix_doc' ])
+if is_freebsd
+ libprocstat = declare_dependency(link_args : [ '-lprocstat' ])
+endif
+
#
# Build-time tools
#
diff --git a/src/libstore/meson.build b/src/libstore/meson.build
index fa363bd19..5416bd2b5 100644
--- a/src/libstore/meson.build
+++ b/src/libstore/meson.build
@@ -167,6 +167,9 @@ if host_machine.system() == 'linux'
elif host_machine.system() == 'darwin'
libstore_sources += files('platform/darwin.cc')
libstore_headers += files('platform/darwin.hh')
+elif host_machine.system() == 'freebsd'
+ libstore_sources += files('platform/freebsd.cc')
+ libstore_headers += files('platform/freebsd.hh')
else
libstore_sources += files('platform/fallback.cc')
libstore_headers += files('platform/fallback.hh')
@@ -202,23 +205,29 @@ foreach name, value : cpp_str_defines
]
endforeach
+dependencies = [
+ libarchive,
+ liblixutil, # Internal.
+ seccomp,
+ sqlite,
+ sodium,
+ curl,
+ openssl,
+ aws_sdk,
+ aws_s3,
+ aws_sdk_transfer,
+ nlohmann_json,
+]
+
+if host_machine.system() == 'freebsd'
+ dependencies += [ libprocstat ]
+endif
+
libstore = library(
'lixstore',
libstore_generated_headers,
libstore_sources,
- dependencies : [
- libarchive,
- liblixutil, # Internal.
- seccomp,
- sqlite,
- sodium,
- curl,
- openssl,
- aws_sdk,
- aws_s3,
- aws_sdk_transfer,
- nlohmann_json,
- ],
+ dependencies : dependencies,
cpp_args : cpp_args,
cpp_pch : cpp_pch,
install : true,
diff --git a/src/libstore/platform.cc b/src/libstore/platform.cc
index d10d33f0e..72757e39b 100644
--- a/src/libstore/platform.cc
+++ b/src/libstore/platform.cc
@@ -5,6 +5,8 @@
#include "platform/linux.hh"
#elif __APPLE__
#include "platform/darwin.hh"
+#elif __FreeBSD__
+#include "platform/freebsd.hh"
#else
#include "platform/fallback.hh"
#endif
@@ -16,6 +18,8 @@ std::shared_ptr<LocalStore> LocalStore::makeLocalStore(const Params & params)
return std::shared_ptr<LocalStore>(new LinuxLocalStore(params));
#elif __APPLE__
return std::shared_ptr<LocalStore>(new DarwinLocalStore(params));
+#elif __FreeBSD__
+ return std::shared_ptr<LocalStore>(new FreeBSDLocalStore(params));
#else
return std::shared_ptr<LocalStore>(new FallbackLocalStore(params));
#endif
@@ -32,6 +36,8 @@ std::shared_ptr<LocalDerivationGoal> LocalDerivationGoal::makeLocalDerivationGoa
return std::make_shared<LinuxLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
#elif __APPLE__
return std::make_shared<DarwinLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
+#elif __FreeBSD__
+ return std::make_shared<FreeBSDLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
#else
return std::make_shared<FallbackLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
#endif
@@ -53,6 +59,10 @@ std::shared_ptr<LocalDerivationGoal> LocalDerivationGoal::makeLocalDerivationGoa
return std::make_shared<DarwinLocalDerivationGoal>(
drvPath, drv, wantedOutputs, worker, buildMode
);
+#elif __FreeBSD__
+ return std::make_shared<FreeBSDLocalDerivationGoal>(
+ drvPath, drv, wantedOutputs, worker, buildMode
+ );
#else
return std::make_shared<FallbackLocalDerivationGoal>(
drvPath, drv, wantedOutputs, worker, buildMode
diff --git a/src/libstore/platform/freebsd.cc b/src/libstore/platform/freebsd.cc
new file mode 100644
index 000000000..bdba1abf5
--- /dev/null
+++ b/src/libstore/platform/freebsd.cc
@@ -0,0 +1,142 @@
+#include "platform/freebsd.hh"
+#include "regex.hh"
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <libprocstat.h>
+
+namespace nix {
+
+static void readSysctlRoots(const char * name, UncheckedRoots & unchecked)
+{
+ size_t len = 0;
+ std::string value;
+ if (int err = sysctlbyname(name, nullptr, &len, nullptr, 0) < 0) {
+ if (err == ENOENT || err == EACCES) {
+ return;
+ } else {
+ throw SysError(err, "sysctlbyname %1%", name);
+ }
+ }
+
+ value.resize(len, ' ');
+ if (int err = sysctlbyname(name, value.data(), &len, nullptr, 0) < 0) {
+ if (err == ENOENT || err == EACCES) {
+ return;
+ } else {
+ throw SysError(err, "sysctlbyname %1%", name);
+ }
+ }
+
+ for (auto & path : tokenizeString<Strings>(value, ";")) {
+ unchecked[path].emplace(fmt("{{sysctl:%1%}}", name));
+ }
+}
+
+struct ProcstatDeleter
+{
+ void operator()(struct procstat * ps)
+ {
+ procstat_close(ps);
+ }
+};
+
+template<auto del>
+struct ProcstatReferredDeleter
+{
+ struct procstat * ps;
+
+ ProcstatReferredDeleter(struct procstat * ps) : ps(ps) {}
+
+ template<typename T>
+ void operator()(T * p)
+ {
+ del(ps, p);
+ }
+};
+
+void FreeBSDLocalStore::findPlatformRoots(UncheckedRoots & unchecked)
+{
+ readSysctlRoots("kern.module_path", unchecked);
+
+ auto storePathRegex = regex::storePathRegex(storeDir);
+
+ auto ps = std::unique_ptr<struct procstat, ProcstatDeleter>(procstat_open_sysctl());
+ if (!ps) {
+ throw SysError("procstat_open_sysctl");
+ }
+
+ auto procs = std::unique_ptr<struct kinfo_proc[], ProcstatReferredDeleter<procstat_freeprocs>>(
+ nullptr, ps.get()
+ );
+ auto files = std::unique_ptr<struct filestat_list, ProcstatReferredDeleter<procstat_freefiles>>(
+ nullptr, ps.get()
+ );
+
+ unsigned int numprocs = 0;
+ procs.reset(procstat_getprocs(ps.get(), KERN_PROC_PROC, 0, &numprocs));
+ if (!procs || numprocs == 0) {
+ throw SysError("procstat_getprocs");
+ };
+
+ for (unsigned int procidx = 0; procidx < numprocs; procidx++) {
+ // Includes file descriptors, executable, cwd,
+ // and mmapped files (including dynamic libraries)
+ files.reset(procstat_getfiles(ps.get(), &procs[procidx], 1));
+ // We only have permission if we're root so just skip it if we fail
+ if (!files) {
+ continue;
+ }
+
+ for (struct filestat * file = files->stqh_first; file; file = file->next.stqe_next) {
+ if (!file->fs_path) {
+ continue;
+ }
+
+ std::string role;
+ if (file->fs_uflags & PS_FST_UFLAG_CTTY) {
+ role = "ctty";
+ } else if (file->fs_uflags & PS_FST_UFLAG_CDIR) {
+ role = "cwd";
+ } else if (file->fs_uflags & PS_FST_UFLAG_JAIL) {
+ role = "jail";
+ } else if (file->fs_uflags & PS_FST_UFLAG_RDIR) {
+ role = "root";
+ } else if (file->fs_uflags & PS_FST_UFLAG_TEXT) {
+ role = "text";
+ } else if (file->fs_uflags & PS_FST_UFLAG_TRACE) {
+ role = "trace";
+ } else if (file->fs_uflags & PS_FST_UFLAG_MMAP) {
+ role = "mmap";
+ } else {
+ role = fmt("fd/%1%", file->fs_fd);
+ }
+
+ unchecked[file->fs_path].emplace(fmt("{procstat:%1%/%2%}", procs[procidx].ki_pid, role)
+ );
+ }
+
+ auto env_name = fmt("{procstat:%1%/env}", procs[procidx].ki_pid);
+ // No need to free, the buffer is reused on next call and deallocated in procstat_close
+ char ** env = procstat_getenvv(ps.get(), &procs[procidx], 0);
+ if (env == nullptr) {
+ continue;
+ }
+
+ for (size_t i = 0; env[i]; i++) {
+ auto envString = std::string(env[i]);
+
+ auto envEnd = std::sregex_iterator{};
+ for (auto match =
+ std::sregex_iterator{envString.begin(), envString.end(), storePathRegex};
+ match != envEnd;
+ match++)
+ {
+ unchecked[match->str()].emplace(env_name);
+ }
+ }
+ }
+}
+}
diff --git a/src/libstore/platform/freebsd.hh b/src/libstore/platform/freebsd.hh
new file mode 100644
index 000000000..99aff3c10
--- /dev/null
+++ b/src/libstore/platform/freebsd.hh
@@ -0,0 +1,47 @@
+#pragma once
+///@file
+
+#include "build/local-derivation-goal.hh"
+#include "gc-store.hh"
+#include "local-store.hh"
+
+namespace nix {
+
+/**
+ * FreeBSD-specific implementation of LocalStore
+ */
+class FreeBSDLocalStore : public LocalStore
+{
+public:
+ FreeBSDLocalStore(const Params & params)
+ : StoreConfig(params)
+ , LocalFSStoreConfig(params)
+ , LocalStoreConfig(params)
+ , Store(params)
+ , LocalFSStore(params)
+ , LocalStore(params)
+ {
+ }
+ FreeBSDLocalStore(const std::string scheme, std::string path, const Params & params)
+ : FreeBSDLocalStore(params)
+ {
+ throw UnimplementedError("FreeBSDLocalStore");
+ }
+
+private:
+
+ void findPlatformRoots(UncheckedRoots & unchecked) override;
+};
+
+/**
+ * FreeBSD-specific implementation of LocalDerivationGoal
+ */
+class FreeBSDLocalDerivationGoal : public LocalDerivationGoal
+{
+public:
+ using LocalDerivationGoal::LocalDerivationGoal;
+
+private:
+};
+
+}