From d854e7dfd6d512c8ed687b61d7aae3358eda71cd Mon Sep 17 00:00:00 2001 From: Samuel Dionne-Riel Date: Tue, 26 Mar 2019 21:08:22 -0400 Subject: [PATCH 01/33] install-multi-user: Detect and fail lack of systemd separately Otherwise, the user is shown: ``` Sorry, I don't know what to do on Linux ``` Which is... not exactly right. --- scripts/install-multi-user.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh index 4b65783a2..80d1c73fb 100644 --- a/scripts/install-multi-user.sh +++ b/scripts/install-multi-user.sh @@ -753,9 +753,13 @@ main() { if [ "$(uname -s)" = "Darwin" ]; then # shellcheck source=./install-darwin-multi-user.sh . "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh" - elif [ "$(uname -s)" = "Linux" ] && [ -e /run/systemd/system ]; then - # shellcheck source=./install-systemd-multi-user.sh - . "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh" + elif [ "$(uname -s)" = "Linux" ]; then + if [ -e /run/systemd/system ]; then + # shellcheck source=./install-systemd-multi-user.sh + . "$EXTRACTED_NIX_PATH/install-systemd-multi-user.sh" + else + failure "Sorry, the multi-user installation requires systemd on Linux (detected using /run/systemd/system)" + fi else failure "Sorry, I don't know what to do on $(uname)" fi From 4a3e96281d6b9ae3dbc20e638f389677df9a649e Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Wed, 5 Jun 2019 00:40:45 -0400 Subject: [PATCH 02/33] Handle SIGWINCH in main thread For the SIGWINCH signal to be caught, it needs to be set in sigaction on the main thread. Previously, this was broken, and updateWindowSize was never being called. Tested on macOS 10.14. --- src/libmain/shared.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 4ed34e54d..f2aeec9e1 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -125,6 +125,9 @@ void initNix() act.sa_handler = sigHandler; if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1"); + /* Make sure SIGWINCH is handled as well. */ + if (sigaction(SIGWINCH, &act, 0)) throw SysError("handling SIGWINCH"); + /* Register a SIGSEGV handler to detect stack overflows. */ detectStackOverflow(); From 5011a52cf3f291c22d784aff6f5bbf8b99ae186a Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Wed, 5 Jun 2019 20:18:47 -0400 Subject: [PATCH 03/33] Just enable hack on macOS This is not needed on linux at all! Tried to explain as much as I understand with the problem. --- src/libmain/shared.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index f2aeec9e1..a6101342a 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -125,8 +125,14 @@ void initNix() act.sa_handler = sigHandler; if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1"); - /* Make sure SIGWINCH is handled as well. */ - if (sigaction(SIGWINCH, &act, 0)) throw SysError("handling SIGWINCH"); +#if __APPLE__ + /* HACK: on darwin, we need can’t use sigprocmask with SIGWINCH. + * Instead, add a dummy sigaction handler, and signalHandlerThread + * can handle the rest. */ + struct sigaction sa; + sa.sa_handler = sigHandler; + if (sigaction(SIGWINCH, &sa, 0)) throw SysError("handling SIGWINCH"); +#endif /* Register a SIGSEGV handler to detect stack overflows. */ detectStackOverflow(); From d171090530f4a2a79efec2c385bee1a10844c706 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Thu, 25 Jul 2019 09:37:57 -0400 Subject: [PATCH 04/33] =?UTF-8?q?Disable=20CLONE=5FNEWUSER=20when=20it?= =?UTF-8?q?=E2=80=99s=20unavailable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some kernels disable "unpriveleged user namespaces". This is unfortunate, but we can still use mount namespaces. Anyway, since each builder has its own nixbld user, we already have most of the benefits of user namespaces. --- src/libstore/build.cc | 14 ++++++++++++-- src/nix/run.cc | 5 ++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index cf6428e12..c10005839 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2302,10 +2302,20 @@ void DerivationGoal::startBuilder() flags |= CLONE_NEWNET; pid_t child = clone(childEntry, stack + stackSize, flags, this); - if (child == -1 && errno == EINVAL) + if (child == -1 && errno == EINVAL) { /* Fallback for Linux < 2.13 where CLONE_NEWPID and CLONE_PARENT are not allowed together. */ - child = clone(childEntry, stack + stackSize, flags & ~CLONE_NEWPID, this); + flags &= ~CLONE_NEWPID; + child = clone(childEntry, stack + stackSize, flags, this); + } + if (child == -1 && (errno == EPERM || errno == EINVAL)) { + /* Some distros patch Linux to not allow unpriveleged + * user namespaces. If we get EPERM or EINVAL, try + * without CLONE_NEWUSER and see if that works. + */ + flags &= ~CLONE_NEWUSER; + child = clone(childEntry, stack + stackSize, flags, this); + } if (child == -1) throw SysError("cloning builder process"); writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n"); diff --git a/src/nix/run.cc b/src/nix/run.cc index 35b763345..90b76d666 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -199,7 +199,10 @@ void chrootHelper(int argc, char * * argv) uid_t gid = getgid(); if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == -1) - throw SysError("setting up a private mount namespace"); + /* Try with just CLONE_NEWNS in case user namespaces are + specifically disabled. */ + if (unshare(CLONE_NEWNS) == -1) + throw SysError("setting up a private mount namespace"); /* Bind-mount realStoreDir on /nix/store. If the latter mount point doesn't already exists, we have to create a chroot From 11d853462925d0b57fe956962e07edf5751fd4c3 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Thu, 25 Jul 2019 14:29:58 -0400 Subject: [PATCH 05/33] Use sandbox fallback when cloning fails in builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When sandbox-fallback = true (the default), the Nix builder will fall back to disabled sandbox mode when the kernel doesn’t allow users to set it up. This prevents hard errors from occuring in tricky places, especially the initial installer. To restore the previous behavior, users can set: sandbox-fallback = false in their /etc/nix/nix.conf configuration. --- src/libstore/build.cc | 12 +++++++++++- src/libstore/globals.hh | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index c10005839..dd08ce7d7 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2316,13 +2316,22 @@ void DerivationGoal::startBuilder() flags &= ~CLONE_NEWUSER; child = clone(childEntry, stack + stackSize, flags, this); } + /* 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 (child == -1 && (errno == EPERM || errno == EINVAL) && settings.sandboxFallback) + _exit(EPERM); if (child == -1) throw SysError("cloning builder process"); writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n"); _exit(0); }, options); - if (helper.wait() != 0) + int res = helper.wait(); + if (res == EPERM && settings.sandboxFallback) { + useChroot = false; + goto fallback; + } else if (res != 0) throw Error("unable to start build process"); userNamespaceSync.readSide = -1; @@ -2353,6 +2362,7 @@ void DerivationGoal::startBuilder() } else #endif { + fallback: options.allowVfork = !buildUser && !drv->isBuiltin(); pid = startProcess([&]() { runChild(); diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index 0af8215d1..cc9534b27 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -209,6 +209,9 @@ public: "The paths to make available inside the build sandbox.", {"build-chroot-dirs", "build-sandbox-paths"}}; + Setting sandboxFallback{this, true, "sandbox-fallback", + "Whether to disable sandboxing when the kernel doesn't allow it."}; + Setting extraSandboxPaths{this, {}, "extra-sandbox-paths", "Additional paths to make available inside the build sandbox.", {"build-extra-chroot-dirs", "build-extra-sandbox-paths"}}; From 9a0855bbb6546e792848e551e79f8efc40782eeb Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Tue, 30 Jul 2019 17:52:42 -0400 Subject: [PATCH 06/33] =?UTF-8?q?Don=E2=80=99t=20rely=20on=20EPERM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit startProcess does not appear to send the exit code to the helper correctly. Not sure why this is, but it is probably safe to just fallback on all sandbox errors. --- src/libstore/build.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index dd08ce7d7..0f71e7511 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2320,7 +2320,7 @@ void DerivationGoal::startBuilder() parent. This is only done when sandbox-fallback is set to true (the default). */ if (child == -1 && (errno == EPERM || errno == EINVAL) && settings.sandboxFallback) - _exit(EPERM); + _exit(1); if (child == -1) throw SysError("cloning builder process"); writeFull(builderOut.writeSide.get(), std::to_string(child) + "\n"); @@ -2328,7 +2328,7 @@ void DerivationGoal::startBuilder() }, options); int res = helper.wait(); - if (res == EPERM && settings.sandboxFallback) { + if (res != 0 && settings.sandboxFallback) { useChroot = false; goto fallback; } else if (res != 0) From a02457db715a80de7630d823fd8d7230a4bd451f Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Wed, 7 Aug 2019 15:14:40 -0400 Subject: [PATCH 07/33] conf: stalled-download-timeout: make tunable Make curl's low speed limit configurable via stalled-download-timeout. Before, this limit was five minutes without receiving a single byte. This is much too long as if the remote end may not have even acknowledged the HTTP request. --- doc/manual/command-ref/conf-file.xml | 8 ++++++++ src/libstore/download.cc | 4 +--- src/libstore/download.hh | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml index c7b540892..1325a3f22 100644 --- a/doc/manual/command-ref/conf-file.xml +++ b/doc/manual/command-ref/conf-file.xml @@ -873,6 +873,14 @@ password my-password + stalled-download-timeout + + The timeout (in seconds) for receiving data from servers + during download. Nix cancels idle downloads after this timeout's + duration. + + + substituters A list of URLs of substituters, separated by diff --git a/src/libstore/download.cc b/src/libstore/download.cc index 91087eebc..c322d267d 100644 --- a/src/libstore/download.cc +++ b/src/libstore/download.cc @@ -236,8 +236,6 @@ struct CurlDownloader : public Downloader return ((DownloadItem *) userp)->readCallback(buffer, size, nitems); } - long lowSpeedTimeout = 300; - void init() { if (!req) req = curl_easy_init(); @@ -297,7 +295,7 @@ struct CurlDownloader : public Downloader curl_easy_setopt(req, CURLOPT_CONNECTTIMEOUT, downloadSettings.connectTimeout.get()); curl_easy_setopt(req, CURLOPT_LOW_SPEED_LIMIT, 1L); - curl_easy_setopt(req, CURLOPT_LOW_SPEED_TIME, lowSpeedTimeout); + curl_easy_setopt(req, CURLOPT_LOW_SPEED_TIME, downloadSettings.stalledDownloadTimeout.get()); /* If no file exist in the specified path, curl continues to work anyway as if netrc support was disabled. */ diff --git a/src/libstore/download.hh b/src/libstore/download.hh index 3b7fff3ba..c68381846 100644 --- a/src/libstore/download.hh +++ b/src/libstore/download.hh @@ -24,6 +24,9 @@ struct DownloadSettings : Config Setting connectTimeout{this, 0, "connect-timeout", "Timeout for connecting to servers during downloads. 0 means use curl's builtin default."}; + Setting stalledDownloadTimeout{this, 300, "stalled-download-timeout", + "Timeout (in seconds) for receiving data from servers during download. Nix cancels idle downloads after this timeout's duration."}; + Setting tries{this, 5, "download-attempts", "How often Nix will attempt to download a file before giving up."}; }; From ee9c988a1b2e3c511b8613e698a0f9632ab1538f Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 12 Apr 2019 12:31:33 -0400 Subject: [PATCH 08/33] Track function start and ends for flame graphs With this patch, and this file I called `log.py`: #!/usr/bin/env nix-shell #!nix-shell -i python3 -p python3 --pure import sys from pprint import pprint stack = [] timestack = [] for line in open(sys.argv[1]): components = line.strip().split(" ", 2) if components[0] != "function-trace": continue direction = components[1] components = components[2].rsplit(" ", 2) loc = components[0] _at = components[1] time = int(components[2]) if direction == "entered": stack.append(loc) timestack.append(time) elif direction == "exited": dur = time - timestack.pop() vst = ";".join(stack) print(f"{vst} {dur}") stack.pop() and: nix-instantiate --trace-function-calls -vvvv ../nixpkgs/pkgs/top-level/release.nix -A unstable > log.matthewbauer 2>&1 ./log.py ./log.matthewbauer > log.matthewbauer.folded flamegraph.pl --title matthewbauer-post-pr log.matthewbauer.folded > log.matthewbauer.folded.svg I can make flame graphs like: http://gsc.io/log.matthewbauer.folded.svg --- Includes test cases around function call failures and tryEval. Uses RAII so the finish is always called at the end of the function. --- contrib/stack-collapse.py | 39 +++++++++++++ doc/manual/command-ref/conf-file.xml | 28 +++++++++ src/libexpr/eval.cc | 8 ++- src/libexpr/eval.hh | 4 ++ src/libexpr/function-trace.hh | 24 ++++++++ tests/function-trace.sh | 86 ++++++++++++++++++++++++++++ tests/local.mk | 3 +- 7 files changed, 189 insertions(+), 3 deletions(-) create mode 100755 contrib/stack-collapse.py create mode 100644 src/libexpr/function-trace.hh create mode 100755 tests/function-trace.sh diff --git a/contrib/stack-collapse.py b/contrib/stack-collapse.py new file mode 100755 index 000000000..ee77e1589 --- /dev/null +++ b/contrib/stack-collapse.py @@ -0,0 +1,39 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i python3 -p python3 --pure + +# To be used with `--trace-function-calls` and `-vvvv` and +# `flamegraph.pl`. +# +# For example: +# +# nix-instantiate --trace-function-calls -vvvv '' -A hello 2> nix-function-calls.trace +# ./contrib/stack-collapse.py nix-function-calls.trace > nix-function-calls.folded +# nix-shell -p flamegraph --run "flamegraph.pl nix-function-calls.folded > nix-function-calls.svg" + +import sys +from pprint import pprint +import fileinput + +stack = [] +timestack = [] + +for line in fileinput.input(): + components = line.strip().split(" ", 2) + if components[0] != "function-trace": + continue + + direction = components[1] + components = components[2].rsplit(" ", 2) + + loc = components[0] + _at = components[1] + time = int(components[2]) + + if direction == "entered": + stack.append(loc) + timestack.append(time) + elif direction == "exited": + dur = time - timestack.pop() + vst = ";".join(stack) + print(f"{vst} {dur}") + stack.pop() diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml index c7b540892..407e5d10b 100644 --- a/doc/manual/command-ref/conf-file.xml +++ b/doc/manual/command-ref/conf-file.xml @@ -973,6 +973,34 @@ requiredSystemFeatures = [ "kvm" ]; + trace-function-calls + + + + Default: false. + + If set to true, the Nix evaluator will + trace every function call. Nix will print a log message at the + "vomit" level for every function entrance and function exit. + + +function-trace entered undefined position at 1565795816999559622 +function-trace exited undefined position at 1565795816999581277 +function-trace entered /nix/store/.../example.nix:226:41 at 1565795253249935150 +function-trace exited /nix/store/.../example.nix:226:41 at 1565795253249941684 + + + The undefined position means the function + call is a builtin. + + Use the contrib/stack-collapse.py script + distributed with the Nix source code to convert the trace logs + in to a format suitable for flamegraph.pl. + + + + + trusted-public-keys A whitespace-separated list of public keys. When diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index d8e10d9f2..9f4b6b411 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -9,6 +9,7 @@ #include "json.hh" #include +#include #include #include #include @@ -16,7 +17,6 @@ #include #include -#include #include #if HAVE_BOEHMGC @@ -1094,9 +1094,13 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) } } - void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & pos) { + std::optional trace; + if (evalSettings.traceFunctionCalls) { + trace.emplace(pos); + } + forceValue(fun, pos); if (fun.type == tPrimOp || fun.type == tPrimOpApp) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index a314e01e0..22472fd72 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -6,6 +6,7 @@ #include "symbol-table.hh" #include "hash.hh" #include "config.hh" +#include "function-trace.hh" #include #include @@ -349,6 +350,9 @@ struct EvalSettings : Config Setting allowedUris{this, {}, "allowed-uris", "Prefixes of URIs that builtin functions such as fetchurl and fetchGit are allowed to fetch."}; + + Setting traceFunctionCalls{this, false, "trace-function-calls", + "Emit log messages for each function entry and exit at the 'vomit' log level (-vvvv)"}; }; extern EvalSettings evalSettings; diff --git a/src/libexpr/function-trace.hh b/src/libexpr/function-trace.hh new file mode 100644 index 000000000..8234b7603 --- /dev/null +++ b/src/libexpr/function-trace.hh @@ -0,0 +1,24 @@ +#pragma once + +#include "eval.hh" +#include + +namespace nix { + +struct FunctionCallTrace +{ + const Pos & pos; + + FunctionCallTrace(const Pos & pos) : pos(pos) { + auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); + auto ns = std::chrono::duration_cast(duration); + vomit("function-trace entered %1% at %2%", pos, ns.count()); + } + + ~FunctionCallTrace() { + auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); + auto ns = std::chrono::duration_cast(duration); + vomit("function-trace exited %1% at %2%", pos, ns.count()); + } +}; +} diff --git a/tests/function-trace.sh b/tests/function-trace.sh new file mode 100755 index 000000000..f7d93b435 --- /dev/null +++ b/tests/function-trace.sh @@ -0,0 +1,86 @@ +source common.sh + +set +x + +expect_trace() { + expr="$1" + expect="$2" + actual=$( + nix-instantiate \ + --trace-function-calls \ + -vvvv \ + --expr "$expr" 2>&1 \ + | grep "function-trace" \ + | sed -e 's/ [0-9]*$//' + ); + + echo -n "Tracing expression '$expr'" + set +e + msg=$(diff -swB \ + <(echo "$expect") \ + <(echo "$actual") + ); + result=$? + set -e + if [ $result -eq 0 ]; then + echo " ok." + else + echo " failed. difference:" + echo "$msg" + return $result + fi +} + +# failure inside a tryEval +expect_trace 'builtins.tryEval (throw "example")' " +function-trace entered undefined position at +function-trace exited undefined position at +function-trace entered (string):1:1 at +function-trace entered (string):1:19 at +function-trace exited (string):1:19 at +function-trace exited (string):1:1 at +" + +# Missing argument to a formal function +expect_trace '({ x }: x) { }' " +function-trace entered undefined position at +function-trace exited undefined position at +function-trace entered (string):1:1 at +function-trace exited (string):1:1 at +" + +# Too many arguments to a formal function +expect_trace '({ x }: x) { x = "x"; y = "y"; }' " +function-trace entered undefined position at +function-trace exited undefined position at +function-trace entered (string):1:1 at +function-trace exited (string):1:1 at +" + +# Not enough arguments to a lambda +expect_trace '(x: y: x + y) 1' " +function-trace entered undefined position at +function-trace exited undefined position at +function-trace entered (string):1:1 at +function-trace exited (string):1:1 at +" + +# Too many arguments to a lambda +expect_trace '(x: x) 1 2' " +function-trace entered undefined position at +function-trace exited undefined position at +function-trace entered (string):1:1 at +function-trace exited (string):1:1 at +function-trace entered (string):1:1 at +function-trace exited (string):1:1 at +" + +# Not a function +expect_trace '1 2' " +function-trace entered undefined position at +function-trace exited undefined position at +function-trace entered (string):1:1 at +function-trace exited (string):1:1 at +" + +set -e diff --git a/tests/local.mk b/tests/local.mk index ef359c631..187f96ea2 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -29,7 +29,8 @@ nix_tests = \ plugins.sh \ search.sh \ nix-copy-ssh.sh \ - post-hook.sh + post-hook.sh \ + function-trace.sh # parallel.sh install-tests += $(foreach x, $(nix_tests), tests/$(x)) From 653c40778462b5921fbbe2abffd1a2822f08ec57 Mon Sep 17 00:00:00 2001 From: Daniel Diaz Date: Fri, 14 Jun 2019 00:05:31 +0200 Subject: [PATCH 09/33] Expanded documentation for .nix-defexpr --- doc/manual/command-ref/nix-env.xml | 40 +++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/doc/manual/command-ref/nix-env.xml b/doc/manual/command-ref/nix-env.xml index 56c466268..693f23f7f 100644 --- a/doc/manual/command-ref/nix-env.xml +++ b/doc/manual/command-ref/nix-env.xml @@ -221,31 +221,53 @@ also . ~/.nix-defexpr - A directory that contains the default Nix + The source for the default Nix expressions used by the , , and operations to obtain derivations. The + --available operations to obtain derivations. The option may be used to override this default. - The Nix expressions in this directory are combined into a - single set, with each file as an attribute that has the name of - the file. Thus, if ~/.nix-defexpr contains - two files, foo and bar, + If ~/.nix-defexpr is a file, + it is loaded as a Nix expression. If the expression + is a set, it is used as the default Nix expression. + If the expression is a function, an empty set is passed + as argument and the return value is used as + the default Nix expression. + + If ~/.nix-defexpr is a directory + containing a default.nix file, that file + is loaded as in the above paragraph. + + If ~/.nix-defexpr is a directory without + a default.nix file, then its contents + (both files and subdirectories) are loaded as Nix expressions. + The expressions are combined into a single set, each expression + under an attribute with the same name as the original file + or subdirectory. + + + For example, if ~/.nix-defexpr contains + two files, foo.nix and bar.nix, then the default Nix expression will essentially be { - foo = import ~/.nix-defexpr/foo; - bar = import ~/.nix-defexpr/bar; + foo = import ~/.nix-defexpr/foo.nix; + bar = import ~/.nix-defexpr/bar.nix; } + The file manifest.nix is always ignored. + Subdirectories without a default.nix file + are traversed recursively in search of more Nix expressions, + but the names of these intermediate directories are not + added to the attribute paths of the default Nix expression. + The command nix-channel places symlinks to the downloaded Nix expressions from each subscribed channel in this directory. - From 91b00b145f0c50e346d0250168cbcbcba7aa3b40 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Mon, 12 Aug 2019 21:03:48 +0200 Subject: [PATCH 10/33] libutil: add SizedSource Introduce the SizeSource which allows to bound how much data is being read from a source. It also contains a drainAll() function to discard the rest of the source, useful to keep the nix protocol in sync. --- src/libutil/serialise.hh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh index 969e4dff3..a344a5ac7 100644 --- a/src/libutil/serialise.hh +++ b/src/libutil/serialise.hh @@ -179,6 +179,36 @@ struct TeeSource : Source } }; +/* A reader that consumes the original Source until 'size'. */ +struct SizedSource : Source +{ + Source & orig; + size_t remain; + SizedSource(Source & orig, size_t size) + : orig(orig), remain(size) { } + size_t read(unsigned char * data, size_t len) + { + if (this->remain <= 0) { + throw EndOfFile("sized: unexpected end-of-file"); + } + len = std::min(len, this->remain); + size_t n = this->orig.read(data, len); + this->remain -= n; + return n; + } + + /* Consume the original source until no remain data is left to consume. */ + size_t drainAll() + { + std::vector buf(8192); + size_t sum = 0; + while (this->remain > 0) { + size_t n = read(buf.data(), buf.size()); + sum += n; + } + return sum; + } +}; /* Convert a function into a sink. */ struct LambdaSink : Sink From b226b5cd976ca71abb3c0861b56d5e5940430924 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Mon, 12 Aug 2019 17:19:43 +0200 Subject: [PATCH 11/33] nix-store: fix out of sync protocol If a NAR is already in the store, addToStore doesn't read the source which makes the protocol go out of sync. This happens for example when two client try to nix-copy-closure the same derivation at the same time. --- src/nix-store/nix-store.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index f324056bb..0cbceb02f 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -950,8 +950,16 @@ static void opServe(Strings opFlags, Strings opArgs) info.sigs = readStrings(in); in >> info.ca; - // FIXME: race if addToStore doesn't read source? - store->addToStore(info, in, NoRepair, NoCheckSigs); + if (info.narSize == 0) { + throw Error("narInfo is too old and missing the narSize field"); + } + + SizedSource sizedSource(in, info.narSize); + + store->addToStore(info, sizedSource, NoRepair, NoCheckSigs); + + // consume all the data that has been sent before continuing. + sizedSource.drainAll(); out << 1; // indicate success From 1dbaf119486fecbdf57ecc2f877307030b665f69 Mon Sep 17 00:00:00 2001 From: Toon Nolten Date: Sat, 17 Aug 2019 16:33:35 +0200 Subject: [PATCH 12/33] Fix nix-env documentation for --delete-generations The documentation for `--delete-generations` had an erroneous fullstop and as it turns out inaccurate information on the `+No.` syntax. --- doc/manual/command-ref/nix-env.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/manual/command-ref/nix-env.xml b/doc/manual/command-ref/nix-env.xml index 693f23f7f..9d13d3014 100644 --- a/doc/manual/command-ref/nix-env.xml +++ b/doc/manual/command-ref/nix-env.xml @@ -1370,10 +1370,10 @@ profile. The generations can be a list of generation numbers, the special value old to delete all non-current generations, a value such as 30d to delete all generations older than the specified number of days (except for the -generation that was active at that point in time), or a value such as. -+5 to only keep the specified items older than the -current generation. Periodically deleting old generations is important -to make garbage collection effective. +generation that was active at that point in time), or a value such as ++5 to only keep the specified number of generations. +Periodically deleting old generations is important to make garbage collection +effective. From 0463d5e36ffdbb60f851bd3b34756eff84151b28 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Thu, 22 Aug 2019 23:38:52 -0400 Subject: [PATCH 13/33] Allow empty /nix directory in multi-user installer With macOS catalina, we can no longer modify the root system volume (#2925). macOS provides a system configuration file in synthetic.conf(5) to create empty root directories. This can be used to mount /nix to a separate volume. As a result, this directory will need to already exist prior to installation. Instead, check for /nix/store and /nix/var for a live Nix installation. --- scripts/install-multi-user.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/install-multi-user.sh b/scripts/install-multi-user.sh index 9b757e7da..3d8b035eb 100644 --- a/scripts/install-multi-user.sh +++ b/scripts/install-multi-user.sh @@ -330,7 +330,7 @@ EOF fi done - if [ -d /nix ]; then + if [ -d /nix/store ] || [ -d /nix/var ]; then failure < Date: Fri, 23 Aug 2019 15:50:54 -0400 Subject: [PATCH 14/33] operators: document exact precedenc, split up similar operators --- doc/manual/expressions/language-operators.xml | 103 ++++++++++++++++-- 1 file changed, 95 insertions(+), 8 deletions(-) diff --git a/doc/manual/expressions/language-operators.xml b/doc/manual/expressions/language-operators.xml index f1f750934..1b14bc658 100644 --- a/doc/manual/expressions/language-operators.xml +++ b/doc/manual/expressions/language-operators.xml @@ -15,13 +15,16 @@ weakest binding). + Name Syntax Associativity Description + Precedence + Select e . attrpath [ or def ] @@ -33,19 +36,25 @@ weakest binding). dot-separated list of attribute names.) If the attribute doesn’t exist, return def if provided, otherwise abort evaluation. + 1 + Application e1 e2 left Call function e1 with argument e2. + 2 + Arithmetic Negation - e none Arithmetic negation. + 3 + Has Attribute e ? attrpath none @@ -53,34 +62,69 @@ weakest binding). the attribute denoted by attrpath; return true or false. + 4 + List Concatenation e1 ++ e2 right List concatenation. + 5 + Multiplication e1 * e2, + + left + Arithmetic multiplication. + 6 + + + Division + e1 / e2 left - Arithmetic multiplication and division. + Arithmetic division. + 6 + Addition + + e1 + e2 + + left + Arithmetic addition. + 7 + + + Subtraction - e1 + e2, e1 - e2 left - Arithmetic addition and subtraction. String or path concatenation (only by +). + Arithmetic subtraction. + 7 + String Concatenation + + string1 + string2 + + left + String concatenation. + 7 + + + Not ! e none Boolean negation. + 8 + Update e1 // e2 right @@ -89,47 +133,90 @@ weakest binding). e2 (with the latter taking precedence over the former in case of equally named attributes). + 9 + Less Than e1 < e2, - e1 > e2, - e1 <= e2, + + none + Arithmetic comparison. + 10 + + + Less Than or Equal To + + e1 <= e2 + + none + Arithmetic comparison. + 10 + + + Greater Than + + e1 > e2 + + none + Arithmetic comparison. + 10 + + + Greater Than or Equal To + e1 >= e2 none Arithmetic comparison. + 10 + Equality + + e1 == e2 + + none + Equality. + 11 + + + Inequality - e1 == e2, e1 != e2 none - Equality and inequality. + Inequality. + 11 + Logical And e1 && e2 left Logical AND. + 12 + Logical Or e1 || e2 left Logical OR. + 13 + Logical Implication e1 -> e2 none Logical implication (equivalent to !e1 || e2). + 14 - \ No newline at end of file + From 5c06a8d3283139140e765b5f10ad7102a6a3e964 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Fri, 23 Aug 2019 20:24:39 -0400 Subject: [PATCH 15/33] Reset tmpDirInSandbox for unsandboxed --- src/libstore/build.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 0f71e7511..96e9b8edd 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2330,6 +2330,7 @@ void DerivationGoal::startBuilder() int res = helper.wait(); if (res != 0 && settings.sandboxFallback) { useChroot = false; + tmpDirInSandbox = tmpDir; goto fallback; } else if (res != 0) throw Error("unable to start build process"); From 6dab42a551a769f304c2a0e66e8771d7289502f2 Mon Sep 17 00:00:00 2001 From: Venkateswara Rao Mandela Date: Sat, 15 Jun 2019 00:27:26 +0530 Subject: [PATCH 16/33] installer: handle network proxy in systemd install If a network proxy configuration is detected, setup an override systemd unit file for nix-daemon service with the non-empty proxy variables. Proxy detection is performed by looking for http/https/ftp proxy and no proxy variables in user environment --- scripts/install-systemd-multi-user.sh | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) mode change 100644 => 100755 scripts/install-systemd-multi-user.sh diff --git a/scripts/install-systemd-multi-user.sh b/scripts/install-systemd-multi-user.sh old mode 100644 new mode 100755 index 04bc539a1..bef3ac4f9 --- a/scripts/install-systemd-multi-user.sh +++ b/scripts/install-systemd-multi-user.sh @@ -9,6 +9,38 @@ readonly SERVICE_DEST=/etc/systemd/system/nix-daemon.service readonly SOCKET_SRC=/lib/systemd/system/nix-daemon.socket readonly SOCKET_DEST=/etc/systemd/system/nix-daemon.socket + +# Path for the systemd override unit file to contain the proxy settings +readonly SERVICE_OVERRIDE=${SERVICE_DEST}.d/override.conf + +create_systemd_override() { + header "Configuring proxy for the nix-daemon service" + _sudo "create directory for systemd unit override" mkdir -p "$(dirname $SERVICE_OVERRIDE)" + cat < Date: Fri, 23 Aug 2019 16:02:49 -0400 Subject: [PATCH 17/33] docs: document the installer's use of proxy env vars --- doc/manual/installation/env-variables.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/manual/installation/env-variables.xml b/doc/manual/installation/env-variables.xml index d1ee0bb2e..e2b8fc867 100644 --- a/doc/manual/installation/env-variables.xml +++ b/doc/manual/installation/env-variables.xml @@ -67,5 +67,23 @@ $ sudo launchctl kickstart -k system/org.nixos.nix-daemon +
+ +Proxy Environment Variables + +The Nix installer has special handling for these proxy-related +environment variables: +http_proxy, https_proxy, +ftp_proxy, no_proxy, +HTTP_PROXY, HTTPS_PROXY, +FTP_PROXY, NO_PROXY. + +If any of these variables are set when running the Nix installer, +then the installer will create an override file at +/etc/systemd/system/nix-daemon.service.d/override.conf +so nix-daemon will use them. + +
+ From d45922472434783bdc29610479a735dd236229a3 Mon Sep 17 00:00:00 2001 From: Piotr Szubiakowski Date: Tue, 27 Aug 2019 10:35:35 +0200 Subject: [PATCH 18/33] nix-daemon.service: add install section. Signed-off-by: Piotr Szubiakowski --- misc/systemd/nix-daemon.service.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/misc/systemd/nix-daemon.service.in b/misc/systemd/nix-daemon.service.in index 5fc04a3f5..25655204d 100644 --- a/misc/systemd/nix-daemon.service.in +++ b/misc/systemd/nix-daemon.service.in @@ -7,3 +7,6 @@ ConditionPathIsReadWrite=@localstatedir@/nix/daemon-socket [Service] ExecStart=@@bindir@/nix-daemon nix-daemon --daemon KillMode=process + +[Install] +WantedBy=multi-user.target From 171d784404fefa7c91e2082f92ec92c39cc1aa8e Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Tue, 27 Aug 2019 06:55:22 -0400 Subject: [PATCH 19/33] docs: operators: Make OR and AND capitalized --- doc/manual/expressions/language-operators.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/expressions/language-operators.xml b/doc/manual/expressions/language-operators.xml index 1b14bc658..4f11bf529 100644 --- a/doc/manual/expressions/language-operators.xml +++ b/doc/manual/expressions/language-operators.xml @@ -190,7 +190,7 @@ weakest binding). 11 - Logical And + Logical AND e1 && e2 left @@ -198,7 +198,7 @@ weakest binding). 12 - Logical Or + Logical OR e1 || e2 left From 45b3dc325a1d49f86182195cf22fc96ddc05c644 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Aug 2019 17:00:04 +0200 Subject: [PATCH 20/33] Add 2.3 release notes --- doc/manual/release-notes/rl-2.3.xml | 70 ++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/doc/manual/release-notes/rl-2.3.xml b/doc/manual/release-notes/rl-2.3.xml index 428213b36..b0f7c8ec5 100644 --- a/doc/manual/release-notes/rl-2.3.xml +++ b/doc/manual/release-notes/rl-2.3.xml @@ -4,9 +4,23 @@ version="5.0" xml:id="ssec-relnotes-2.3"> -Release 2.3 (????-??-??) +Release 2.3 (2019-08-??) -This release contains the following changes: +This is primarily a bug fix release. However, it makes some +incompatible changes: + + + + + Nix now uses BSD file locks instead of POSIX file + locks. Since previous releases used POSIX file locks, you should + not use Nix 2.2 and previous releases at the same time on a Nix + store. + + + + +It also has the following changes: @@ -18,5 +32,57 @@ already begin with refs/.
+ + + The installer now enables sandboxing by default on + Linux. The max-jobs setting now defaults to + 1. + + + + New builtin functions: + builtins.isPath, + builtins.hashFile. + + + + + nix: Add + () flag to + print build log output to stderr rather than showing the last log + line in the progress bar. To distinguish between concurrent + builds, log lines are prefixed by the name of the package. + + + + + Builds are now executed in a pseudo-terminal, and the + TERM evnironment variable is set to + xterm-256color. This allows many programs + (e.g. gcc, clang, + cmake) to print colorized log output. + + + + Add convenience flag. This flag + disables substituters; sets the tarball-ttl + setting to infinity (ensuring that any previously downloaded files + are considered current); and disables retrying downloads and sets + the connection timeout to the minimum. This flag is enabled + automatically if there are no configured non-loopback network + interfaces. + + + + Add a post-build-hook setting to run a + program after a build has succeeded. + + + + Add a trace-function-calls setting to log + the duration of Nix function calls to stderr. + + + From 73728874ab89d77bce3b103acb239d4d5eec14b1 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Aug 2019 17:01:54 +0200 Subject: [PATCH 21/33] Hopefully fix post-hook test on macOS https://hydra.nixos.org/build/99262744 --- tests/push-to-store.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/push-to-store.sh b/tests/push-to-store.sh index d97eb095d..6aadb916b 100755 --- a/tests/push-to-store.sh +++ b/tests/push-to-store.sh @@ -1,4 +1,4 @@ #!/bin/sh echo Pushing "$@" to "$REMOTE_STORE" -echo -n "$OUT_PATHS" | xargs -d: nix copy --to "$REMOTE_STORE" --no-require-sigs +printf "%s" "$OUT_PATHS" | xargs -d: nix copy --to "$REMOTE_STORE" --no-require-sigs From fdff96501f7f1762446a930e3a27b56a4fc912c2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Aug 2019 21:18:00 +0200 Subject: [PATCH 22/33] Update release notes --- doc/manual/release-notes/rl-2.3.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/manual/release-notes/rl-2.3.xml b/doc/manual/release-notes/rl-2.3.xml index b0f7c8ec5..a1f4a4b75 100644 --- a/doc/manual/release-notes/rl-2.3.xml +++ b/doc/manual/release-notes/rl-2.3.xml @@ -83,6 +83,11 @@ incompatible changes: the duration of Nix function calls to stderr. + + On Linux, sandboxing is now disabled by default on systems + that don’t have the necessary kernel support. + + From ceefddafe839a0c9ac553367e16f965dda7fb086 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Aug 2019 22:18:34 +0200 Subject: [PATCH 23/33] Compress binary tarballs using xz Fixes https://github.com/NixOS/nix/issues/240. Apparently 'tar -xf' can decompress xz files on macOS nowadays. --- release.nix | 6 +++--- scripts/install.in | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/release.nix b/release.nix index 78b39108f..bec955730 100644 --- a/release.nix +++ b/release.nix @@ -165,10 +165,10 @@ let chmod +x $TMPDIR/install-systemd-multi-user.sh chmod +x $TMPDIR/install-multi-user dir=nix-${version}-${system} - fn=$out/$dir.tar.bz2 + fn=$out/$dir.tar.xz mkdir -p $out/nix-support echo "file binary-dist $fn" >> $out/nix-support/hydra-build-products - tar cvfj $fn \ + tar cvfJ $fn \ --owner=0 --group=0 --mode=u+rw,uga+r \ --absolute-names \ --hard-dereference \ @@ -295,7 +295,7 @@ let substitute ${./scripts/install.in} $out/install \ ${pkgs.lib.concatMapStrings - (system: "--replace '@binaryTarball_${system}@' $(nix hash-file --base16 --type sha256 ${binaryTarball.${system}}/*.tar.bz2) ") + (system: "--replace '@binaryTarball_${system}@' $(nix hash-file --base16 --type sha256 ${binaryTarball.${system}}/*.tar.xz) ") [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ] } \ --replace '@nixVersion@' ${build.x86_64-linux.src.version} diff --git a/scripts/install.in b/scripts/install.in index 4857638c0..902758b13 100644 --- a/scripts/install.in +++ b/scripts/install.in @@ -30,12 +30,11 @@ case "$(uname -s).$(uname -m)" in *) oops "sorry, there is no binary distribution of Nix for your platform";; esac -url="https://nixos.org/releases/nix/nix-@nixVersion@/nix-@nixVersion@-$system.tar.bz2" +url="https://nixos.org/releases/nix/nix-@nixVersion@/nix-@nixVersion@-$system.tar.xz" -tarball="$tmpDir/$(basename "$tmpDir/nix-@nixVersion@-$system.tar.bz2")" +tarball="$tmpDir/$(basename "$tmpDir/nix-@nixVersion@-$system.tar.xz")" require_util curl "download the binary tarball" -require_util bzcat "decompress the binary tarball" require_util tar "unpack the binary tarball" echo "downloading Nix @nixVersion@ binary tarball for $system from '$url' to '$tmpDir'..." @@ -57,7 +56,7 @@ fi unpack=$tmpDir/unpack mkdir -p "$unpack" -< "$tarball" bzcat | tar -xf - -C "$unpack" || oops "failed to unpack '$url'" +tar -xf "$tarball" -C "$unpack" || oops "failed to unpack '$url'" script=$(echo "$unpack"/*/install) From 5fa8b3f96577db65e080aaef65ad1cae462356cc Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 27 Aug 2019 22:38:48 +0200 Subject: [PATCH 24/33] Update the libboost hack This cuts about 46 MiB from the closure. --- release.nix | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/release.nix b/release.nix index bec955730..ab677f3bd 100644 --- a/release.nix +++ b/release.nix @@ -72,7 +72,12 @@ let # https://github.com/NixOS/nixpkgs/issues/45462 '' mkdir -p $out/lib - cp ${boost}/lib/libboost_context* $out/lib + cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib + rm -f $out/lib/*.a + chmod u+w $out/lib/*.so.* + ${lib.optionalString stdenv.isLinux '' + patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.* + ''} ''; configureFlags = configureFlags ++ From 7298a38a07d62d2077ca30a3ff619e32edb4eb1e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 28 Aug 2019 16:29:44 +0200 Subject: [PATCH 25/33] Don't send certain setting overrides to the daemon These are already handled separately. This fixes warnings like warning: ignoring the user-specified setting 'max-jobs', because it is a restricted setting and you are not a trusted user when using the -j flag. --- src/libstore/remote-store.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 15faf78a5..1c2e23f9c 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -191,6 +191,13 @@ void RemoteStore::setOptions(Connection & conn) if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) { std::map overrides; globalConfig.getSettings(overrides, true); + overrides.erase(settings.keepFailed.name); + overrides.erase(settings.keepGoing.name); + overrides.erase(settings.tryFallback.name); + overrides.erase(settings.maxBuildJobs.name); + overrides.erase(settings.maxSilentTime.name); + overrides.erase(settings.buildCores.name); + overrides.erase(settings.useSubstitutes.name); conn.to << overrides.size(); for (auto & i : overrides) conn.to << i.first << i.second.value; From 693e68e09c9a17ca72b074bd2e575bf435647b45 Mon Sep 17 00:00:00 2001 From: Matthew Bauer Date: Wed, 28 Aug 2019 12:26:08 -0400 Subject: [PATCH 26/33] Set maximum name length in Nix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously we allowed any length of name for Nix derivations. This is bad because different file systems have different max lengths. To make things predictable, I have picked a max. This was done by trying to build this derivation: derivation { name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; builder = "/no-such-path"; system = "x86_64-linux"; } Take off one a and it will not lead to file name too long. That ends up being 212 a’s. An even smaller max could be picked if we want to support more file systems. Working backwards, this is why: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-${name}.drv.chroot > 255 - 32 - 1 - 4 - 7 = 211 --- src/libstore/store-api.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index f5608d384..3bb9db0b7 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -97,6 +97,10 @@ void checkStoreName(const string & name) reasons (e.g., "." and ".."). */ if (string(name, 0, 1) == ".") throw Error(baseError % "it is illegal to start the name with a period"); + /* Disallow names longer than 211 characters. ext4’s max is 256, + but we need extra space for the hash and .chroot extensions. */ + if (name.length() > 211) + throw Error(baseError % "name must be less than 212 characters"); for (auto & i : name) if (!((i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || From c128031492b7134f67065b66a89f9183e79e99f9 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 28 Aug 2019 22:04:16 +0200 Subject: [PATCH 27/33] Fix macOS build https://hydra.nixos.org/build/99500938 --- release.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.nix b/release.nix index ab677f3bd..0fe683518 100644 --- a/release.nix +++ b/release.nix @@ -74,8 +74,8 @@ let mkdir -p $out/lib cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib rm -f $out/lib/*.a - chmod u+w $out/lib/*.so.* ${lib.optionalString stdenv.isLinux '' + chmod u+w $out/lib/*.so.* patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.* ''} ''; From b6120d26a84a69755c049ca5115b4388239d4540 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 28 Aug 2019 22:19:31 +0200 Subject: [PATCH 28/33] gc-auto.sh: Increase verbosity --- tests/gc-auto.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/gc-auto.sh b/tests/gc-auto.sh index 1e91282d0..4b1f6374a 100644 --- a/tests/gc-auto.sh +++ b/tests/gc-auto.sh @@ -29,7 +29,7 @@ with import ./config.nix; mkDerivation { EOF ) -nix build -o $TEST_ROOT/result-A -L "($expr)" \ +nix build -v -o $TEST_ROOT/result-A -L "($expr)" \ --min-free 1000 --max-free 2000 --min-free-check-interval 1 & pid=$! @@ -50,7 +50,7 @@ with import ./config.nix; mkDerivation { EOF ) -nix build -o $TEST_ROOT/result-B -L "($expr2)" \ +nix build -v -o $TEST_ROOT/result-B -L "($expr2)" \ --min-free 1000 --max-free 2000 --min-free-check-interval 1 wait "$pid" From f27e53f77e39d1247c47b48acb63af3d24ca74bf Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 29 Aug 2019 12:09:58 +0200 Subject: [PATCH 29/33] Cleanup --- src/libstore/gc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 366dbfb0a..f73601679 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -920,11 +920,11 @@ void LocalStore::autoGC(bool sync) promise.set_value(); }); - printInfo("running auto-GC to free %d bytes", settings.maxFree - avail); - GCOptions options; options.maxFreed = settings.maxFree - avail; + printInfo("running auto-GC to free %d bytes", options.maxFreed); + GCResults results; collectGarbage(options, results); From ecb0a23d51e46e2e0180850bdc8ad6cb7cc3d13f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 29 Aug 2019 12:10:01 +0200 Subject: [PATCH 30/33] Add some more instrumentation --- tests/gc-auto.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/gc-auto.sh b/tests/gc-auto.sh index 4b1f6374a..49894bc68 100644 --- a/tests/gc-auto.sh +++ b/tests/gc-auto.sh @@ -6,6 +6,9 @@ garbage1=$(nix add-to-store --name garbage1 ./tarball.sh) garbage2=$(nix add-to-store --name garbage2 ./tarball.sh) garbage3=$(nix add-to-store --name garbage3 ./tarball.sh) +ls -l $garbage3 +du $garbage3 + fake_free=$TEST_ROOT/fake-free export _NIX_TEST_FREE_SPACE_FILE=$fake_free echo 1100 > $fake_free From 31f5ecfaa5bce2282f50daed1e4f477c64705fb3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 29 Aug 2019 12:35:15 +0200 Subject: [PATCH 31/33] Maybe fix #3058 --- tests/gc-auto.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/gc-auto.sh b/tests/gc-auto.sh index 49894bc68..68b7219f2 100644 --- a/tests/gc-auto.sh +++ b/tests/gc-auto.sh @@ -2,12 +2,12 @@ source common.sh clearStore -garbage1=$(nix add-to-store --name garbage1 ./tarball.sh) -garbage2=$(nix add-to-store --name garbage2 ./tarball.sh) -garbage3=$(nix add-to-store --name garbage3 ./tarball.sh) +garbage1=$(nix add-to-store --name garbage1 ./nar-access.sh) +garbage2=$(nix add-to-store --name garbage2 ./nar-access.sh) +garbage3=$(nix add-to-store --name garbage3 ./nar-access.sh) ls -l $garbage3 -du $garbage3 +POSIXLY_CORRECT=1 du $garbage3 fake_free=$TEST_ROOT/fake-free export _NIX_TEST_FREE_SPACE_FILE=$fake_free From 5bdac86be2eb6d541784c4f149bfa06b59ef63a2 Mon Sep 17 00:00:00 2001 From: toonn Date: Thu, 29 Aug 2019 13:46:38 +0200 Subject: [PATCH 32/33] Reword to clarify newer generations are left alone My attempt at clarifying the docs resulted in a false explanation. This is now fixed and I added an example to eliminate all possible confusion. --- doc/manual/command-ref/nix-env.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/manual/command-ref/nix-env.xml b/doc/manual/command-ref/nix-env.xml index 9d13d3014..c8c01f9a4 100644 --- a/doc/manual/command-ref/nix-env.xml +++ b/doc/manual/command-ref/nix-env.xml @@ -1371,7 +1371,10 @@ special value old to delete all non-current generations, a value such as 30d to delete all generations older than the specified number of days (except for the generation that was active at that point in time), or a value such as -+5 to only keep the specified number of generations. ++5 to keep the last 5 generations +ignoring any newer than current, e.g., if 30 is the current +generation +5 will delete generation 25 +and all older generations. Periodically deleting old generations is important to make garbage collection effective. From a2c4fcd5e9782dc8d2998773380c7171ee53b813 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 29 Aug 2019 14:49:58 +0200 Subject: [PATCH 33/33] Don't rely on st_blocks It doesn't seem very reliable on ZFS. --- src/libstore/gc.cc | 7 +++---- src/libutil/util.cc | 2 +- tests/gc-auto.sh | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index f73601679..a166f4ee2 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -690,9 +690,8 @@ void LocalStore::removeUnusedLinks(const GCState & state) throw SysError(format("statting '%1%'") % path); if (st.st_nlink != 1) { - unsigned long long size = st.st_blocks * 512ULL; - actualSize += size; - unsharedSize += (st.st_nlink - 1) * size; + actualSize += st.st_size; + unsharedSize += (st.st_nlink - 1) * st.st_size; continue; } @@ -701,7 +700,7 @@ void LocalStore::removeUnusedLinks(const GCState & state) if (unlink(path.c_str()) == -1) throw SysError(format("deleting '%1%'") % path); - state.results.bytesFreed += st.st_blocks * 512ULL; + state.results.bytesFreed += st.st_size; } struct stat st; diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 44fa72482..1b7449991 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -397,7 +397,7 @@ static void _deletePath(const Path & path, unsigned long long & bytesFreed) } if (!S_ISDIR(st.st_mode) && st.st_nlink == 1) - bytesFreed += st.st_blocks * 512; + bytesFreed += st.st_size; if (S_ISDIR(st.st_mode)) { /* Make the directory accessible. */ diff --git a/tests/gc-auto.sh b/tests/gc-auto.sh index 68b7219f2..54ead227e 100644 --- a/tests/gc-auto.sh +++ b/tests/gc-auto.sh @@ -22,7 +22,7 @@ with import ./config.nix; mkDerivation { echo foo > \$out/bar echo 1... sleep 2 - echo 100 > $fake_free + echo 200 > $fake_free echo 2... sleep 2 echo 3... @@ -44,7 +44,7 @@ with import ./config.nix; mkDerivation { echo foo > \$out/bar echo 1... sleep 2 - echo 100 > $fake_free + echo 200 > $fake_free echo 2... sleep 2 echo 3...