aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/binary-cache-store.cc2
-rw-r--r--src/libstore/binary-cache-store.hh2
-rw-r--r--src/libstore/build.cc56
-rw-r--r--src/libstore/globals.cc44
-rw-r--r--src/libstore/globals.hh17
-rw-r--r--src/libstore/local-store.cc3
-rw-r--r--src/libstore/local-store.hh3
-rw-r--r--src/libstore/local.mk6
-rw-r--r--src/libstore/pathlocks.cc6
-rw-r--r--src/libstore/pathlocks.hh6
-rw-r--r--src/libstore/store-api.cc13
-rw-r--r--src/libstore/store-api.hh8
12 files changed, 126 insertions, 40 deletions
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index ab971dd8b..d1b278b8e 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -149,7 +149,7 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, const ref<std::str
/* Compress the NAR. */
narInfo->compression = compression;
auto now1 = std::chrono::steady_clock::now();
- auto narCompressed = compress(compression, *nar);
+ auto narCompressed = compress(compression, *nar, parallelCompression);
auto now2 = std::chrono::steady_clock::now();
narInfo->fileHash = hashString(htSHA256, *narCompressed);
narInfo->fileSize = narCompressed->size();
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index 8492ff600..e20b96844 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -19,6 +19,8 @@ public:
const Setting<bool> writeNARListing{this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"};
const Setting<Path> secretKeyFile{this, "", "secret-key", "path to secret key used to sign the binary cache"};
const Setting<Path> localNarCache{this, "", "local-nar-cache", "path to a local cache of NARs"};
+ const Setting<bool> parallelCompression{this, false, "parallel-compression",
+ "enable multi-threading compression, available for xz only currently"};
private:
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index d4b93b510..1d611ffba 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -49,7 +49,9 @@
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/syscall.h>
+#if HAVE_SECCOMP
#include <seccomp.h>
+#endif
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
#endif
@@ -1335,19 +1337,6 @@ void DerivationGoal::tryToBuild()
{
trace("trying to build");
- /* Check for the possibility that some other goal in this process
- has locked the output since we checked in haveDerivation().
- (It can't happen between here and the lockPaths() call below
- because we're not allowing multi-threading.) If so, put this
- goal to sleep until another goal finishes, then try again. */
- for (auto & i : drv->outputs)
- if (pathIsLockedByMe(worker.store.toRealPath(i.second.path))) {
- debug(format("putting derivation '%1%' to sleep because '%2%' is locked by another goal")
- % drvPath % i.second.path);
- worker.waitForAnyGoal(shared_from_this());
- return;
- }
-
/* Obtain locks on all output paths. The locks are automatically
released when we exit this function or Nix crashes. If we
can't acquire the lock, then continue; hopefully some other
@@ -2484,7 +2473,7 @@ void setupSeccomp()
{
#if __linux__
if (!settings.filterSyscalls) return;
-
+#if HAVE_SECCOMP
scmp_filter_ctx ctx;
if (!(ctx = seccomp_init(SCMP_ACT_ALLOW)))
@@ -2530,6 +2519,11 @@ void setupSeccomp()
if (seccomp_load(ctx) != 0)
throw SysError("unable to load seccomp BPF program");
+#else
+ throw Error(
+ "seccomp is not supported on this platform; "
+ "you can bypass this error by setting the option 'filter-syscalls' to false, but note that untrusted builds can then create setuid binaries!");
+#endif
#endif
}
@@ -3428,7 +3422,7 @@ void DerivationGoal::flushLine()
else {
if (settings.verboseBuild &&
(settings.printRepeatedBuilds || curRound == 1))
- printError(filterANSIEscapes(currentLogLine, true));
+ printError(currentLogLine);
else {
logTail.push_back(currentLogLine);
if (logTail.size() > settings.logLines) logTail.pop_front();
@@ -3670,7 +3664,7 @@ void SubstitutionGoal::tryNext()
/* Update the total expected download size. */
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
- maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, narInfo->narSize);
+ maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, info->narSize);
maintainExpectedDownload =
narInfo && narInfo->fileSize
@@ -3684,9 +3678,12 @@ void SubstitutionGoal::tryNext()
/* Bail out early if this substituter lacks a valid
signature. LocalStore::addToStore() also checks for this, but
only after we've downloaded the path. */
- if (worker.store.requireSigs && !info->checkSignatures(worker.store, worker.store.publicKeys)) {
- printInfo(format("warning: substituter '%s' does not have a valid signature for path '%s'")
- % sub->getUri() % storePath);
+ if (worker.store.requireSigs
+ && !sub->isTrusted
+ && !info->checkSignatures(worker.store, worker.store.publicKeys))
+ {
+ printError("warning: substituter '%s' does not have a valid signature for path '%s'",
+ sub->getUri(), storePath);
tryNext();
return;
}
@@ -3736,6 +3733,17 @@ void SubstitutionGoal::tryToRun()
return;
}
+ /* If the store path is already locked (probably by a
+ DerivationGoal), then put this goal to sleep. Note: we don't
+ acquire a lock here since that breaks addToStore(), so below we
+ handle an AlreadyLocked exception from addToStore(). The check
+ here is just an optimisation to prevent having to redo a
+ download due to a locked path. */
+ if (pathIsLockedByMe(worker.store.toRealPath(storePath))) {
+ worker.waitForAWhile(shared_from_this());
+ return;
+ }
+
maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t>>(worker.runningSubstitutions);
worker.updateProgress();
@@ -3752,7 +3760,7 @@ void SubstitutionGoal::tryToRun()
PushActivity pact(act.id);
copyStorePath(ref<Store>(sub), ref<Store>(worker.store.shared_from_this()),
- storePath, repair);
+ storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
promise.set_value();
} catch (...) {
@@ -3775,8 +3783,14 @@ void SubstitutionGoal::finished()
try {
promise.get_future().get();
+ } catch (AlreadyLocked & e) {
+ /* Probably a DerivationGoal is already building this store
+ path. Sleep for a while and try again. */
+ state = &SubstitutionGoal::init;
+ worker.waitForAWhile(shared_from_this());
+ return;
} catch (Error & e) {
- printInfo(e.msg());
+ printError(e.msg());
/* Try the next substitute. */
state = &SubstitutionGoal::tryNext;
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index d3c96ddd6..f46e83262 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <map>
#include <thread>
+#include <dlfcn.h>
namespace nix {
@@ -37,6 +38,7 @@ Settings::Settings()
, nixConfDir(canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR)))
, nixLibexecDir(canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR)))
, nixBinDir(canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR)))
+ , nixManDir(canonPath(NIX_MAN_DIR))
, nixDaemonSocketFile(canonPath(nixStateDir + DEFAULT_SOCKET_PATH))
{
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
@@ -137,4 +139,46 @@ void MaxBuildJobsSetting::set(const std::string & str)
throw UsageError("configuration setting '%s' should be 'auto' or an integer", name);
}
+
+void initPlugins()
+{
+ for (const auto & pluginFile : settings.pluginFiles.get()) {
+ Paths pluginFiles;
+ try {
+ auto ents = readDirectory(pluginFile);
+ for (const auto & ent : ents)
+ pluginFiles.emplace_back(pluginFile + "/" + ent.name);
+ } catch (SysError & e) {
+ if (e.errNo != ENOTDIR)
+ throw;
+ pluginFiles.emplace_back(pluginFile);
+ }
+ for (const auto & file : pluginFiles) {
+ /* handle is purposefully leaked as there may be state in the
+ DSO needed by the action of the plugin. */
+ void *handle =
+ dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL);
+ if (!handle)
+ throw Error("could not dynamically open plugin file '%s%': %s%", file, dlerror());
+ }
+ }
+ /* We handle settings registrations here, since plugins can add settings */
+ if (RegisterSetting::settingRegistrations) {
+ for (auto & registration : *RegisterSetting::settingRegistrations)
+ settings.addSetting(registration);
+ delete RegisterSetting::settingRegistrations;
+ }
+ settings.handleUnknownSettings();
+}
+
+RegisterSetting::SettingRegistrations * RegisterSetting::settingRegistrations;
+
+RegisterSetting::RegisterSetting(AbstractSetting * s)
+{
+ if (!settingRegistrations)
+ settingRegistrations = new SettingRegistrations;
+ settingRegistrations->emplace_back(s);
+}
+
+
}
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 20ac8fe4e..dd01f832d 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -82,6 +82,9 @@ public:
/* The directory where the main programs are stored. */
Path nixBinDir;
+ /* The directory where the man pages are stored. */
+ Path nixManDir;
+
/* File name of the socket the daemon listens to. */
Path nixDaemonSocketFile;
@@ -367,14 +370,28 @@ public:
Setting<Strings> allowedUris{this, {}, "allowed-uris",
"Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."};
+
+ Setting<Paths> pluginFiles{this, {}, "plugin-files",
+ "Plugins to dynamically load at nix initialization time."};
};
// FIXME: don't use a global variable.
extern Settings settings;
+/* This should be called after settings are initialized, but before
+ anything else */
+void initPlugins();
+
extern const string nixVersion;
+struct RegisterSetting
+{
+ typedef std::vector<AbstractSetting *> SettingRegistrations;
+ static SettingRegistrations * settingRegistrations;
+ RegisterSetting(AbstractSetting * s);
+};
+
}
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 7afecc1cf..4afe51ea9 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -992,8 +992,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, const ref<std::string> &
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
lock on this path). */
- Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS"));
- if (find(locksHeld.begin(), locksHeld.end(), info.path) == locksHeld.end())
+ if (!locksHeld.count(info.path))
outputLock.lockPaths({realPath});
if (repair || !isValidPath(info.path)) {
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 30bef3a79..bbd50e1c1 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -104,6 +104,9 @@ private:
public:
+ // Hack for build-remote.cc.
+ PathSet locksHeld = tokenizeString<PathSet>(getEnv("NIX_HELD_LOCKS"));
+
/* Initialise the local store, upgrading the schema if
necessary. */
LocalStore(const Params & params);
diff --git a/src/libstore/local.mk b/src/libstore/local.mk
index 50c46ce6f..e11efa5c2 100644
--- a/src/libstore/local.mk
+++ b/src/libstore/local.mk
@@ -9,6 +9,9 @@ libstore_SOURCES := $(wildcard $(d)/*.cc)
libstore_LIBS = libutil libformat
libstore_LDFLAGS = $(SQLITE3_LIBS) -lbz2 $(LIBCURL_LIBS) $(SODIUM_LIBS) -pthread
+ifneq ($(OS), FreeBSD)
+ libstore_LDFLAGS += -ldl
+endif
libstore_FILES = sandbox-defaults.sb sandbox-minimal.sb sandbox-network.sb
@@ -22,7 +25,7 @@ ifeq ($(OS), SunOS)
libstore_LDFLAGS += -lsocket
endif
-ifeq ($(OS), Linux)
+ifeq ($(HAVE_SECCOMP), 1)
libstore_LDFLAGS += -lseccomp
endif
@@ -35,6 +38,7 @@ libstore_CXXFLAGS = \
-DNIX_CONF_DIR=\"$(sysconfdir)/nix\" \
-DNIX_LIBEXEC_DIR=\"$(libexecdir)\" \
-DNIX_BIN_DIR=\"$(bindir)\" \
+ -DNIX_MAN_DIR=\"$(mandir)\" \
-DSANDBOX_SHELL="\"$(sandbox_shell)\"" \
-DLSOF=\"$(lsof)\"
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index 587f29598..08d1efdbe 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -113,8 +113,10 @@ bool PathLocks::lockPaths(const PathSet & _paths,
{
auto lockedPaths(lockedPaths_.lock());
- if (lockedPaths->count(lockPath))
- throw Error("deadlock: trying to re-acquire self-held lock '%s'", lockPath);
+ if (lockedPaths->count(lockPath)) {
+ if (!wait) return false;
+ throw AlreadyLocked("deadlock: trying to re-acquire self-held lock '%s'", lockPath);
+ }
lockedPaths->insert(lockPath);
}
diff --git a/src/libstore/pathlocks.hh b/src/libstore/pathlocks.hh
index 2a7de6114..db51f950a 100644
--- a/src/libstore/pathlocks.hh
+++ b/src/libstore/pathlocks.hh
@@ -2,10 +2,8 @@
#include "util.hh"
-
namespace nix {
-
/* Open (possibly create) a lock file and return the file descriptor.
-1 is returned if create is false and the lock could not be opened
because it doesn't exist. Any other error throws an exception. */
@@ -18,6 +16,7 @@ enum LockType { ltRead, ltWrite, ltNone };
bool lockFile(int fd, LockType lockType, bool wait);
+MakeError(AlreadyLocked, Error);
class PathLocks
{
@@ -38,9 +37,6 @@ public:
void setDeletion(bool deletePaths);
};
-
-// FIXME: not thread-safe!
bool pathIsLockedByMe(const Path & path);
-
}
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 77ab87ef7..8830edcc3 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -222,11 +222,10 @@ Path Store::makeTextPath(const string & name, const Hash & hash,
}
-std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath,
- bool recursive, HashType hashAlgo, PathFilter & filter) const
+std::pair<Path, Hash> Store::computeStorePathForPath(const string & name,
+ const Path & srcPath, bool recursive, HashType hashAlgo, PathFilter & filter) const
{
Hash h = recursive ? hashPath(hashAlgo, srcPath, filter).first : hashFile(hashAlgo, srcPath);
- string name = baseNameOf(srcPath);
Path dstPath = makeFixedOutputPath(recursive, h, name);
return std::pair<Path, Hash>(dstPath, h);
}
@@ -840,7 +839,7 @@ ref<Store> openStore(const std::string & uri_,
for (auto fun : *RegisterStoreImplementation::implementations) {
auto store = fun(uri, params);
if (store) {
- store->warnUnknownSettings();
+ store->handleUnknownSettings();
return ref<Store>(store);
}
}
@@ -897,7 +896,11 @@ std::list<ref<Store>> getDefaultSubstituters()
auto addStore = [&](const std::string & uri) {
if (done.count(uri)) return;
done.insert(uri);
- stores.push_back(openStore(uri));
+ try {
+ stores.push_back(openStore(uri));
+ } catch (Error & e) {
+ printError("warning: %s", e.what());
+ }
};
for (auto uri : settings.substituters.get())
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 70f23e1fc..563aa566b 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -248,6 +248,8 @@ public:
const Setting<int> pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"};
+ const Setting<bool> isTrusted{this, false, "trusted", "whether paths from this store can be used as substitutes even when they lack trusted signatures"};
+
protected:
struct State
@@ -305,9 +307,9 @@ public:
/* This is the preparatory part of addToStore(); it computes the
store path to which srcPath is to be copied. Returns the store
path and the cryptographic hash of the contents of srcPath. */
- std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
- bool recursive = true, HashType hashAlgo = htSHA256,
- PathFilter & filter = defaultPathFilter) const;
+ std::pair<Path, Hash> computeStorePathForPath(const string & name,
+ const Path & srcPath, bool recursive = true,
+ HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const;
/* Preparatory part of addTextToStore().