Skip to content

Commit

Permalink
WIP move settings from Settings to LocalStoreConfig
Browse files Browse the repository at this point in the history
Trying to do #5638 but this is not working very well at all.
  • Loading branch information
Ericson2314 committed Feb 3, 2023
1 parent dbe0748 commit 1c34b9f
Show file tree
Hide file tree
Showing 15 changed files with 428 additions and 327 deletions.
54 changes: 31 additions & 23 deletions src/libstore/build/local-derivation-goal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ namespace nix {
void handleDiffHook(
uid_t uid, uid_t gid,
const Path & tryA, const Path & tryB,
const Path & drvPath, const Path & tmpDir)
const Path & drvPath, const Path & tmpDir,
const LocalStore & store)
{
auto diffHook = settings.diffHook;
if (diffHook != "" && settings.runDiffHook) {
auto diffHook = store.diffHook;
if (diffHook != "" && store.runDiffHook) {
try {
auto diffRes = runProgram(RunOptions {
.program = diffHook,
Expand Down Expand Up @@ -176,10 +177,12 @@ void LocalDerivationGoal::tryLocalBuild() {
return;
}

auto & localStore = getLocalStore();

/* Are we doing a chroot build? */
{
auto noChroot = parsedDrv->getBoolAttr("__noChroot");
if (settings.sandboxMode == smEnabled) {
if (localStore.sandboxMode == smEnabled) {
if (noChroot)
throw Error("derivation '%s' has '__noChroot' set, "
"but that's not allowed when 'sandbox' is 'true'", worker.store.printStorePath(drvPath));
Expand All @@ -190,13 +193,12 @@ void LocalDerivationGoal::tryLocalBuild() {
#endif
useChroot = true;
}
else if (settings.sandboxMode == smDisabled)
else if (localStore.sandboxMode == smDisabled)
useChroot = false;
else if (settings.sandboxMode == smRelaxed)
else if (localStore.sandboxMode == smRelaxed)
useChroot = derivationType.isSandboxed() && !noChroot;
}

auto & localStore = getLocalStore();
if (localStore.storeDir != localStore.realStoreDir.get()) {
#if __linux__
useChroot = true;
Expand Down Expand Up @@ -399,6 +401,8 @@ static void linkOrCopy(const Path & from, const Path & to)

void LocalDerivationGoal::startBuilder()
{
auto & localStore = getLocalStore();

if ((buildUser && buildUser->getUIDCount() != 1)
#if __linux__
|| settings.useCgroups
Expand Down Expand Up @@ -573,7 +577,7 @@ void LocalDerivationGoal::startBuilder()
host file system. */
dirsInChroot.clear();

for (auto i : settings.sandboxPaths.get()) {
for (auto i : localStore.sandboxPaths.get()) {
if (i.empty()) continue;
bool optional = false;
if (i[i.size() - 1] == '?') {
Expand Down Expand Up @@ -604,7 +608,7 @@ void LocalDerivationGoal::startBuilder()
dirsInChroot.insert_or_assign(p, p);
}

PathSet allowedPaths = settings.allowedImpureHostPrefixes;
PathSet allowedPaths = localStore.allowedImpureHostPrefixes;

/* This works like the above, except on a per-derivation level */
auto impurePaths = parsedDrv->getStringsAttr("__impureHostDeps").value_or(Strings());
Expand Down Expand Up @@ -744,17 +748,17 @@ void LocalDerivationGoal::startBuilder()
if (needsHashRewrite() && pathExists(homeDir))
throw Error("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir);

if (useChroot && settings.preBuildHook != "" && dynamic_cast<Derivation *>(drv.get())) {
if (useChroot && localStore.preBuildHook != "" && dynamic_cast<Derivation *>(drv.get())) {
printMsg(lvlChatty, format("executing pre-build hook '%1%'")
% settings.preBuildHook);
% localStore.preBuildHook);
auto args = useChroot ? Strings({worker.store.printStorePath(drvPath), chrootRootDir}) :
Strings({ worker.store.printStorePath(drvPath) });
enum BuildHookState {
stBegin,
stExtraChrootDirs
};
auto state = stBegin;
auto lines = runProgram(settings.preBuildHook, false, args);
auto lines = runProgram(localStore.preBuildHook, false, args);
auto lastPos = std::string::size_type{0};
for (auto nlPos = lines.find('\n'); nlPos != std::string::npos;
nlPos = lines.find('\n', lastPos))
Expand Down Expand Up @@ -956,7 +960,7 @@ void LocalDerivationGoal::startBuilder()
/* Otherwise exit with EPERM so we can handle this in the
parent. This is only done when sandbox-fallback is set
to true (the default). */
if (settings.sandboxFallback)
if (localStore.sandboxFallback)
_exit(1);
/* Mention sandbox-fallback in the error message so the user
knows that having it disabled contributed to the
Expand All @@ -973,7 +977,7 @@ void LocalDerivationGoal::startBuilder()
});

int res = helper.wait();
if (res != 0 && settings.sandboxFallback) {
if (res != 0 && localStore.sandboxFallback) {
useChroot = false;
initTmpDir();
goto fallback;
Expand Down Expand Up @@ -1021,7 +1025,7 @@ void LocalDerivationGoal::startBuilder()
"root:x:0:0:Nix build user:%3%:/noshell\n"
"nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n"
"nobody:x:65534:65534:Nobody:/:/noshell\n",
sandboxUid(), sandboxGid(), settings.sandboxBuildDir));
sandboxUid(), sandboxGid(), localStore.sandboxBuildDir));

/* Save the mount- and user namespace of the child. We have to do this
*before* the child does a chroot. */
Expand Down Expand Up @@ -1090,7 +1094,8 @@ void LocalDerivationGoal::initTmpDir() {
/* In a sandbox, for determinism, always use the same temporary
directory. */
#if __linux__
tmpDirInSandbox = useChroot ? settings.sandboxBuildDir : tmpDir;
const auto & localStore = getLocalStore();
tmpDirInSandbox = useChroot ? localStore.sandboxBuildDir : tmpDir;
#else
tmpDirInSandbox = tmpDir;
#endif
Expand Down Expand Up @@ -1617,10 +1622,10 @@ void LocalDerivationGoal::chownToBuilder(const Path & path)
}


void setupSeccomp()
void setupSeccomp(const LocalStoreConfig & localStore)
{
#if __linux__
if (!settings.filterSyscalls) return;
if (!localStore.filterSyscalls) return;
#if HAVE_SECCOMP
scmp_filter_ctx ctx;

Expand Down Expand Up @@ -1682,7 +1687,7 @@ void setupSeccomp()
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
throw SysError("unable to add seccomp rule");

if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, settings.allowNewPrivileges ? 0 : 1) != 0)
if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, localStore.allowNewPrivileges ? 0 : 1) != 0)
throw SysError("unable to set 'no new privileges' seccomp attribute");

if (seccomp_load(ctx) != 0)
Expand All @@ -1708,7 +1713,7 @@ void LocalDerivationGoal::runChild()
commonChildInit(builderOut);

try {
setupSeccomp();
setupSeccomp(getLocalStore());
} catch (...) {
if (buildUser) throw;
}
Expand All @@ -1726,6 +1731,8 @@ void LocalDerivationGoal::runChild()
#if __linux__
if (useChroot) {

auto & localStore = getLocalStore();

userNamespaceSync.writeSide = -1;

if (drainFD(userNamespaceSync.readSide.get()) != "1")
Expand Down Expand Up @@ -1880,7 +1887,7 @@ void LocalDerivationGoal::runChild()
/* Mount a new tmpfs on /dev/shm to ensure that whatever
the builder puts in /dev/shm is cleaned up automatically. */
if (pathExists("/dev/shm") && mount("none", (chrootRootDir + "/dev/shm").c_str(), "tmpfs", 0,
fmt("size=%s", settings.sandboxShmSize).c_str()) == -1)
fmt("size=%s", localStore.sandboxShmSize).c_str()) == -1)
throw SysError("mounting /dev/shm");

/* Mount a new devpts on /dev/pts. Note that this
Expand Down Expand Up @@ -2645,15 +2652,16 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
ValidPathInfo oldInfo(*worker.store.queryPathInfo(newInfo.path));
if (newInfo.narHash != oldInfo.narHash) {
worker.checkMismatch = true;
if (settings.runDiffHook || settings.keepFailed) {
if (localStore.runDiffHook || settings.keepFailed) {
auto dst = worker.store.toRealPath(finalDestPath + checkSuffix);
deletePath(dst);
movePath(actualPath, dst);

handleDiffHook(
buildUser ? buildUser->getUID() : getuid(),
buildUser ? buildUser->getGID() : getgid(),
finalDestPath, dst, worker.store.printStorePath(drvPath), tmpDir);
finalDestPath, dst, worker.store.printStorePath(drvPath), tmpDir,
localStore);

throw NotDeterministic("derivation '%s' may not be deterministic: output '%s' differs from '%s'",
worker.store.printStorePath(drvPath), worker.store.toRealPath(finalDestPath), dst);
Expand Down
10 changes: 6 additions & 4 deletions src/libstore/build/worker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ void Worker::run(const Goals & _topGoals)
checkInterrupt();

// TODO GC interface?
if (auto localStore = dynamic_cast<LocalStore *>(&store))
if (auto * localStore = dynamic_cast<LocalStore *>(&store))
localStore->autoGC(false);

/* Call every wake goal (in the ordering established by
Expand Down Expand Up @@ -318,9 +318,11 @@ void Worker::waitForInput()
is a build timeout, then wait for input until the first
deadline for any child. */
auto nearest = steady_time_point::max(); // nearest deadline
if (settings.minFree.get() != 0)
// Periodicallty wake up to see if we need to run the garbage collector.
nearest = before + std::chrono::seconds(10);
// TODO GC interface?
if (auto * localStore = dynamic_cast<const LocalStore *>(&store))
if (localStore->minFree.get() != 0)
// Periodicallty wake up to see if we need to run the garbage collector.
nearest = before + std::chrono::seconds(10);
for (auto & i : children) {
if (!i.respectTimeouts) continue;
if (0 != settings.maxSilentTime)
Expand Down
6 changes: 3 additions & 3 deletions src/libstore/gc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -914,13 +914,13 @@ void LocalStore::autoGC(bool sync)

auto now = std::chrono::steady_clock::now();

if (now < state->lastGCCheck + std::chrono::seconds(settings.minFreeCheckInterval)) return;
if (now < state->lastGCCheck + std::chrono::seconds(minFreeCheckInterval)) return;

auto avail = getAvail();

state->lastGCCheck = now;

if (avail >= settings.minFree || avail >= settings.maxFree) return;
if (avail >= minFree || avail >= maxFree) return;

if (avail > state->availAfterGC * 0.97) return;

Expand All @@ -942,7 +942,7 @@ void LocalStore::autoGC(bool sync)
});

GCOptions options;
options.maxFreed = settings.maxFree - avail;
options.maxFreed = this->maxFree - avail;

printInfo("running auto-GC to free %d bytes", options.maxFreed);

Expand Down
54 changes: 0 additions & 54 deletions src/libstore/globals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ Settings::Settings()
{
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
lockCPU = getEnv("NIX_AFFINITY_HACK") == "1";
allowSymlinkedStore = getEnv("NIX_IGNORE_SYMLINK_STORE") == "1";

caFile = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or(""));
if (caFile == "") {
Expand All @@ -62,10 +61,6 @@ Settings::Settings()
builders = concatStringsSep(" ", ss);
}

#if defined(__linux__) && defined(SANDBOX_SHELL)
sandboxPaths = tokenizeString<StringSet>("/bin/sh=" SANDBOX_SHELL);
#endif

/* chroot-like behavior from Apple's sandbox */
#if __APPLE__
sandboxPaths = tokenizeString<StringSet>("/System/Library/Frameworks /System/Library/PrivateFrameworks /bin/sh /bin/bash /private/tmp /private/var/tmp /usr/lib");
Expand Down Expand Up @@ -189,55 +184,6 @@ bool Settings::isWSL1()

const std::string nixVersion = PACKAGE_VERSION;

NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, {
{SandboxMode::smEnabled, true},
{SandboxMode::smRelaxed, "relaxed"},
{SandboxMode::smDisabled, false},
});

template<> void BaseSetting<SandboxMode>::set(const std::string & str, bool append)
{
if (str == "true") value = smEnabled;
else if (str == "relaxed") value = smRelaxed;
else if (str == "false") value = smDisabled;
else throw UsageError("option '%s' has invalid value '%s'", name, str);
}

template<> bool BaseSetting<SandboxMode>::isAppendable()
{
return false;
}

template<> std::string BaseSetting<SandboxMode>::to_string() const
{
if (value == smEnabled) return "true";
else if (value == smRelaxed) return "relaxed";
else if (value == smDisabled) return "false";
else abort();
}

template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::string & category)
{
args.addFlag({
.longName = name,
.description = "Enable sandboxing.",
.category = category,
.handler = {[this]() { override(smEnabled); }}
});
args.addFlag({
.longName = "no-" + name,
.description = "Disable sandboxing.",
.category = category,
.handler = {[this]() { override(smDisabled); }}
});
args.addFlag({
.longName = "relaxed-" + name,
.description = "Enable sandboxing, but allow builds to disable it.",
.category = category,
.handler = {[this]() { override(smRelaxed); }}
});
}

void MaxBuildJobsSetting::set(const std::string & str, bool append)
{
if (str == "auto") value = std::max(1U, std::thread::hardware_concurrency());
Expand Down
Loading

0 comments on commit 1c34b9f

Please sign in to comment.