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
This commit is contained in:
parent
73c013a5df
commit
53f3e39815
5 changed files with 225 additions and 13 deletions
|
@ -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
|
||||
#
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
142
src/libstore/platform/freebsd.cc
Normal file
142
src/libstore/platform/freebsd.cc
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
src/libstore/platform/freebsd.hh
Normal file
47
src/libstore/platform/freebsd.hh
Normal file
|
@ -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:
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue