Compare commits

...

17 commits

Author SHA1 Message Date
Artemis Tosini 60a48311e8 Merge "libutil: Support getSelfExe on FreeBSD" into main 2024-07-25 23:10:30 +00:00
jade c4c7cb7613 Merge changes Ic0dfcfe2,Ibe73851f,Ia7a8df1c,I400b2031 into main
* changes:
  package.nix: remove dead code
  diff-closures: remove gratuitous copy
  tree-wide: NULL -> nullptr
  libutil: rip out GNU Hurd support code
2024-07-25 18:05:41 +00:00
Qyriad 8d12e0fbb7 fix building with Musl, fixing static builds
Musl stdout macro expands¹ to something that isn't a valid identifier,
so we get syntax errors when compiling usage of a method called stdout
with Musl's stdio.h.

[1]: https://git.musl-libc.org/cgit/musl/tree/include/stdio.h?id=ab31e9d6a0fa7c5c408856c89df2dfb12c344039#n67

Change-Id: I10e6f6a49504399bf8edd59c5d9e4e62449469e8
2024-07-24 17:21:40 +00:00
Artemis Tosini 3b96b51cf4
libutil: Support getSelfExe on FreeBSD
getSelfExe is used in a few places re-execute nix.
Current code in this file uses ifdefs to support several
platforms, just keep doing that

Change-Id: Iecc2ada0101aea0c30524e3a1218594f919d74bf
2024-07-24 01:28:03 +00:00
jade 98e8cf9c63 package.nix: remove dead code
Change-Id: Ic0dfcfe27dbf13da4f7f74f5fab8ce6fa718d28f
2024-07-23 21:53:43 +02:00
jade 12a5838d11 diff-closures: remove gratuitous copy
This was done originally because std::smatch does not accept `const char
*` as iterators. However, this was because we should have been using
std::cmatch instead.

Change-Id: Ibe73851fd39755e883df2d33d22fed72ac0a04ae
2024-07-23 21:45:30 +02:00
jade 2436f2110a tree-wide: NULL -> nullptr
This is slightly more type safe and is more in line with modern C++.

Change-Id: Ia7a8df1c7788085020d1bdc941d6f9cee356144e
2024-07-23 21:06:55 +02:00
jade 916b5c68fb libutil: rip out GNU Hurd support code
Nobody has stepped up to add further support for Hurd since this code
appeared in 2010 or 2014. We don't need it.

Change-Id: I400b2031a225551ea3c71a3ef3ea9fdb599dfba3
2024-07-23 20:52:04 +02:00
Artemis Tosini 53f3e39815
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
2024-07-23 17:49:33 +00:00
Pierre Bourdon 73c013a5df Merge "libexpr/gc-alloc: fix compilation with !HAVE_BOEHMGC" into main 2024-07-22 23:14:59 +00:00
Pierre Bourdon e76245f8e9
libexpr/gc-alloc: fix compilation with !HAVE_BOEHMGC
Fixes: 72ee25b402
Change-Id: Ib59386af1415a8ed4b53af24ec22a4ffa5e5877d
2024-07-23 00:50:09 +02:00
eldritch horrors 472ff1b833 libstore: keep Goal errors as unique_ptrs
Error is pretty large, and most goals do not fail. this alone more than
halves the size of Goal on x86_64-linux, from 720 bytes down to 344. in
derived classes the difference is not as dramatic, but even the largest
derived class (`LocalDerivationGoal`) loses almost 20% of its footprint

Change-Id: Ifda8f94c81b6566eeb3e52d55d9796ec40c7bce8
2024-07-22 19:01:40 +00:00
eldritch horrors 7bf1aff44a libstore: remove an always-defaulted argument
Change-Id: I3c7f17d5492a16bb54480fa1aa384b96fba72d61
2024-07-22 19:01:40 +00:00
eldritch horrors 58a91d70c9 libstore: use std::async instead of Goal threads
the goals are either already using std::async and merely forgot to
remove std::thread vestiges or they emulate async with threads and
promises. we can simply use async directly everywhere for clarity.

Change-Id: I3f05098310a25984f10fff1e68c573329002b500
2024-07-22 19:01:40 +00:00
eldritch horrors ad36fb43ad libstore: remove addToWeakGoals
under owner_less it's equivalent to insert(), only sometimes a little
bit faster because it does not construct a weak_ptr if the goal is in
the set already. this small difference in performance does not matter
here and c++23 will make insert transparent anyway, so we can drop it

Change-Id: I7cbd7d6e0daa95d67145ec58183162f6c4743b15
2024-07-22 19:01:40 +00:00
eldritch horrors d70e045f90 libstore: remove Goal::ecBusy
this should be an optional. "busy" is not an *exit* code!

Change-Id: Ic231cb27b022312b1a7a7b9602f32845b7a9c934
2024-07-22 19:01:40 +00:00
eldritch horrors 20f53346df libstore: remove unused Worker::waitForAnyGoal
Change-Id: Ia3ebd434b17052b6760ce74d8e20025a72148613
2024-07-22 19:01:40 +00:00
29 changed files with 315 additions and 165 deletions

View file

@ -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
#

View file

@ -92,31 +92,19 @@ let
# Reimplementation of Nixpkgs' Meson cross file, with some additions to make
# it actually work.
mesonCrossFile =
let
cpuFamily =
platform:
with platform;
if isAarch32 then
"arm"
else if isx86_32 then
"x86"
else
platform.uname.processor;
in
builtins.toFile "lix-cross-file.conf" ''
[properties]
# Meson is convinced that if !buildPlatform.canExecute hostPlatform then we cannot
# build anything at all, which is not at all correct. If we can't execute the host
# platform, we'll just disable tests and doc gen.
needs_exe_wrapper = false
mesonCrossFile = builtins.toFile "lix-cross-file.conf" ''
[properties]
# Meson is convinced that if !buildPlatform.canExecute hostPlatform then we cannot
# build anything at all, which is not at all correct. If we can't execute the host
# platform, we'll just disable tests and doc gen.
needs_exe_wrapper = false
[binaries]
# Meson refuses to consider any CMake binary during cross compilation if it's
# not explicitly specified here, in the cross file.
# https://github.com/mesonbuild/meson/blob/0ed78cf6fa6d87c0738f67ae43525e661b50a8a2/mesonbuild/cmake/executor.py#L72
cmake = 'cmake'
'';
[binaries]
# Meson refuses to consider any CMake binary during cross compilation if it's
# not explicitly specified here, in the cross file.
# https://github.com/mesonbuild/meson/blob/0ed78cf6fa6d87c0738f67ae43525e661b50a8a2/mesonbuild/cmake/executor.py#L72
cmake = 'cmake'
'';
# The internal API docs need these for the build, but if we're not building
# Nix itself, then these don't need to be propagated.

View file

@ -236,9 +236,9 @@ static int main_build_remote(int argc, char * * argv)
}
#if __APPLE__
futimes(bestSlotLock.get(), NULL);
futimes(bestSlotLock.get(), nullptr);
#else
futimens(bestSlotLock.get(), NULL);
futimens(bestSlotLock.get(), nullptr);
#endif
lock.reset();

View file

@ -10,6 +10,8 @@
#include <string_view>
#include <vector>
#include "checked-arithmetic.hh"
#if HAVE_BOEHMGC
#include <functional> // std::less
#include <utility> // std::pair
@ -18,8 +20,6 @@
#include <gc/gc_allocator.h>
#include <gc/gc_cpp.h>
#include "checked-arithmetic.hh"
/// calloc, transparently GC-enabled.
#define LIX_GC_CALLOC(size) GC_MALLOC(size)

View file

@ -695,7 +695,7 @@ struct GitInputScheme : InputScheme
});
Finally const _wait([&] { proc.wait(); });
unpackTarfile(*proc.stdout(), tmpDir);
unpackTarfile(*proc.getStdout(), tmpDir);
}
auto storePath = store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, htSHA256, filter);

View file

@ -932,7 +932,7 @@ void runPostBuildHook(
Finally const _wait([&] { proc.wait(); });
// FIXME just process the data, without a wrapper sink class
proc.stdout()->drainInto(sink);
proc.getStdout()->drainInto(sink);
}
void DerivationGoal::buildDone()

View file

@ -4,7 +4,6 @@
#include "store-api.hh"
#include "goal.hh"
#include "realisation.hh"
#include <thread>
#include <future>
namespace nix {
@ -41,11 +40,6 @@ class DrvOutputSubstitutionGoal : public Goal {
*/
std::shared_ptr<Store> sub;
/**
* The substituter thread.
*/
std::thread thr;
std::unique_ptr<MaintainCount<uint64_t>> maintainRunningSubstitutions;
struct DownloadState

View file

@ -22,7 +22,7 @@ void Store::buildPaths(const std::vector<DerivedPath> & reqs, BuildMode buildMod
if (ex)
logError(i->ex->info());
else
ex = std::move(i->ex);
ex = std::move(*i->ex);
}
if (i->exitCode != Goal::ecSuccess) {
if (auto i2 = dynamic_cast<DerivationGoal *>(i.get()))

View file

@ -34,18 +34,10 @@ BuildResult Goal::getBuildResult(const DerivedPath & req) const {
}
void addToWeakGoals(WeakGoals & goals, GoalPtr p)
{
if (goals.find(p) != goals.end())
return;
goals.insert(p);
}
void Goal::addWaitee(GoalPtr waitee)
{
waitees.insert(waitee);
addToWeakGoals(waitee->waiters, shared_from_this());
waitee->waiters.insert(shared_from_this());
}
@ -79,15 +71,14 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
void Goal::amDone(ExitCode result, std::optional<Error> ex)
{
trace("done");
assert(exitCode == ecBusy);
assert(result == ecSuccess || result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure);
assert(!exitCode.has_value());
exitCode = result;
if (ex) {
if (!waiters.empty())
logError(ex->info());
else
this->ex = std::move(*ex);
this->ex = std::make_unique<Error>(std::move(*ex));
}
for (auto & i : waiters) {

View file

@ -53,7 +53,7 @@ enum struct JobCategory {
struct Goal : public std::enable_shared_from_this<Goal>
{
typedef enum {ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
typedef enum {ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode;
/**
* Backlink to the worker.
@ -96,7 +96,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
/**
* Whether the goal is finished.
*/
ExitCode exitCode = ecBusy;
std::optional<ExitCode> exitCode;
protected:
/**
@ -121,7 +121,7 @@ public:
/**
* Exception containing an error message, if any.
*/
std::optional<Error> ex;
std::unique_ptr<Error> ex;
Goal(Worker & worker, DerivedPath path)
: worker(worker)
@ -175,6 +175,4 @@ public:
virtual JobCategory jobCategory() const = 0;
};
void addToWeakGoals(WeakGoals & goals, GoalPtr p);
}

View file

@ -1882,7 +1882,7 @@ void LocalDerivationGoal::runChild()
sandboxArgs.push_back("_ALLOW_LOCAL_NETWORKING");
sandboxArgs.push_back("1");
}
if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), NULL)) {
if (sandbox_init_with_parameters(sandboxProfile.c_str(), 0, stringsToCharPtrs(sandboxArgs).data(), nullptr)) {
writeFull(STDERR_FILENO, "failed to configure sandbox\n");
_exit(1);
}

View file

@ -214,9 +214,7 @@ void PathSubstitutionGoal::tryToRun()
outPipe.create();
promise = std::promise<void>();
thr = std::thread([this]() {
thr = std::async(std::launch::async, [this]() {
auto & fetchPath = subPath ? *subPath : storePath;
try {
ReceiveInterrupts receiveInterrupts;
@ -230,16 +228,12 @@ void PathSubstitutionGoal::tryToRun()
copyStorePath(
*sub, worker.store, fetchPath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs
);
promise.set_value();
} catch (const EndOfFile &) {
promise.set_exception(std::make_exception_ptr(EndOfFile(
throw EndOfFile(
"NAR for '%s' fetched from '%s' is incomplete",
sub->printStorePath(fetchPath),
sub->getUri()
)));
} catch (...) {
promise.set_exception(std::current_exception());
);
}
});
@ -253,11 +247,10 @@ void PathSubstitutionGoal::finished()
{
trace("substitute finished");
thr.join();
worker.childTerminated(this);
try {
promise.get_future().get();
thr.get();
} catch (std::exception & e) {
printError(e.what());
@ -316,9 +309,9 @@ void PathSubstitutionGoal::handleEOF(int fd)
void PathSubstitutionGoal::cleanup()
{
try {
if (thr.joinable()) {
if (thr.valid()) {
// FIXME: signal worker thread to quit.
thr.join();
thr.get();
worker.childTerminated(this);
}

View file

@ -50,9 +50,7 @@ struct PathSubstitutionGoal : public Goal
/**
* The substituter thread.
*/
std::thread thr;
std::promise<void> promise;
std::future<void> thr;
/**
* Whether to try to repair a valid path.

View file

@ -157,21 +157,13 @@ void Worker::removeGoal(GoalPtr goal)
if (goal->exitCode == Goal::ecFailed && !settings.keepGoing)
topGoals.clear();
}
/* Wake up goals waiting for any goal to finish. */
for (auto & i : waitingForAnyGoal) {
GoalPtr goal = i.lock();
if (goal) wakeUp(goal);
}
waitingForAnyGoal.clear();
}
void Worker::wakeUp(GoalPtr goal)
{
goal->trace("woken up");
addToWeakGoals(awake, goal);
awake.insert(goal);
}
@ -213,7 +205,7 @@ void Worker::childStarted(GoalPtr goal, const std::set<int> & fds,
}
void Worker::childTerminated(Goal * goal, bool wakeSleepers)
void Worker::childTerminated(Goal * goal)
{
auto i = std::find_if(children.begin(), children.end(),
[&](const Child & child) { return child.goal2 == goal; });
@ -236,16 +228,13 @@ void Worker::childTerminated(Goal * goal, bool wakeSleepers)
children.erase(i);
if (wakeSleepers) {
/* Wake up goals waiting for a build slot. */
for (auto & j : wantingToBuild) {
GoalPtr goal = j.lock();
if (goal) wakeUp(goal);
}
wantingToBuild.clear();
/* Wake up goals waiting for a build slot. */
for (auto & j : wantingToBuild) {
GoalPtr goal = j.lock();
if (goal) wakeUp(goal);
}
wantingToBuild.clear();
}
@ -257,21 +246,14 @@ void Worker::waitForBuildSlot(GoalPtr goal)
(isSubstitutionGoal && getNrSubstitutions() < settings.maxSubstitutionJobs))
wakeUp(goal); /* we can do it right away */
else
addToWeakGoals(wantingToBuild, goal);
}
void Worker::waitForAnyGoal(GoalPtr goal)
{
debug("wait for any goal");
addToWeakGoals(waitingForAnyGoal, goal);
wantingToBuild.insert(goal);
}
void Worker::waitForAWhile(GoalPtr goal)
{
debug("wait for a while");
addToWeakGoals(waitingForAWhile, goal);
waitingForAWhile.insert(goal);
}
@ -429,7 +411,7 @@ void Worker::waitForInput()
GoalPtr goal = j->goal.lock();
assert(goal);
if (goal->exitCode == Goal::ecBusy &&
if (!goal->exitCode.has_value() &&
0 != settings.maxSilentTime &&
j->respectTimeouts &&
after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime))
@ -440,7 +422,7 @@ void Worker::waitForInput()
continue;
}
else if (goal->exitCode == Goal::ecBusy &&
else if (!goal->exitCode.has_value() &&
0 != settings.buildTimeout &&
j->respectTimeouts &&
after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout))

View file

@ -90,11 +90,6 @@ private:
std::map<StorePath, std::weak_ptr<PathSubstitutionGoal>> substitutionGoals;
std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
/**
* Goals waiting for busy paths to be unlocked.
*/
WeakGoals waitingForAnyGoal;
/**
* Goals sleeping for a few seconds (polling a lock).
*/
@ -228,12 +223,9 @@ public:
bool inBuildSlot, bool respectTimeouts);
/**
* Unregisters a running child process. `wakeSleepers` should be
* false if there is no sense in waking up goals that are sleeping
* because they can't run yet (e.g., there is no free build slot,
* or the hook would still say `postpone`).
* Unregisters a running child process.
*/
void childTerminated(Goal * goal, bool wakeSleepers = true);
void childTerminated(Goal * goal);
/**
* Put `goal` to sleep until a build slot becomes available (which
@ -241,12 +233,6 @@ public:
*/
void waitForBuildSlot(GoalPtr goal);
/**
* Wait for any goal to finish. Pretty indiscriminate way to
* wait for some resource that some other goal is holding.
*/
void waitForAnyGoal(GoalPtr goal);
/**
* Wait for a few seconds and then retry this goal. Used when
* waiting for a lock held by another process. This kind of

View file

@ -177,14 +177,14 @@ static bool hasVirt() {
size_t size;
size = sizeof(hasVMM);
if (sysctlbyname("kern.hv_vmm_present", &hasVMM, &size, NULL, 0) == 0) {
if (sysctlbyname("kern.hv_vmm_present", &hasVMM, &size, nullptr, 0) == 0) {
if (hasVMM)
return false;
}
// whether the kernel and hardware supports virt
size = sizeof(hvSupport);
if (sysctlbyname("kern.hv_support", &hvSupport, &size, NULL, 0) == 0) {
if (sysctlbyname("kern.hv_support", &hvSupport, &size, nullptr, 0) == 0) {
return hvSupport == 1;
} else {
return false;

View file

@ -557,7 +557,7 @@ void LocalStore::openDB(State & state, bool create)
if (sqlite3_exec(db, "pragma main.journal_size_limit = 1099511627776;", 0, 0, 0) != SQLITE_OK)
SQLiteError::throw_(db, "setting journal_size_limit");
int enable = 1;
if (sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, &enable) != SQLITE_OK)
if (sqlite3_file_control(db, nullptr, SQLITE_FCNTL_PERSIST_WAL, &enable) != SQLITE_OK)
SQLiteError::throw_(db, "setting persistent WAL mode");
}

View file

@ -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,

View file

@ -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

View file

@ -235,15 +235,15 @@ void DarwinLocalDerivationGoal::execBuilder(std::string builder, Strings args, S
if (drv->platform == "aarch64-darwin") {
// Unset kern.curproc_arch_affinity so we can escape Rosetta
int affinity = 0;
sysctlbyname("kern.curproc_arch_affinity", NULL, NULL, &affinity, sizeof(affinity));
sysctlbyname("kern.curproc_arch_affinity", nullptr, nullptr, &affinity, sizeof(affinity));
cpu_type_t cpu = CPU_TYPE_ARM64;
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL);
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, nullptr);
} else if (drv->platform == "x86_64-darwin") {
cpu_type_t cpu = CPU_TYPE_X86_64;
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL);
posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, nullptr);
}
posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
posix_spawn(nullptr, builder.c_str(), nullptr, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
}
}

View 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);
}
}
}
}
}

View 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:
};
}

View file

@ -15,6 +15,11 @@
# include <sys/resource.h>
#endif
#if __FreeBSD__
# include <sys/param.h>
# include <sys/sysctl.h>
#endif
#include <sys/mount.h>
#include <cgroup.hh>
@ -102,6 +107,24 @@ std::optional<Path> getSelfExe()
return buf;
else
return std::nullopt;
#elif __FreeBSD__
int sysctlName[] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PATHNAME,
-1,
};
size_t pathLen = 0;
if (sysctl(sysctlName, sizeof(sysctlName) / sizeof(sysctlName[0]), nullptr, &pathLen, nullptr, 0) < 0) {
return std::nullopt;
}
std::vector<char> path(pathLen);
if (sysctl(sysctlName, sizeof(sysctlName) / sizeof(sysctlName[0]), path.data(), &pathLen, nullptr, 0) < 0) {
return std::nullopt;
}
return Path(path.begin(), path.end());
#else
return std::nullopt;
#endif

View file

@ -21,22 +21,14 @@ Path absPath(Path path, std::optional<PathView> dir, bool resolveSymlinks)
{
if (path.empty() || path[0] != '/') {
if (!dir) {
#ifdef __GNU__
/* GNU (aka. GNU/Hurd) doesn't have any limitation on path
lengths and doesn't define `PATH_MAX'. */
char *buf = getcwd(NULL, 0);
if (buf == NULL)
#else
char buf[PATH_MAX];
if (!getcwd(buf, sizeof(buf)))
#endif
if (!getcwd(buf, sizeof(buf))) {
throw SysError("cannot get cwd");
}
path = concatStrings(buf, "/", path);
#ifdef __GNU__
free(buf);
#endif
} else
} else {
path = concatStrings(*dir, "/", path);
}
}
return canonPath(path, resolveSymlinks);
}

View file

@ -251,7 +251,7 @@ std::pair<int, std::string> runProgram(RunOptions && options)
try {
auto proc = runProgram2(options);
Finally const _wait([&] { proc.wait(); });
stdout = proc.stdout()->drain();
stdout = proc.getStdout()->drain();
} catch (ExecError & e) {
status = e.status;
}

View file

@ -106,7 +106,7 @@ public:
void wait();
Source * stdout() const { return stdoutSource.get(); }
Source * getStdout() const { return stdoutSource.get(); };
};
std::pair<int, std::string> runProgram(RunOptions && options);

View file

@ -54,7 +54,7 @@ TarArchive::TarArchive(Source & source, bool raw) : buffer(65536)
archive_read_support_format_raw(archive);
archive_read_support_format_empty(archive);
}
archive_read_set_option(archive, NULL, "mac-ext", NULL);
archive_read_set_option(archive, nullptr, "mac-ext", nullptr);
check(archive_read_open(archive, (void *)this, callback_open, callback_read, callback_close), "Failed to open archive (%s)");
}
@ -65,7 +65,7 @@ TarArchive::TarArchive(const Path & path)
archive_read_support_filter_all(archive);
archive_read_support_format_all(archive);
archive_read_set_option(archive, NULL, "mac-ext", NULL);
archive_read_set_option(archive, nullptr, "mac-ext", nullptr);
check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s");
}

View file

@ -24,24 +24,17 @@ GroupedPaths getClosureInfo(ref<Store> store, const StorePath & toplevel)
GroupedPaths groupedPaths;
for (auto & path : closure) {
for (auto const & path : closure) {
/* Strip the output name. Unfortunately this is ambiguous (we
can't distinguish between output names like "bin" and
version suffixes like "unstable"). */
static std::regex regex("(.*)-([a-z]+|lib32|lib64)");
std::smatch match;
std::cmatch match;
std::string name{path.name()};
// Used to keep name alive through being potentially overwritten below
// (to not invalidate the references from the regex result)
//
// n.b. cannot be just path.name().{begin,end}() since that returns const
// char *, which does not, for some reason, convert as required on
// libstdc++. Seems like a libstdc++ bug or standard bug to me... we
// can afford the allocation in any case.
const std::string origName{path.name()};
std::string_view const origName = path.name();
std::string outputName;
if (std::regex_match(origName, match, regex)) {
if (std::regex_match(origName.begin(), origName.end(), match, regex)) {
name = match[1];
outputName = match[2];
}

View file

@ -48,7 +48,7 @@ std::set<std::string> runResolver(const Path & filename)
return {};
}
char* obj = (char*) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
char* obj = (char*) mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
if (!obj)
throw SysError("mmapping '%s'", filename);