aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuillaume Maudoux <guillaume.maudoux@tweag.io>2022-10-16 20:39:19 +0200
committerGuillaume Maudoux <guillaume.maudoux@tweag.io>2022-10-16 20:39:19 +0200
commit3f9f6ae12712b366c038f21de99c8ede6c805be9 (patch)
treef2510a23941efd48c102580fc945107c5cb32e12 /src
parent96f2dd99d39da61706895b05ed864558679fac79 (diff)
parent3093bd3a855b8fa1f572fd5a33c1971adf5e3e08 (diff)
Merge remote-tracking branch 'origin/master' into coerce-string
Diffstat (limited to 'src')
-rw-r--r--src/libcmd/command.cc3
-rw-r--r--src/libcmd/common-eval-args.cc2
-rw-r--r--src/libcmd/common-eval-args.hh2
-rw-r--r--src/libcmd/repl.cc8
-rw-r--r--src/libexpr/fetchurl.nix8
-rw-r--r--src/libexpr/flake/config.cc2
-rw-r--r--src/libexpr/flake/flake.cc4
-rw-r--r--src/libexpr/flake/lockfile.cc2
-rw-r--r--src/libexpr/primops.cc8
-rw-r--r--src/libmain/common-args.cc1
-rw-r--r--src/libmain/common-args.hh1
-rw-r--r--src/libmain/progress-bar.cc2
-rw-r--r--src/libmain/shared.cc3
-rw-r--r--src/libmain/shared.hh20
-rw-r--r--src/libmain/stack.cc12
-rw-r--r--src/libstore/build/local-derivation-goal.cc15
-rw-r--r--src/libstore/daemon.cc2
-rw-r--r--src/libstore/filetransfer.cc1
-rw-r--r--src/libstore/gc.cc11
-rw-r--r--src/libstore/globals.cc10
-rw-r--r--src/libstore/globals.hh20
-rw-r--r--src/libstore/local-store.cc38
-rw-r--r--src/libstore/local-store.hh2
-rw-r--r--src/libstore/nar-accessor.cc3
-rw-r--r--src/libstore/store-api.cc4
-rw-r--r--src/libutil/archive.cc7
-rw-r--r--src/libutil/archive.hh1
-rw-r--r--src/libutil/args.cc6
-rw-r--r--src/libutil/util.cc38
-rw-r--r--src/libutil/util.hh8
-rw-r--r--src/nix-build/nix-build.cc4
-rw-r--r--src/nix/develop.cc1
-rw-r--r--src/nix/develop.md6
-rw-r--r--src/nix/main.cc8
-rw-r--r--src/nix/make-content-addressed.md2
-rw-r--r--src/nix/shell.md6
-rw-r--r--src/nix/verify.cc2
37 files changed, 205 insertions, 68 deletions
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 14bb27936..1fdd9e0bd 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -88,7 +88,8 @@ EvalCommand::EvalCommand()
{
addFlag({
.longName = "debugger",
- .description = "start an interactive environment if evaluation fails",
+ .description = "Start an interactive environment if evaluation fails.",
+ .category = MixEvalArgs::category,
.handler = {&startReplOnEvalErrors, true},
});
}
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 5b6e82388..140ed3b88 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -13,8 +13,6 @@ namespace nix {
MixEvalArgs::MixEvalArgs()
{
- auto category = "Common evaluation options";
-
addFlag({
.longName = "arg",
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh
index 03fa226aa..1ec800613 100644
--- a/src/libcmd/common-eval-args.hh
+++ b/src/libcmd/common-eval-args.hh
@@ -10,6 +10,8 @@ class Bindings;
struct MixEvalArgs : virtual Args
{
+ static constexpr auto category = "Common evaluation options";
+
MixEvalArgs();
Bindings * getAutoArgs(EvalState & state);
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index a8de6b80b..4a89f3e28 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -242,7 +242,11 @@ void NixRepl::mainLoop()
// Allow nix-repl specific settings in .inputrc
rl_readline_name = "nix-repl";
- createDirs(dirOf(historyFile));
+ try {
+ createDirs(dirOf(historyFile));
+ } catch (SysError & e) {
+ logWarning(e.info());
+ }
#ifndef READLINE
el_hist_size = 1000;
#endif
@@ -1046,7 +1050,7 @@ struct CmdRepl : InstallablesCommand
evalSettings.pureEval = false;
}
- void prepare()
+ void prepare() override
{
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
warn("future versions of Nix will require using `--file` to load a file");
diff --git a/src/libexpr/fetchurl.nix b/src/libexpr/fetchurl.nix
index 02531103b..9d1b61d7f 100644
--- a/src/libexpr/fetchurl.nix
+++ b/src/libexpr/fetchurl.nix
@@ -12,13 +12,13 @@
, executable ? false
, unpack ? false
, name ? baseNameOf (toString url)
+, impure ? false
}:
-derivation {
+derivation ({
builder = "builtin:fetchurl";
# New-style output content requirements.
- inherit outputHashAlgo outputHash;
outputHashMode = if unpack || executable then "recursive" else "flat";
inherit name url executable unpack;
@@ -38,4 +38,6 @@ derivation {
# To make "nix-prefetch-url" work.
urls = [ url ];
-}
+} // (if impure
+ then { __impure = true; }
+ else { inherit outputHashAlgo outputHash; }))
diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc
index 3e9d264b4..6df95f1f0 100644
--- a/src/libexpr/flake/config.cc
+++ b/src/libexpr/flake/config.cc
@@ -68,7 +68,7 @@ void ConfigFile::apply()
}
}
if (!trusted) {
- warn("ignoring untrusted flake configuration setting '%s'", name);
+ warn("ignoring untrusted flake configuration setting '%s'.\nPass '%s' to trust it", name, "--accept-flake-config");
continue;
}
}
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 06562f614..a9f15b0f6 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -483,12 +483,12 @@ LockedFlake lockFlake(
} else if (auto follows = std::get_if<1>(&i.second)) {
if (! trustLock) {
// It is possible that the flake has changed,
- // so we must confirm all the follows that are in the lockfile are also in the flake.
+ // so we must confirm all the follows that are in the lock file are also in the flake.
auto overridePath(inputPath);
overridePath.push_back(i.first);
auto o = overrides.find(overridePath);
// If the override disappeared, we have to refetch the flake,
- // since some of the inputs may not be present in the lockfile.
+ // since some of the inputs may not be present in the lock file.
if (o == overrides.end()) {
mustRefetch = true;
// There's no point populating the rest of the fake inputs,
diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc
index 60b52d578..629d2e669 100644
--- a/src/libexpr/flake/lockfile.cc
+++ b/src/libexpr/flake/lockfile.cc
@@ -36,7 +36,7 @@ LockedNode::LockedNode(const nlohmann::json & json)
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
{
if (!lockedRef.input.isLocked())
- throw Error("lockfile contains mutable lock '%s'",
+ throw Error("lock file contains mutable lock '%s'",
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 5ce0f4015..9be4bbf6a 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -2423,8 +2423,8 @@ static RegisterPrimOp primop_intersectAttrs({
.name = "__intersectAttrs",
.args = {"e1", "e2"},
.doc = R"(
- Return a set consisting of the attributes in the set *e2* that also
- exist in the set *e1*.
+ Return a set consisting of the attributes in the set *e2* which have the
+ same name as some attribute in *e1*.
)",
.fun = prim_intersectAttrs,
});
@@ -3818,8 +3818,8 @@ static RegisterPrimOp primop_parseDrvName({
.args = {"s"},
.doc = R"(
Split the string *s* into a package name and version. The package
- name is everything up to but not including the first dash followed
- by a digit, and the version is everything following that dash. The
+ name is everything up to but not including the first dash not followed
+ by a letter, and the version is everything following that dash. The
result is returned in a set `{ name, version }`. Thus,
`builtins.parseDrvName "nix-0.12pre12876"` returns `{ name =
"nix"; version = "0.12pre12876"; }`.
diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc
index 12f5403ea..f92920d18 100644
--- a/src/libmain/common-args.cc
+++ b/src/libmain/common-args.cc
@@ -32,6 +32,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
addFlag({
.longName = "option",
.description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).",
+ .category = miscCategory,
.labels = {"name", "value"},
.handler = {[](std::string name, std::string value) {
try {
diff --git a/src/libmain/common-args.hh b/src/libmain/common-args.hh
index 25453b8c6..f180d83ce 100644
--- a/src/libmain/common-args.hh
+++ b/src/libmain/common-args.hh
@@ -6,6 +6,7 @@ namespace nix {
//static constexpr auto commonArgsCategory = "Miscellaneous common options";
static constexpr auto loggingCategory = "Logging-related options";
+static constexpr auto miscCategory = "Miscellaneous global options";
class MixCommonArgs : public virtual Args
{
diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc
index 0bbeaff8d..961f4e18a 100644
--- a/src/libmain/progress-bar.cc
+++ b/src/libmain/progress-bar.cc
@@ -503,7 +503,7 @@ public:
return s[0];
}
- virtual void setPrintBuildLogs(bool printBuildLogs)
+ void setPrintBuildLogs(bool printBuildLogs) override
{
this->printBuildLogs = printBuildLogs;
}
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 52b75f757..c1cf38565 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -4,6 +4,7 @@
#include "gc-store.hh"
#include "util.hh"
#include "loggers.hh"
+#include "progress-bar.hh"
#include <algorithm>
#include <cctype>
@@ -422,6 +423,8 @@ RunPager::RunPager()
if (!pager) pager = getenv("PAGER");
if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return;
+ stopProgressBar();
+
Pipe toPager;
toPager.create();
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index 0cc56d47d..3c37fd627 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -113,5 +113,25 @@ struct PrintFreed
/* Install a SIGSEGV handler to detect stack overflows. */
void detectStackOverflow();
+/* Pluggable behavior to run in case of a stack overflow.
+
+ Default value: defaultStackOverflowHandler.
+
+ This is called by the handler installed by detectStackOverflow().
+
+ This gives Nix library consumers a limit opportunity to report the error
+ condition. The handler should exit the process.
+ See defaultStackOverflowHandler() for a reference implementation.
+
+ NOTE: Use with diligence, because this runs in the signal handler, with very
+ limited stack space and a potentially a corrupted heap, all while the failed
+ thread is blocked indefinitely. All functions called must be reentrant. */
+extern std::function<void(siginfo_t * info, void * ctx)> stackOverflowHandler;
+
+/* The default, robust implementation of stackOverflowHandler.
+
+ Prints an error message directly to stderr using a syscall instead of the
+ logger. Exits the process immediately after. */
+void defaultStackOverflowHandler(siginfo_t * info, void * ctx);
}
diff --git a/src/libmain/stack.cc b/src/libmain/stack.cc
index b0a4a4c5d..10f71c1dc 100644
--- a/src/libmain/stack.cc
+++ b/src/libmain/stack.cc
@@ -1,4 +1,5 @@
#include "error.hh"
+#include "shared.hh"
#include <cstring>
#include <cstddef>
@@ -29,9 +30,7 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
ptrdiff_t diff = (char *) info->si_addr - sp;
if (diff < 0) diff = -diff;
if (diff < 4096) {
- char msg[] = "error: stack overflow (possible infinite recursion)\n";
- [[gnu::unused]] auto res = write(2, msg, strlen(msg));
- _exit(1); // maybe abort instead?
+ nix::stackOverflowHandler(info, ctx);
}
}
@@ -67,5 +66,12 @@ void detectStackOverflow()
#endif
}
+std::function<void(siginfo_t * info, void * ctx)> stackOverflowHandler(defaultStackOverflowHandler);
+
+void defaultStackOverflowHandler(siginfo_t * info, void * ctx) {
+ char msg[] = "error: stack overflow (possible infinite recursion)\n";
+ [[gnu::unused]] auto res = write(2, msg, strlen(msg));
+ _exit(1); // maybe abort instead?
+}
}
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 18b682e13..5cea3b590 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -1594,6 +1594,8 @@ void LocalDerivationGoal::runChild()
/* Warning: in the child we should absolutely not make any SQLite
calls! */
+ bool sendException = true;
+
try { /* child */
commonChildInit(builderOut);
@@ -2050,6 +2052,8 @@ void LocalDerivationGoal::runChild()
/* Indicate that we managed to set up the build environment. */
writeFull(STDERR_FILENO, std::string("\2\n"));
+ sendException = false;
+
/* Execute the program. This should not return. */
if (drv->isBuiltin()) {
try {
@@ -2103,10 +2107,13 @@ void LocalDerivationGoal::runChild()
throw SysError("executing '%1%'", drv->builder);
} catch (Error & e) {
- writeFull(STDERR_FILENO, "\1\n");
- FdSink sink(STDERR_FILENO);
- sink << e;
- sink.flush();
+ if (sendException) {
+ writeFull(STDERR_FILENO, "\1\n");
+ FdSink sink(STDERR_FILENO);
+ sink << e;
+ sink.flush();
+ } else
+ std::cerr << e.msg();
_exit(1);
}
}
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index de69b50ee..48dd5c247 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -239,6 +239,8 @@ struct ClientSettings
else if (trusted
|| name == settings.buildTimeout.name
|| name == settings.buildRepeat.name
+ || name == settings.maxSilentTime.name
+ || name == settings.pollInterval.name
|| name == "connect-timeout"
|| (name == "builders" && value == ""))
settings.set(name, value);
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 252403cb5..5746c32a3 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -322,7 +322,6 @@ struct curlFileTransfer : public FileTransfer
}
if (request.verifyTLS) {
- debug("verify TLS: Nix CA file = '%s'", settings.caFile);
if (settings.caFile != "")
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
} else {
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 4c1a82279..9ef8972f3 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -619,6 +619,17 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
Path path = storeDir + "/" + std::string(baseName);
Path realPath = realStoreDir + "/" + std::string(baseName);
+ /* There may be temp directories in the store that are still in use
+ by another process. We need to be sure that we can acquire an
+ exclusive lock before deleting them. */
+ if (baseName.find("tmp-", 0) == 0) {
+ AutoCloseFD tmpDirFd = open(realPath.c_str(), O_RDONLY | O_DIRECTORY);
+ if (tmpDirFd.get() == -1 || !lockFile(tmpDirFd.get(), ltWrite, false)) {
+ debug("skipping locked tempdir '%s'", realPath);
+ return;
+ }
+ }
+
printInfo("deleting '%1%'", path);
results.paths.insert(path);
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index d724897bb..ff658c428 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -154,13 +154,9 @@ StringSet Settings::getDefaultExtraPlatforms()
// machines. Note that we can’t force processes from executing
// x86_64 in aarch64 environments or vice versa since they can
// always exec with their own binary preferences.
- if (pathExists("/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plist") ||
- pathExists("/System/Library/LaunchDaemons/com.apple.oahd.plist")) {
- if (std::string{SYSTEM} == "x86_64-darwin")
- extraPlatforms.insert("aarch64-darwin");
- else if (std::string{SYSTEM} == "aarch64-darwin")
- extraPlatforms.insert("x86_64-darwin");
- }
+ if (std::string{SYSTEM} == "aarch64-darwin" &&
+ runProgram(RunOptions {.program = "arch", .args = {"-arch", "x86_64", "/usr/bin/true"}, .mergeStderrToStdout = true}).first == 0)
+ extraPlatforms.insert("x86_64-darwin");
#endif
return extraPlatforms;
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index e9d721e59..3dcf3d479 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -560,9 +560,15 @@ public:
R"(
If set to `true` (the default), any non-content-addressed path added
or copied to the Nix store (e.g. when substituting from a binary
- cache) must have a valid signature, that is, be signed using one of
- the keys listed in `trusted-public-keys` or `secret-key-files`. Set
- to `false` to disable signature checking.
+ cache) must have a signature by a trusted key. A trusted key is one
+ listed in `trusted-public-keys`, or a public key counterpart to a
+ private key stored in a file listed in `secret-key-files`.
+
+ Set to `false` to disable signature checking and trust all
+ non-content-addressed paths unconditionally.
+
+ (Content-addressed paths are inherently trustworthy and thus
+ unaffected by this configuration option.)
)"};
Setting<StringSet> extraPlatforms{
@@ -613,6 +619,14 @@ public:
are tried based on their Priority value, which each substituter can set
independently. Lower value means higher priority.
The default is `https://cache.nixos.org`, with a Priority of 40.
+
+ Nix will copy a store path from a remote store only if one
+ of the following is true:
+
+ - the store object is signed by one of the [`trusted-public-keys`](#conf-trusted-public-keys)
+ - the substituter is in the [`trusted-substituters`](#conf-trusted-substituters) list
+ - the [`require-sigs`](#conf-require-sigs) option has been set to `false`
+ - the store object is [output-addressed](glossary.md#gloss-output-addressed-store-object)
)",
{"binary-caches"}};
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index a272e4301..d374d4558 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -158,7 +158,7 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
txn.commit();
}
- writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
+ writeFile(schemaPath, fmt("%d", nixCASchemaVersion), 0666, true);
lockFile(lockFd.get(), ltRead, true);
}
}
@@ -281,7 +281,7 @@ LocalStore::LocalStore(const Params & params)
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion;
openDB(*state, true);
- writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
+ writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
}
else if (curSchema < nixSchemaVersion) {
@@ -329,7 +329,7 @@ LocalStore::LocalStore(const Params & params)
txn.commit();
}
- writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
+ writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
lockFile(globalLock.get(), ltRead, true);
}
@@ -751,7 +751,7 @@ void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag check
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
registerDrvOutput(info);
else
- throw Error("cannot register realisation '%s' because it lacks a valid signature", info.outPath.to_string());
+ throw Error("cannot register realisation '%s' because it lacks a signature by a trusted key", info.outPath.to_string());
}
void LocalStore::registerDrvOutput(const Realisation & info)
@@ -1266,7 +1266,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
RepairFlag repair, CheckSigsFlag checkSigs)
{
if (checkSigs && pathInfoIsUntrusted(info))
- throw Error("cannot add path '%s' because it lacks a valid signature", printStorePath(info.path));
+ throw Error("cannot add path '%s' because it lacks a signature by a trusted key", printStorePath(info.path));
addTempRoot(info.path);
@@ -1382,13 +1382,15 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
std::unique_ptr<AutoDelete> delTempDir;
Path tempPath;
+ Path tempDir;
+ AutoCloseFD tempDirFd;
if (!inMemory) {
/* Drain what we pulled so far, and then keep on pulling */
StringSource dumpSource { dump };
ChainSource bothSource { dumpSource, source };
- auto tempDir = createTempDir(realStoreDir, "add");
+ std::tie(tempDir, tempDirFd) = createTempDirInStore();
delTempDir = std::make_unique<AutoDelete>(tempDir);
tempPath = tempDir + "/x";
@@ -1507,18 +1509,24 @@ StorePath LocalStore::addTextToStore(
/* Create a temporary directory in the store that won't be
- garbage-collected. */
-Path LocalStore::createTempDirInStore()
+ garbage-collected until the returned FD is closed. */
+std::pair<Path, AutoCloseFD> LocalStore::createTempDirInStore()
{
- Path tmpDir;
+ Path tmpDirFn;
+ AutoCloseFD tmpDirFd;
+ bool lockedByUs = false;
do {
/* There is a slight possibility that `tmpDir' gets deleted by
- the GC between createTempDir() and addTempRoot(), so repeat
- until `tmpDir' exists. */
- tmpDir = createTempDir(realStoreDir);
- addTempRoot(parseStorePath(tmpDir));
- } while (!pathExists(tmpDir));
- return tmpDir;
+ the GC between createTempDir() and when we acquire a lock on it.
+ We'll repeat until 'tmpDir' exists and we've locked it. */
+ tmpDirFn = createTempDir(realStoreDir, "tmp");
+ tmpDirFd = open(tmpDirFn.c_str(), O_RDONLY | O_DIRECTORY);
+ if (tmpDirFd.get() < 0) {
+ continue;
+ }
+ lockedByUs = lockFile(tmpDirFd.get(), ltWrite, true);
+ } while (!pathExists(tmpDirFn) || !lockedByUs);
+ return {tmpDirFn, std::move(tmpDirFd)};
}
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 70d225be3..bd0ce1fe6 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -256,7 +256,7 @@ private:
void findRuntimeRoots(Roots & roots, bool censor);
- Path createTempDirInStore();
+ std::pair<Path, AutoCloseFD> createTempDirInStore();
void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);
diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc
index 72d41cc94..398147fc3 100644
--- a/src/libstore/nar-accessor.cc
+++ b/src/libstore/nar-accessor.cc
@@ -75,6 +75,9 @@ struct NarAccessor : public FSAccessor
createMember(path, {FSAccessor::Type::tRegular, false, 0, 0});
}
+ void closeRegularFile() override
+ { }
+
void isExecutable() override
{
parents.top()->isExecutable = true;
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 86b12257a..06a9758fc 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -1363,9 +1363,9 @@ std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Para
} catch (Error & e) {
return std::make_shared<LocalStore>(params);
}
- warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
+ warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
} else
- debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
+ debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
Store::Params params2;
params2["root"] = chrootStore;
return std::make_shared<LocalStore>(params2);
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 30b471af5..4b0636129 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -234,6 +234,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
else if (s == "contents" && type == tpRegular) {
parseContents(sink, source, path);
+ sink.closeRegularFile();
}
else if (s == "executable" && type == tpRegular) {
@@ -324,6 +325,12 @@ struct RestoreSink : ParseSink
if (!fd) throw SysError("creating file '%1%'", p);
}
+ void closeRegularFile() override
+ {
+ /* Call close explicitly to make sure the error is checked */
+ fd.close();
+ }
+
void isExecutable() override
{
struct stat st;
diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh
index 79ce08df0..ac4183bf5 100644
--- a/src/libutil/archive.hh
+++ b/src/libutil/archive.hh
@@ -60,6 +60,7 @@ struct ParseSink
virtual void createDirectory(const Path & path) { };
virtual void createRegularFile(const Path & path) { };
+ virtual void closeRegularFile() { };
virtual void isExecutable() { };
virtual void preallocateContents(uint64_t size) { };
virtual void receiveContents(std::string_view data) { };
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 44b63f0f6..753980fd4 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -216,7 +216,7 @@ nlohmann::json Args::toJSON()
if (flag->shortName)
j["shortName"] = std::string(1, flag->shortName);
if (flag->description != "")
- j["description"] = flag->description;
+ j["description"] = trim(flag->description);
j["category"] = flag->category;
if (flag->handler.arity != ArityAny)
j["arity"] = flag->handler.arity;
@@ -237,7 +237,7 @@ nlohmann::json Args::toJSON()
}
auto res = nlohmann::json::object();
- res["description"] = description();
+ res["description"] = trim(description());
res["flags"] = std::move(flags);
res["args"] = std::move(args);
auto s = doc();
@@ -379,7 +379,7 @@ nlohmann::json MultiCommand::toJSON()
auto j = command->toJSON();
auto cat = nlohmann::json::object();
cat["id"] = command->category();
- cat["description"] = categories[command->category()];
+ cat["description"] = trim(categories[command->category()]);
j["category"] = std::move(cat);
cmds[name] = std::move(j);
}
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 96ac11ea2..623b74bdd 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -353,7 +353,7 @@ void readFile(const Path & path, Sink & sink)
}
-void writeFile(const Path & path, std::string_view s, mode_t mode)
+void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
@@ -364,10 +364,16 @@ void writeFile(const Path & path, std::string_view s, mode_t mode)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
+ if (sync)
+ fd.fsync();
+ // Explicitly close to make sure exceptions are propagated.
+ fd.close();
+ if (sync)
+ syncParent(path);
}
-void writeFile(const Path & path, Source & source, mode_t mode)
+void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
{
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
if (!fd)
@@ -386,6 +392,20 @@ void writeFile(const Path & path, Source & source, mode_t mode)
e.addTrace({}, "writing file '%1%'", path);
throw;
}
+ if (sync)
+ fd.fsync();
+ // Explicitly close to make sure exceptions are propagated.
+ fd.close();
+ if (sync)
+ syncParent(path);
+}
+
+void syncParent(const Path & path)
+{
+ AutoCloseFD fd = open(dirOf(path).c_str(), O_RDONLY, 0);
+ if (!fd)
+ throw SysError("opening file '%1%'", path);
+ fd.fsync();
}
std::string readLine(int fd)
@@ -841,6 +861,20 @@ void AutoCloseFD::close()
}
}
+void AutoCloseFD::fsync()
+{
+ if (fd != -1) {
+ int result;
+#if __APPLE__
+ result = ::fcntl(fd, F_FULLFSYNC);
+#else
+ result = ::fsync(fd);
+#endif
+ if (result == -1)
+ throw SysError("fsync file descriptor %1%", fd);
+ }
+}
+
AutoCloseFD::operator bool() const
{
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index cd83f250f..e5c678682 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -115,9 +115,12 @@ std::string readFile(const Path & path);
void readFile(const Path & path, Sink & sink);
/* Write a string to a file. */
-void writeFile(const Path & path, std::string_view s, mode_t mode = 0666);
+void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
-void writeFile(const Path & path, Source & source, mode_t mode = 0666);
+void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
+
+/* Flush a file's parent directory to disk */
+void syncParent(const Path & path);
/* Read a line from a file descriptor. */
std::string readLine(int fd);
@@ -231,6 +234,7 @@ public:
explicit operator bool() const;
int release();
void close();
+ void fsync();
};
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index df292dce6..adcaab686 100644
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -85,7 +85,6 @@ static void main_nix_build(int argc, char * * argv)
Strings attrPaths;
Strings left;
RepairFlag repair = NoRepair;
- Path gcRoot;
BuildMode buildMode = bmNormal;
bool readStdin = false;
@@ -167,9 +166,6 @@ static void main_nix_build(int argc, char * * argv)
else if (*arg == "--out-link" || *arg == "-o")
outLink = getArg(*arg, arg, end);
- else if (*arg == "--add-root")
- gcRoot = getArg(*arg, arg, end);
-
else if (*arg == "--dry-run")
dryRun = true;
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index ba7ba7c25..4de109754 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -246,6 +246,7 @@ struct Common : InstallableCommand, MixProfile
"NIX_LOG_FD",
"NIX_REMOTE",
"PPID",
+ "SHELL",
"SHELLOPTS",
"SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt
"TEMP",
diff --git a/src/nix/develop.md b/src/nix/develop.md
index e036ec6b9..4e8542d1b 100644
--- a/src/nix/develop.md
+++ b/src/nix/develop.md
@@ -66,6 +66,12 @@ R""(
`nixpkgs#glibc` in `~/my-glibc` and want to compile another package
against it.
+* Run a series of script commands:
+
+ ```console
+ # nix develop --command bash -c "mkdir build && cmake .. && make"
+ ```
+
# Description
`nix develop` starts a `bash` shell that provides an interactive build
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 85a3835c2..7172b4bd2 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -74,6 +74,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
addFlag({
.longName = "help",
.description = "Show usage information.",
+ .category = miscCategory,
.handler = {[&]() { throw HelpRequested(); }},
});
@@ -88,6 +89,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
addFlag({
.longName = "version",
.description = "Show version information.",
+ .category = miscCategory,
.handler = {[&]() { showVersion = true; }},
});
@@ -95,12 +97,14 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
.longName = "offline",
.aliases = {"no-net"}, // FIXME: remove
.description = "Disable substituters and consider all previously downloaded files up-to-date.",
+ .category = miscCategory,
.handler = {[&]() { useNet = false; }},
});
addFlag({
.longName = "refresh",
.description = "Consider all previously downloaded files out-of-date.",
+ .category = miscCategory,
.handler = {[&]() { refresh = true; }},
});
}
@@ -187,7 +191,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
*vUtils);
auto attrs = state.buildBindings(16);
- attrs.alloc("command").mkString(toplevel.toJSON().dump());
+ attrs.alloc("toplevel").mkString(toplevel.toJSON().dump());
auto vRes = state.allocValue();
state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);
@@ -325,7 +329,7 @@ void mainWrapped(int argc, char * * argv)
std::cout << "attrs\n"; break;
}
for (auto & s : *completions)
- std::cout << s.completion << "\t" << s.description << "\n";
+ std::cout << s.completion << "\t" << trim(s.description) << "\n";
}
});
diff --git a/src/nix/make-content-addressed.md b/src/nix/make-content-addressed.md
index 215683e6d..32eecc880 100644
--- a/src/nix/make-content-addressed.md
+++ b/src/nix/make-content-addressed.md
@@ -22,7 +22,7 @@ R""(
```console
# nix copy --to /tmp/nix --trusted-public-keys '' nixpkgs#hello
- cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a valid signature
+ cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a signature by a trusted key
```
* Create a content-addressed representation of the current NixOS
diff --git a/src/nix/shell.md b/src/nix/shell.md
index 90b81fb2f..9fa1031f5 100644
--- a/src/nix/shell.md
+++ b/src/nix/shell.md
@@ -23,6 +23,12 @@ R""(
Hi everybody!
```
+* Run multiple commands in a shell environment:
+
+ ```console
+ # nix shell nixpkgs#gnumake -c sh -c "cd src && make"
+ ```
+
* Run GNU Hello in a chroot store:
```console
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index e92df1303..efa2434dc 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -41,7 +41,7 @@ struct CmdVerify : StorePathsCommand
addFlag({
.longName = "sigs-needed",
.shortName = 'n',
- .description = "Require that each path has at least *n* valid signatures.",
+ .description = "Require that each path is signed by at least *n* different keys.",
.labels = {"n"},
.handler = {&sigsNeeded}
});