forked from lix-project/lix
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
|
@ -314,6 +314,10 @@ nlohmann_json = dependency('nlohmann_json', required : true)
|
||||||
# *absolutely* are not going to make it work)
|
# *absolutely* are not going to make it work)
|
||||||
lix_doc = declare_dependency(link_args : [ '-llix_doc' ])
|
lix_doc = declare_dependency(link_args : [ '-llix_doc' ])
|
||||||
|
|
||||||
|
if is_freebsd
|
||||||
|
libprocstat = declare_dependency(link_args : [ '-lprocstat' ])
|
||||||
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
# Build-time tools
|
# Build-time tools
|
||||||
#
|
#
|
||||||
|
|
|
@ -167,6 +167,9 @@ if host_machine.system() == 'linux'
|
||||||
elif host_machine.system() == 'darwin'
|
elif host_machine.system() == 'darwin'
|
||||||
libstore_sources += files('platform/darwin.cc')
|
libstore_sources += files('platform/darwin.cc')
|
||||||
libstore_headers += files('platform/darwin.hh')
|
libstore_headers += files('platform/darwin.hh')
|
||||||
|
elif host_machine.system() == 'freebsd'
|
||||||
|
libstore_sources += files('platform/freebsd.cc')
|
||||||
|
libstore_headers += files('platform/freebsd.hh')
|
||||||
else
|
else
|
||||||
libstore_sources += files('platform/fallback.cc')
|
libstore_sources += files('platform/fallback.cc')
|
||||||
libstore_headers += files('platform/fallback.hh')
|
libstore_headers += files('platform/fallback.hh')
|
||||||
|
@ -202,23 +205,29 @@ foreach name, value : cpp_str_defines
|
||||||
]
|
]
|
||||||
endforeach
|
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(
|
libstore = library(
|
||||||
'lixstore',
|
'lixstore',
|
||||||
libstore_generated_headers,
|
libstore_generated_headers,
|
||||||
libstore_sources,
|
libstore_sources,
|
||||||
dependencies : [
|
dependencies : dependencies,
|
||||||
libarchive,
|
|
||||||
liblixutil, # Internal.
|
|
||||||
seccomp,
|
|
||||||
sqlite,
|
|
||||||
sodium,
|
|
||||||
curl,
|
|
||||||
openssl,
|
|
||||||
aws_sdk,
|
|
||||||
aws_s3,
|
|
||||||
aws_sdk_transfer,
|
|
||||||
nlohmann_json,
|
|
||||||
],
|
|
||||||
cpp_args : cpp_args,
|
cpp_args : cpp_args,
|
||||||
cpp_pch : cpp_pch,
|
cpp_pch : cpp_pch,
|
||||||
install : true,
|
install : true,
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "platform/linux.hh"
|
#include "platform/linux.hh"
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
#include "platform/darwin.hh"
|
#include "platform/darwin.hh"
|
||||||
|
#elif __FreeBSD__
|
||||||
|
#include "platform/freebsd.hh"
|
||||||
#else
|
#else
|
||||||
#include "platform/fallback.hh"
|
#include "platform/fallback.hh"
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,6 +18,8 @@ std::shared_ptr<LocalStore> LocalStore::makeLocalStore(const Params & params)
|
||||||
return std::shared_ptr<LocalStore>(new LinuxLocalStore(params));
|
return std::shared_ptr<LocalStore>(new LinuxLocalStore(params));
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
return std::shared_ptr<LocalStore>(new DarwinLocalStore(params));
|
return std::shared_ptr<LocalStore>(new DarwinLocalStore(params));
|
||||||
|
#elif __FreeBSD__
|
||||||
|
return std::shared_ptr<LocalStore>(new FreeBSDLocalStore(params));
|
||||||
#else
|
#else
|
||||||
return std::shared_ptr<LocalStore>(new FallbackLocalStore(params));
|
return std::shared_ptr<LocalStore>(new FallbackLocalStore(params));
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +36,8 @@ std::shared_ptr<LocalDerivationGoal> LocalDerivationGoal::makeLocalDerivationGoa
|
||||||
return std::make_shared<LinuxLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
return std::make_shared<LinuxLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
return std::make_shared<DarwinLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
return std::make_shared<DarwinLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||||
|
#elif __FreeBSD__
|
||||||
|
return std::make_shared<FreeBSDLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||||
#else
|
#else
|
||||||
return std::make_shared<FallbackLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
return std::make_shared<FallbackLocalDerivationGoal>(drvPath, wantedOutputs, worker, buildMode);
|
||||||
#endif
|
#endif
|
||||||
|
@ -53,6 +59,10 @@ std::shared_ptr<LocalDerivationGoal> LocalDerivationGoal::makeLocalDerivationGoa
|
||||||
return std::make_shared<DarwinLocalDerivationGoal>(
|
return std::make_shared<DarwinLocalDerivationGoal>(
|
||||||
drvPath, drv, wantedOutputs, worker, buildMode
|
drvPath, drv, wantedOutputs, worker, buildMode
|
||||||
);
|
);
|
||||||
|
#elif __FreeBSD__
|
||||||
|
return std::make_shared<FreeBSDLocalDerivationGoal>(
|
||||||
|
drvPath, drv, wantedOutputs, worker, buildMode
|
||||||
|
);
|
||||||
#else
|
#else
|
||||||
return std::make_shared<FallbackLocalDerivationGoal>(
|
return std::make_shared<FallbackLocalDerivationGoal>(
|
||||||
drvPath, drv, wantedOutputs, worker, buildMode
|
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