mirror of
https://github.com/NixOS/nix.git
synced 2025-11-15 23:12:44 +01:00
Merge remote-tracking branch 'upstream/master' into overlayfs-store
This commit is contained in:
commit
c99c80f075
200 changed files with 6007 additions and 1158 deletions
|
|
@ -124,14 +124,6 @@ void BinaryCacheStore::writeNarInfo(ref<NarInfo> narInfo)
|
|||
diskCache->upsertNarInfo(getUri(), std::string(narInfo->path.hashPart()), std::shared_ptr<NarInfo>(narInfo));
|
||||
}
|
||||
|
||||
AutoCloseFD openFile(const Path & path)
|
||||
{
|
||||
auto fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
if (!fd)
|
||||
throw SysError("opening file '%1%'", path);
|
||||
return fd;
|
||||
}
|
||||
|
||||
ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||
Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs,
|
||||
std::function<ValidPathInfo(HashResult)> mkInfo)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include "cgroup.hh"
|
||||
#include "personality.hh"
|
||||
#include "current-process.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "child.hh"
|
||||
#include "unix-domain-socket.hh"
|
||||
#include "posix-fs-canonicalise.hh"
|
||||
|
|
@ -40,18 +39,19 @@
|
|||
|
||||
/* Includes required for chroot support. */
|
||||
#if __linux__
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sched.h>
|
||||
#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))
|
||||
# include <sys/ioctl.h>
|
||||
# include <net/if.h>
|
||||
# include <netinet/ip.h>
|
||||
# include <sys/mman.h>
|
||||
# include <sched.h>
|
||||
# include <sys/param.h>
|
||||
# include <sys/mount.h>
|
||||
# include <sys/syscall.h>
|
||||
# include "namespaces.hh"
|
||||
# if HAVE_SECCOMP
|
||||
# include <seccomp.h>
|
||||
# endif
|
||||
# define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
|
|
@ -488,7 +488,7 @@ void LocalDerivationGoal::startBuilder()
|
|||
|
||||
/* Create a temporary directory where the build will take
|
||||
place. */
|
||||
tmpDir = createTempDir("", "nix-build-" + std::string(drvPath.name()), false, false, 0700);
|
||||
tmpDir = createTempDir(settings.buildDir.get().value_or(""), "nix-build-" + std::string(drvPath.name()), false, false, 0700);
|
||||
|
||||
chownToBuilder(tmpDir);
|
||||
|
||||
|
|
@ -2053,13 +2053,13 @@ void LocalDerivationGoal::runChild()
|
|||
i.first, i.second.source);
|
||||
|
||||
std::string path = i.first;
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st)) {
|
||||
if (i.second.optional && errno == ENOENT)
|
||||
auto optSt = maybeLstat(path.c_str());
|
||||
if (!optSt) {
|
||||
if (i.second.optional)
|
||||
continue;
|
||||
throw SysError("getting attributes of path '%s", path);
|
||||
throw SysError("getting attributes of required path '%s", path);
|
||||
}
|
||||
if (S_ISDIR(st.st_mode))
|
||||
if (S_ISDIR(optSt->st_mode))
|
||||
sandboxProfile += fmt("\t(subpath \"%s\")\n", path);
|
||||
else
|
||||
sandboxProfile += fmt("\t(literal \"%s\")\n", path);
|
||||
|
|
@ -2089,11 +2089,12 @@ void LocalDerivationGoal::runChild()
|
|||
bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking");
|
||||
|
||||
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms
|
||||
to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */
|
||||
Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true);
|
||||
to find temporary directories, so we want to open up a broader place for them to put their files, if needed. */
|
||||
Path globalTmpDir = canonPath(defaultTempDir(), true);
|
||||
|
||||
/* They don't like trailing slashes on subpath directives */
|
||||
if (globalTmpDir.back() == '/') globalTmpDir.pop_back();
|
||||
while (!globalTmpDir.empty() && globalTmpDir.back() == '/')
|
||||
globalTmpDir.pop_back();
|
||||
|
||||
if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") {
|
||||
builder = "/usr/bin/sandbox-exec";
|
||||
|
|
@ -2270,14 +2271,12 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
|
|||
continue;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (lstat(actualPath.c_str(), &st) == -1) {
|
||||
if (errno == ENOENT)
|
||||
throw BuildError(
|
||||
"builder for '%s' failed to produce output path for output '%s' at '%s'",
|
||||
worker.store.printStorePath(drvPath), outputName, actualPath);
|
||||
throw SysError("getting attributes of path '%s'", actualPath);
|
||||
}
|
||||
auto optSt = maybeLstat(actualPath.c_str());
|
||||
if (!optSt)
|
||||
throw BuildError(
|
||||
"builder for '%s' failed to produce output path for output '%s' at '%s'",
|
||||
worker.store.printStorePath(drvPath), outputName, actualPath);
|
||||
struct stat & st = *optSt;
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
/* Check that the output is not group or world writable, as
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
|
|||
continue;
|
||||
|
||||
else if (S_ISDIR(srcSt.st_mode)) {
|
||||
struct stat dstSt;
|
||||
auto res = lstat(dstFile.c_str(), &dstSt);
|
||||
if (res == 0) {
|
||||
auto dstStOpt = maybeLstat(dstFile.c_str());
|
||||
if (dstStOpt) {
|
||||
auto & dstSt = *dstStOpt;
|
||||
if (S_ISDIR(dstSt.st_mode)) {
|
||||
createLinks(state, srcFile, dstFile, priority);
|
||||
continue;
|
||||
|
|
@ -82,14 +82,13 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
|
|||
createLinks(state, srcFile, dstFile, priority);
|
||||
continue;
|
||||
}
|
||||
} else if (errno != ENOENT)
|
||||
throw SysError("getting status of '%1%'", dstFile);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
struct stat dstSt;
|
||||
auto res = lstat(dstFile.c_str(), &dstSt);
|
||||
if (res == 0) {
|
||||
auto dstStOpt = maybeLstat(dstFile.c_str());
|
||||
if (dstStOpt) {
|
||||
auto & dstSt = *dstStOpt;
|
||||
if (S_ISLNK(dstSt.st_mode)) {
|
||||
auto prevPriority = state.priorities[dstFile];
|
||||
if (prevPriority == priority)
|
||||
|
|
@ -104,8 +103,7 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
|
|||
throw SysError("unlinking '%1%'", dstFile);
|
||||
} else if (S_ISDIR(dstSt.st_mode))
|
||||
throw Error("collision between non-directory '%1%' and directory '%2%'", srcFile, dstFile);
|
||||
} else if (errno != ENOENT)
|
||||
throw SysError("getting status of '%1%'", dstFile);
|
||||
}
|
||||
}
|
||||
|
||||
createSymlink(srcFile, dstFile);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "daemon.hh"
|
||||
#include "monitor-fd.hh"
|
||||
#include "signals.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "worker-protocol-impl.hh"
|
||||
#include "build-result.hh"
|
||||
|
|
@ -254,7 +255,7 @@ struct ClientSettings
|
|||
else if (setSubstituters(settings.substituters))
|
||||
;
|
||||
else
|
||||
debug("ignoring the client-specified setting '%s', because it is a restricted setting and you are not a trusted user", name);
|
||||
warn("ignoring the client-specified setting '%s', because it is a restricted setting and you are not a trusted user", name);
|
||||
} catch (UsageError & e) {
|
||||
warn(e.what());
|
||||
}
|
||||
|
|
@ -1038,7 +1039,7 @@ void processConnection(
|
|||
unsigned int opCount = 0;
|
||||
|
||||
Finally finally([&]() {
|
||||
_isInterrupted = false;
|
||||
setInterrupted(false);
|
||||
printMsgUsing(prevLogger, lvlDebug, "%d operations", opCount);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1239,16 +1239,14 @@ DerivationOutput DerivationOutput::fromJSON(
|
|||
const ExperimentalFeatureSettings & xpSettings)
|
||||
{
|
||||
std::set<std::string_view> keys;
|
||||
ensureType(_json, nlohmann::detail::value_t::object);
|
||||
auto json = (std::map<std::string, nlohmann::json>) _json;
|
||||
auto & json = getObject(_json);
|
||||
|
||||
for (const auto & [key, _] : json)
|
||||
keys.insert(key);
|
||||
|
||||
auto methodAlgo = [&]() -> std::pair<ContentAddressMethod, HashAlgorithm> {
|
||||
std::string hashAlgoStr = json["hashAlgo"];
|
||||
// remaining to parse, will be mutated by parsers
|
||||
std::string_view s = hashAlgoStr;
|
||||
auto & str = getString(valueAt(json, "hashAlgo"));
|
||||
std::string_view s = str;
|
||||
ContentAddressMethod method = ContentAddressMethod::parsePrefix(s);
|
||||
if (method == TextIngestionMethod {})
|
||||
xpSettings.require(Xp::DynamicDerivations);
|
||||
|
|
@ -1258,7 +1256,7 @@ DerivationOutput DerivationOutput::fromJSON(
|
|||
|
||||
if (keys == (std::set<std::string_view> { "path" })) {
|
||||
return DerivationOutput::InputAddressed {
|
||||
.path = store.parseStorePath((std::string) json["path"]),
|
||||
.path = store.parseStorePath(getString(valueAt(json, "path"))),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -1267,10 +1265,10 @@ DerivationOutput DerivationOutput::fromJSON(
|
|||
auto dof = DerivationOutput::CAFixed {
|
||||
.ca = ContentAddress {
|
||||
.method = std::move(method),
|
||||
.hash = Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashAlgo),
|
||||
.hash = Hash::parseNonSRIUnprefixed(getString(valueAt(json, "hash")), hashAlgo),
|
||||
},
|
||||
};
|
||||
if (dof.path(store, drvName, outputName) != store.parseStorePath((std::string) json["path"]))
|
||||
if (dof.path(store, drvName, outputName) != store.parseStorePath(getString(valueAt(json, "path"))))
|
||||
throw Error("Path doesn't match derivation output");
|
||||
return dof;
|
||||
}
|
||||
|
|
@ -1357,20 +1355,19 @@ nlohmann::json Derivation::toJSON(const StoreDirConfig & store) const
|
|||
|
||||
Derivation Derivation::fromJSON(
|
||||
const StoreDirConfig & store,
|
||||
const nlohmann::json & json,
|
||||
const nlohmann::json & _json,
|
||||
const ExperimentalFeatureSettings & xpSettings)
|
||||
{
|
||||
using nlohmann::detail::value_t;
|
||||
|
||||
Derivation res;
|
||||
|
||||
ensureType(json, value_t::object);
|
||||
auto & json = getObject(_json);
|
||||
|
||||
res.name = ensureType(valueAt(json, "name"), value_t::string);
|
||||
res.name = getString(valueAt(json, "name"));
|
||||
|
||||
try {
|
||||
auto & outputsObj = ensureType(valueAt(json, "outputs"), value_t::object);
|
||||
for (auto & [outputName, output] : outputsObj.items()) {
|
||||
for (auto & [outputName, output] : getObject(valueAt(json, "outputs"))) {
|
||||
res.outputs.insert_or_assign(
|
||||
outputName,
|
||||
DerivationOutput::fromJSON(store, res.name, outputName, output));
|
||||
|
|
@ -1381,8 +1378,7 @@ Derivation Derivation::fromJSON(
|
|||
}
|
||||
|
||||
try {
|
||||
auto & inputsList = ensureType(valueAt(json, "inputSrcs"), value_t::array);
|
||||
for (auto & input : inputsList)
|
||||
for (auto & input : getArray(valueAt(json, "inputSrcs")))
|
||||
res.inputSrcs.insert(store.parseStorePath(static_cast<const std::string &>(input)));
|
||||
} catch (Error & e) {
|
||||
e.addTrace({}, "while reading key 'inputSrcs'");
|
||||
|
|
@ -1391,18 +1387,17 @@ Derivation Derivation::fromJSON(
|
|||
|
||||
try {
|
||||
std::function<DerivedPathMap<StringSet>::ChildNode(const nlohmann::json &)> doInput;
|
||||
doInput = [&](const auto & json) {
|
||||
doInput = [&](const auto & _json) {
|
||||
auto & json = getObject(_json);
|
||||
DerivedPathMap<StringSet>::ChildNode node;
|
||||
node.value = static_cast<const StringSet &>(
|
||||
ensureType(valueAt(json, "outputs"), value_t::array));
|
||||
for (auto & [outputId, childNode] : ensureType(valueAt(json, "dynamicOutputs"), value_t::object).items()) {
|
||||
node.value = getStringSet(valueAt(json, "outputs"));
|
||||
for (auto & [outputId, childNode] : getObject(valueAt(json, "dynamicOutputs"))) {
|
||||
xpSettings.require(Xp::DynamicDerivations);
|
||||
node.childMap[outputId] = doInput(childNode);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
auto & inputDrvsObj = ensureType(valueAt(json, "inputDrvs"), value_t::object);
|
||||
for (auto & [inputDrvPath, inputOutputs] : inputDrvsObj.items())
|
||||
for (auto & [inputDrvPath, inputOutputs] : getObject(valueAt(json, "inputDrvs")))
|
||||
res.inputDrvs.map[store.parseStorePath(inputDrvPath)] =
|
||||
doInput(inputOutputs);
|
||||
} catch (Error & e) {
|
||||
|
|
@ -1410,10 +1405,10 @@ Derivation Derivation::fromJSON(
|
|||
throw;
|
||||
}
|
||||
|
||||
res.platform = ensureType(valueAt(json, "system"), value_t::string);
|
||||
res.builder = ensureType(valueAt(json, "builder"), value_t::string);
|
||||
res.args = ensureType(valueAt(json, "args"), value_t::array);
|
||||
res.env = ensureType(valueAt(json, "env"), value_t::object);
|
||||
res.platform = getString(valueAt(json, "system"));
|
||||
res.builder = getString(valueAt(json, "builder"));
|
||||
res.args = getStringList(valueAt(json, "args"));
|
||||
res.env = getStringMap(valueAt(json, "env"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "filetransfer.hh"
|
||||
#include "namespaces.hh"
|
||||
#include "globals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "s3.hh"
|
||||
|
|
@ -12,6 +11,10 @@
|
|||
#include <aws/core/client/ClientConfiguration.h>
|
||||
#endif
|
||||
|
||||
#if __linux__
|
||||
# include "namespaces.hh"
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
|
@ -255,11 +258,11 @@ struct curlFileTransfer : public FileTransfer
|
|||
int progressCallback(double dltotal, double dlnow)
|
||||
{
|
||||
try {
|
||||
act.progress(dlnow, dltotal);
|
||||
act.progress(dlnow, dltotal);
|
||||
} catch (nix::Interrupted &) {
|
||||
assert(_isInterrupted);
|
||||
assert(getInterrupted());
|
||||
}
|
||||
return _isInterrupted;
|
||||
return getInterrupted();
|
||||
}
|
||||
|
||||
static int progressCallbackWrapper(void * userp, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
|
|
@ -463,7 +466,7 @@ struct curlFileTransfer : public FileTransfer
|
|||
if (errorSink)
|
||||
response = std::move(errorSink->s);
|
||||
auto exc =
|
||||
code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted
|
||||
code == CURLE_ABORTED_BY_CALLBACK && getInterrupted()
|
||||
? FileTransferError(Interrupted, std::move(response), "%s of '%s' was interrupted", request.verb(), request.uri)
|
||||
: httpStatus != 0
|
||||
? FileTransferError(err,
|
||||
|
|
@ -568,7 +571,9 @@ struct curlFileTransfer : public FileTransfer
|
|||
stopWorkerThread();
|
||||
});
|
||||
|
||||
#if __linux__
|
||||
unshareFilesystem();
|
||||
#endif
|
||||
|
||||
std::map<CURL *, std::shared_ptr<TransferItem>> items;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "current-process.hh"
|
||||
#include "archive.hh"
|
||||
#include "args.hh"
|
||||
#include "users.hh"
|
||||
#include "abstract-setting-to-json.hh"
|
||||
#include "compute-levels.hh"
|
||||
|
||||
|
|
@ -57,7 +56,7 @@ Settings::Settings()
|
|||
, nixManDir(canonPath(NIX_MAN_DIR))
|
||||
, nixDaemonSocketFile(canonPath(getEnvNonEmpty("NIX_DAEMON_SOCKET_PATH").value_or(nixStateDir + DEFAULT_SOCKET_PATH)))
|
||||
{
|
||||
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
|
||||
buildUsersGroup = isRootUser() ? "nixbld" : "";
|
||||
allowSymlinkedStore = getEnv("NIX_IGNORE_SYMLINK_STORE") == "1";
|
||||
|
||||
auto sslOverride = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or(""));
|
||||
|
|
@ -346,6 +345,12 @@ void initPlugins()
|
|||
dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle)
|
||||
throw Error("could not dynamically open plugin file '%s': %s", file, dlerror());
|
||||
|
||||
/* Older plugins use a statically initialized object to run their code.
|
||||
Newer plugins can also export nix_plugin_entry() */
|
||||
void (*nix_plugin_entry)() = (void (*)())dlsym(handle, "nix_plugin_entry");
|
||||
if (nix_plugin_entry)
|
||||
nix_plugin_entry();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -404,6 +409,7 @@ void assertLibStoreInitialized() {
|
|||
}
|
||||
|
||||
void initLibStore() {
|
||||
if (initLibStoreDone) return;
|
||||
|
||||
initLibUtil();
|
||||
|
||||
|
|
@ -415,7 +421,7 @@ void initLibStore() {
|
|||
sshd). This breaks build users because they don't have access
|
||||
to the TMPDIR, in particular in ‘nix-store --serve’. */
|
||||
#if __APPLE__
|
||||
if (hasPrefix(getEnv("TMPDIR").value_or("/tmp"), "/var/folders/"))
|
||||
if (hasPrefix(defaultTempDir(), "/var/folders/"))
|
||||
unsetenv("TMPDIR");
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "config.hh"
|
||||
#include "environment-variables.hh"
|
||||
#include "experimental-features.hh"
|
||||
#include "users.hh"
|
||||
|
||||
#include <map>
|
||||
#include <limits>
|
||||
|
|
@ -665,7 +666,7 @@ public:
|
|||
Setting<bool> sandboxFallback{this, true, "sandbox-fallback",
|
||||
"Whether to disable sandboxing when the kernel doesn't allow it."};
|
||||
|
||||
Setting<bool> requireDropSupplementaryGroups{this, getuid() == 0, "require-drop-supplementary-groups",
|
||||
Setting<bool> requireDropSupplementaryGroups{this, isRootUser(), "require-drop-supplementary-groups",
|
||||
R"(
|
||||
Following the principle of least privilege,
|
||||
Nix will attempt to drop supplementary groups when building with sandboxing.
|
||||
|
|
@ -687,16 +688,36 @@ public:
|
|||
Setting<std::string> sandboxShmSize{
|
||||
this, "50%", "sandbox-dev-shm-size",
|
||||
R"(
|
||||
This option determines the maximum size of the `tmpfs` filesystem
|
||||
mounted on `/dev/shm` in Linux sandboxes. For the format, see the
|
||||
description of the `size` option of `tmpfs` in mount(8). The default
|
||||
is `50%`.
|
||||
*Linux only*
|
||||
|
||||
This option determines the maximum size of the `tmpfs` filesystem
|
||||
mounted on `/dev/shm` in Linux sandboxes. For the format, see the
|
||||
description of the `size` option of `tmpfs` in mount(8). The default
|
||||
is `50%`.
|
||||
)"};
|
||||
|
||||
Setting<Path> sandboxBuildDir{this, "/build", "sandbox-build-dir",
|
||||
"The build directory inside the sandbox."};
|
||||
R"(
|
||||
*Linux only*
|
||||
|
||||
The build directory inside the sandbox.
|
||||
|
||||
This directory is backed by [`build-dir`](#conf-build-dir) on the host.
|
||||
)"};
|
||||
#endif
|
||||
|
||||
Setting<std::optional<Path>> buildDir{this, std::nullopt, "build-dir",
|
||||
R"(
|
||||
The directory on the host, in which derivations' temporary build directories are created.
|
||||
|
||||
If not set, Nix will use the system temporary directory indicated by the `TMPDIR` environment variable.
|
||||
Note that builds are often performed by the Nix daemon, so its `TMPDIR` is used, and not that of the Nix command line interface.
|
||||
|
||||
This is also the location where [`--keep-failed`](@docroot@/command-ref/opt-common.md#opt-keep-failed) leaves its files.
|
||||
|
||||
If Nix runs without sandbox, or if the platform does not support sandboxing with bind mounts (e.g. macOS), then the [`builder`](@docroot@/language/derivations.md#attr-builder)'s environment will contain this directory, instead of the virtual location [`sandbox-build-dir`](#conf-sandbox-build-dir).
|
||||
)"};
|
||||
|
||||
Setting<PathSet> allowedImpureHostPrefixes{this, {}, "allowed-impure-host-deps",
|
||||
"Which prefixes to allow derivations to ask for access to (primarily for Darwin)."};
|
||||
|
||||
|
|
@ -1136,9 +1157,10 @@ public:
|
|||
this, {}, "plugin-files",
|
||||
R"(
|
||||
A list of plugin files to be loaded by Nix. Each of these files will
|
||||
be dlopened by Nix, allowing them to affect execution through static
|
||||
initialization. In particular, these plugins may construct static
|
||||
instances of RegisterPrimOp to add new primops or constants to the
|
||||
be dlopened by Nix. If they contain the symbol `nix_plugin_entry()`,
|
||||
this symbol will be called. Alternatively, they can affect execution
|
||||
through static initialization. In particular, these plugins may construct
|
||||
static instances of RegisterPrimOp to add new primops or constants to the
|
||||
expression language, RegisterStoreImplementation to add new store
|
||||
implementations, RegisterCommand to add new subcommands to the `nix`
|
||||
command, and RegisterSetting to add new nix config settings. See the
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public:
|
|||
, BinaryCacheStore(params)
|
||||
, cacheUri(scheme + "://" + _cacheUri)
|
||||
{
|
||||
if (cacheUri.back() == '/')
|
||||
while (!cacheUri.empty() && cacheUri.back() == '/')
|
||||
cacheUri.pop_back();
|
||||
|
||||
diskCache = getNarInfoDiskCache();
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "posix-fs-canonicalise.hh"
|
||||
#include "posix-source-accessor.hh"
|
||||
#include "keys.hh"
|
||||
#include "users.hh"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
|
@ -223,7 +224,7 @@ LocalStore::LocalStore(const Params & params)
|
|||
|
||||
/* Optionally, create directories and set permissions for a
|
||||
multi-user install. */
|
||||
if (getuid() == 0 && settings.buildUsersGroup != "") {
|
||||
if (isRootUser() && settings.buildUsersGroup != "") {
|
||||
mode_t perm = 01775;
|
||||
|
||||
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
|
||||
|
|
@ -558,6 +559,19 @@ void LocalStore::openDB(State & state, bool create)
|
|||
sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
|
||||
SQLiteError::throw_(db, "setting journal mode");
|
||||
|
||||
if (mode == "wal") {
|
||||
/* persist the WAL files when the db connection is closed. This allows
|
||||
for read-only connections without write permissions on the
|
||||
containing directory to succeed on a closed db. Setting the
|
||||
journal_size_limit to 2^40 bytes results in the WAL files getting
|
||||
truncated to 0 on exit and limits the on disk size of the WAL files
|
||||
to 2^40 bytes following a checkpoint */
|
||||
if (sqlite3_exec(db, "pragma main.journal_size_limit = 1099511627776;", 0, 0, 0) == SQLITE_OK) {
|
||||
int enable = 1;
|
||||
sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, &enable);
|
||||
}
|
||||
}
|
||||
|
||||
/* Increase the auto-checkpoint interval to 40000 pages. This
|
||||
seems enough to ensure that instantiating the NixOS system
|
||||
derivation is done in a single fsync(). */
|
||||
|
|
@ -579,7 +593,7 @@ void LocalStore::openDB(State & state, bool create)
|
|||
void LocalStore::makeStoreWritable()
|
||||
{
|
||||
#if __linux__
|
||||
if (getuid() != 0) return;
|
||||
if (!isRootUser()) return;
|
||||
/* Check if /nix/store is on a read-only mount. */
|
||||
struct statvfs stat;
|
||||
if (statvfs(realStoreDir.get().c_str(), &stat) != 0)
|
||||
|
|
@ -1588,7 +1602,7 @@ static void makeMutable(const Path & path)
|
|||
/* Upgrade from schema 6 (Nix 0.15) to schema 7 (Nix >= 1.3). */
|
||||
void LocalStore::upgradeStore7()
|
||||
{
|
||||
if (getuid() != 0) return;
|
||||
if (!isRootUser()) return;
|
||||
printInfo("removing immutable bits from the Nix store (this may take a while)...");
|
||||
makeMutable(realStoreDir);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ libstore_NAME = libnixstore
|
|||
libstore_DIR := $(d)
|
||||
|
||||
libstore_SOURCES := $(wildcard $(d)/*.cc $(d)/builtins/*.cc $(d)/build/*.cc)
|
||||
ifdef HOST_UNIX
|
||||
libstore_SOURCES += $(wildcard $(d)/unix/*.cc)
|
||||
endif
|
||||
|
||||
libstore_LIBS = libutil
|
||||
|
||||
libstore_LDFLAGS += $(SQLITE3_LIBS) $(LIBCURL_LIBS) $(THREAD_LDFLAGS)
|
||||
ifdef HOST_LINUX
|
||||
libstore_LDFLAGS += -ldl
|
||||
libstore_LDFLAGS += -ldl
|
||||
endif
|
||||
|
||||
$(foreach file,$(libstore_FILES),$(eval $(call install-data-in,$(d)/$(file),$(datadir)/nix/sandbox)))
|
||||
|
|
@ -27,8 +30,15 @@ ifeq ($(HAVE_SECCOMP), 1)
|
|||
libstore_LDFLAGS += $(LIBSECCOMP_LIBS)
|
||||
endif
|
||||
|
||||
# Not just for this library itself, but also for downstream libraries using this library
|
||||
|
||||
INCLUDE_libstore := -I $(d) -I $(d)/build
|
||||
ifdef HOST_UNIX
|
||||
INCLUDE_libstore += -I $(d)/unix
|
||||
endif
|
||||
|
||||
libstore_CXXFLAGS += \
|
||||
-I src/libutil -I src/libstore -I src/libstore/build \
|
||||
$(INCLUDE_libutil) $(INCLUDE_libstore) $(INCLUDE_libstore) \
|
||||
-DNIX_PREFIX=\"$(prefix)\" \
|
||||
-DNIX_STORE_DIR=\"$(storedir)\" \
|
||||
-DNIX_DATA_DIR=\"$(datadir)\" \
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "file-system.hh"
|
||||
#include "globals.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "users.hh"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
|
@ -192,10 +193,10 @@ std::unique_ptr<UserLock> acquireUserLock(uid_t nrIds, bool useUserNamespace)
|
|||
bool useBuildUsers()
|
||||
{
|
||||
#if __linux__
|
||||
static bool b = (settings.buildUsersGroup != "" || settings.autoAllocateUids) && getuid() == 0;
|
||||
static bool b = (settings.buildUsersGroup != "" || settings.autoAllocateUids) && isRootUser();
|
||||
return b;
|
||||
#elif __APPLE__
|
||||
static bool b = settings.buildUsersGroup != "" && getuid() == 0;
|
||||
static bool b = settings.buildUsersGroup != "" && isRootUser();
|
||||
return b;
|
||||
#else
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -172,19 +172,18 @@ NarInfo NarInfo::fromJSON(
|
|||
};
|
||||
|
||||
if (json.contains("url"))
|
||||
res.url = ensureType(valueAt(json, "url"), value_t::string);
|
||||
res.url = getString(valueAt(json, "url"));
|
||||
|
||||
if (json.contains("compression"))
|
||||
res.compression = ensureType(valueAt(json, "compression"), value_t::string);
|
||||
res.compression = getString(valueAt(json, "compression"));
|
||||
|
||||
if (json.contains("downloadHash"))
|
||||
res.fileHash = Hash::parseAny(
|
||||
static_cast<const std::string &>(
|
||||
ensureType(valueAt(json, "downloadHash"), value_t::string)),
|
||||
getString(valueAt(json, "downloadHash")),
|
||||
std::nullopt);
|
||||
|
||||
if (json.contains("downloadSize"))
|
||||
res.fileSize = ensureType(valueAt(json, "downloadSize"), value_t::number_integer);
|
||||
res.fileSize = getInteger(valueAt(json, "downloadSize"));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,23 +190,18 @@ nlohmann::json UnkeyedValidPathInfo::toJSON(
|
|||
|
||||
UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(
|
||||
const Store & store,
|
||||
const nlohmann::json & json)
|
||||
const nlohmann::json & _json)
|
||||
{
|
||||
using nlohmann::detail::value_t;
|
||||
|
||||
UnkeyedValidPathInfo res {
|
||||
Hash(Hash::dummy),
|
||||
};
|
||||
|
||||
ensureType(json, value_t::object);
|
||||
res.narHash = Hash::parseAny(
|
||||
static_cast<const std::string &>(
|
||||
ensureType(valueAt(json, "narHash"), value_t::string)),
|
||||
std::nullopt);
|
||||
res.narSize = ensureType(valueAt(json, "narSize"), value_t::number_integer);
|
||||
auto & json = getObject(_json);
|
||||
res.narHash = Hash::parseAny(getString(valueAt(json, "narHash")), std::nullopt);
|
||||
res.narSize = getInteger(valueAt(json, "narSize"));
|
||||
|
||||
try {
|
||||
auto & references = ensureType(valueAt(json, "references"), value_t::array);
|
||||
auto references = getStringList(valueAt(json, "references"));
|
||||
for (auto & input : references)
|
||||
res.references.insert(store.parseStorePath(static_cast<const std::string &>
|
||||
(input)));
|
||||
|
|
@ -216,20 +211,16 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(
|
|||
}
|
||||
|
||||
if (json.contains("ca"))
|
||||
res.ca = ContentAddress::parse(
|
||||
static_cast<const std::string &>(
|
||||
ensureType(valueAt(json, "ca"), value_t::string)));
|
||||
res.ca = ContentAddress::parse(getString(valueAt(json, "ca")));
|
||||
|
||||
if (json.contains("deriver"))
|
||||
res.deriver = store.parseStorePath(
|
||||
static_cast<const std::string &>(
|
||||
ensureType(valueAt(json, "deriver"), value_t::string)));
|
||||
res.deriver = store.parseStorePath(getString(valueAt(json, "deriver")));
|
||||
|
||||
if (json.contains("registrationTime"))
|
||||
res.registrationTime = ensureType(valueAt(json, "registrationTime"), value_t::number_integer);
|
||||
res.registrationTime = getInteger(valueAt(json, "registrationTime"));
|
||||
|
||||
if (json.contains("ultimate"))
|
||||
res.ultimate = ensureType(valueAt(json, "ultimate"), value_t::boolean);
|
||||
res.ultimate = getBoolean(valueAt(json, "ultimate"));
|
||||
|
||||
if (json.contains("signatures"))
|
||||
res.sigs = valueAt(json, "signatures");
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ std::string optimisticLockProfile(const Path & profile)
|
|||
Path profilesDir()
|
||||
{
|
||||
auto profileRoot =
|
||||
(getuid() == 0)
|
||||
isRootUser()
|
||||
? rootProfilesDir()
|
||||
: createNixStateDir() + "/profiles";
|
||||
createDirs(profileRoot);
|
||||
|
|
@ -332,7 +332,7 @@ Path getDefaultProfile()
|
|||
// Backwards compatibiliy measure: Make root's profile available as
|
||||
// `.../default` as it's what NixOS and most of the init scripts expect
|
||||
Path globalProfileLink = settings.nixStateDir + "/profiles/default";
|
||||
if (getuid() == 0 && !pathExists(globalProfileLink)) {
|
||||
if (isRootUser() && !pathExists(globalProfileLink)) {
|
||||
replaceSymlink(profile, globalProfileLink);
|
||||
}
|
||||
return absPath(readLink(profileLink), dirOf(profileLink));
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <sqlite3.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
@ -256,10 +257,8 @@ void handleSQLiteBusy(const SQLiteBusy & e, time_t & nextWarning)
|
|||
/* Sleep for a while since retrying the transaction right away
|
||||
is likely to fail again. */
|
||||
checkInterrupt();
|
||||
struct timespec t;
|
||||
t.tv_sec = 0;
|
||||
t.tv_nsec = (random() % 100) * 1000 * 1000; /* <= 0.1s */
|
||||
nanosleep(&t, 0);
|
||||
/* <= 0.1s */
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds { rand() % 100 });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1307,7 +1307,7 @@ std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Para
|
|||
#if __linux__
|
||||
else if (!pathExists(stateDir)
|
||||
&& params.empty()
|
||||
&& getuid() != 0
|
||||
&& !isRootUser()
|
||||
&& !getEnv("NIX_STORE_DIR").has_value()
|
||||
&& !getEnv("NIX_STATE_DIR").has_value())
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue