about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/advanced-topics/advanced-topics.xml10
-rw-r--r--doc/manual/advanced-topics/distributed-builds.xml (renamed from doc/manual/builds/enabling-builds.xml)21
-rw-r--r--doc/manual/builds/build-farm.xml22
-rw-r--r--doc/manual/command-ref/conf-file.xml11
-rw-r--r--doc/manual/command-ref/nix-channel.xml56
-rw-r--r--doc/manual/command-ref/nix-install-package.xml35
-rw-r--r--doc/manual/command-ref/nix-pull.xml7
-rw-r--r--doc/manual/command-ref/nix-push.xml10
-rw-r--r--doc/manual/command-ref/utilities.xml4
-rw-r--r--doc/manual/expressions/custom-builder.xml26
-rw-r--r--doc/manual/expressions/debug-build.xml17
-rw-r--r--doc/manual/expressions/derivations.xml14
-rw-r--r--doc/manual/expressions/generic-builder.xml4
-rw-r--r--doc/manual/expressions/simple-building-testing.xml4
-rw-r--r--doc/manual/expressions/standard-env.xml60
-rw-r--r--doc/manual/expressions/writing-nix-expressions.xml1
-rw-r--r--doc/manual/installation/multi-user.xml10
-rw-r--r--doc/manual/introduction/about-nix.xml4
-rw-r--r--doc/manual/local.mk10
-rw-r--r--doc/manual/manual.xml2
-rw-r--r--doc/manual/packages/basic-package-mgmt.xml138
-rw-r--r--doc/manual/packages/channels.xml44
-rw-r--r--doc/manual/packages/garbage-collection.xml11
-rw-r--r--doc/manual/packages/profiles.xml8
-rw-r--r--doc/manual/release-notes/rl-1.8.xml6
-rw-r--r--doc/manual/style.css13
-rw-r--r--doc/manual/troubleshooting/links-nix-store.xml10
-rw-r--r--doc/signing.txt4
-rw-r--r--mk/functions.mk2
-rw-r--r--mk/jars.mk15
-rw-r--r--mk/lib.mk24
-rw-r--r--mk/libraries.mk21
-rw-r--r--mk/patterns.mk9
-rw-r--r--mk/programs.mk4
-rw-r--r--mk/templates.mk4
-rw-r--r--release.nix9
-rw-r--r--scripts/download-from-binary-cache.pl.in10
-rw-r--r--scripts/install-nix-from-closure.sh18
-rw-r--r--scripts/nix-profile.sh.in4
-rw-r--r--src/libexpr/eval.cc21
-rw-r--r--src/libexpr/eval.hh8
-rw-r--r--src/libexpr/primops.cc35
-rw-r--r--src/libmain/shared.cc59
-rw-r--r--src/libmain/stack.cc2
-rw-r--r--src/libstore/build.cc64
-rw-r--r--src/libstore/gc.cc4
-rw-r--r--src/libstore/local-store.cc5
-rw-r--r--src/libstore/pathlocks.cc2
-rw-r--r--src/libstore/remote-store.cc2
-rw-r--r--src/libutil/types.hh1
-rw-r--r--src/libutil/util.cc92
-rw-r--r--src/libutil/util.hh18
-rw-r--r--src/nix-daemon/nix-daemon.cc37
-rw-r--r--src/nix-instantiate/nix-instantiate.cc2
-rw-r--r--src/nix-store/nix-store.cc2
-rw-r--r--tests/remote-builds.nix2
56 files changed, 527 insertions, 511 deletions
diff --git a/doc/manual/advanced-topics/advanced-topics.xml b/doc/manual/advanced-topics/advanced-topics.xml
new file mode 100644
index 000000000000..338aa6f3a238
--- /dev/null
+++ b/doc/manual/advanced-topics/advanced-topics.xml
@@ -0,0 +1,10 @@
+<part xmlns="http://docbook.org/ns/docbook"
+      xmlns:xlink="http://www.w3.org/1999/xlink"
+      xmlns:xi="http://www.w3.org/2001/XInclude"
+      version="5.0">
+
+<title>Advanced Topics</title>
+
+<xi:include href="distributed-builds.xml" />
+
+</part>
diff --git a/doc/manual/builds/enabling-builds.xml b/doc/manual/advanced-topics/distributed-builds.xml
index 4b45812ee918..70f396f81cdb 100644
--- a/doc/manual/builds/enabling-builds.xml
+++ b/doc/manual/advanced-topics/distributed-builds.xml
@@ -2,9 +2,18 @@
       xmlns:xlink="http://www.w3.org/1999/xlink"
       xmlns:xi="http://www.w3.org/2001/XInclude"
       version="5.0"
-      xml:id="ch-enabling-builds">
+      xml:id='chap-distributed-builds'>
 
-<title>Enabling Distributed Builds</title>
+<title>Distributed Builds</title>
+
+<para>Nix supports distributed builds, where a local Nix installation can
+forward Nix builds to other machines over the network.  This allows
+multiple builds to be performed in parallel (thus improving
+performance) and allows Nix to perform multi-platform builds in a
+semi-transparent way.  For instance, if you perform a build for a
+<literal>powerpc-darwin</literal> on an <literal>i686-linux</literal>
+machine, Nix can automatically forward the build to a
+<literal>powerpc-darwin</literal> machine, if available.</para>
 
 <para>You can enable distributed builds by setting the environment
 variable <envar>NIX_BUILD_HOOK</envar> to point to a program that Nix
@@ -41,7 +50,7 @@ example configuration is shown in <xref linkend='ex-remote-systems'
 bits of information:
 
 <orderedlist>
-  
+
   <listitem><para>The name of the remote machine, with optionally the
   user under which the remote build should be performed.  This is
   actually passed as an argument to <command>ssh</command>, so it can
@@ -73,9 +82,9 @@ bits of information:
   <filename>build-remote.pl</filename> will only perform the
   derivation on a machine that has the specified features.  For
   instance, the attribute
-  
+
 <programlisting>
-requiredSystemFeatures = [ "kvm" ];  
+requiredSystemFeatures = [ "kvm" ];
 </programlisting>
 
   will cause the build to be performed on a machine that has the
@@ -103,4 +112,4 @@ running, they should use the same <envar>NIX_CURRENT_LOAD</envar>
 file.  Maybe in the future <filename>build-remote.pl</filename> will
 look at the actual remote load.</para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/doc/manual/builds/build-farm.xml b/doc/manual/builds/build-farm.xml
deleted file mode 100644
index e0e9f10f1173..000000000000
--- a/doc/manual/builds/build-farm.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<part xmlns="http://docbook.org/ns/docbook"
-      xmlns:xlink="http://www.w3.org/1999/xlink"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      version="5.0"
-      xml:id='chap-distributed-builds'>
-
-<title>Distributed Builds</title>
-
-<partintro>
-<para>Nix supports distributed builds, where a local Nix installation can
-forward Nix builds to other machines over the network.  This allows
-multiple builds to be performed in parallel (thus improving
-performance) and allows Nix to perform multi-platform builds in a
-semi-transparent way.  For instance, if you perform a build for a
-<literal>powerpc-darwin</literal> on an <literal>i686-linux</literal>
-machine, Nix can automatically forward the build to a
-<literal>powerpc-darwin</literal> machine, if available.</para>
-</partintro>
-
-<xi:include href="enabling-builds.xml" />
-
-</part>
diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index a7539c4c7e40..053f4d43cb0c 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -348,7 +348,7 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
 
     <listitem><para>A list of URLs of binary caches, separated by
     whitespace.  The default is
-    <literal>http://cache.nixos.org</literal>.</para></listitem>
+    <literal>https://cache.nixos.org</literal>.</para></listitem>
 
   </varlistentry>
 
@@ -402,6 +402,15 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
   </varlistentry>
 
 
+  <varlistentry><term><literal>verify-https-binary-caches</literal></term>
+
+    <listitem><para>Whether HTTPS binary caches are required to have a
+    certificate that can be verified. Defaults to
+    <literal>true</literal>.</para></listitem>
+
+  </varlistentry>
+
+
   <varlistentry><term><literal>force-manifest</literal></term>
 
     <listitem><para>If this option is set to <literal>false</literal>
diff --git a/doc/manual/command-ref/nix-channel.xml b/doc/manual/command-ref/nix-channel.xml
index c4cc04ce24d8..b777c6b6b73c 100644
--- a/doc/manual/command-ref/nix-channel.xml
+++ b/doc/manual/command-ref/nix-channel.xml
@@ -33,8 +33,8 @@
 
 <para>A Nix channel is mechanism that allows you to automatically stay
 up-to-date with a set of pre-built Nix expressions.  A Nix channel is
-just a URL that points to a place containing a set of Nix expressions
-and a <command>nix-push</command> manifest.  <phrase
+just a URL that points to a place containing both a set of Nix
+expressions and a pointer to a binary cache.  <phrase
 condition="manual">See also <xref linkend="sec-channels"
 />.</phrase></para>
 
@@ -99,13 +99,6 @@ an update.</para>
 <para>The list of subscribed channels is stored in
 <filename>~/.nix-channels</filename>.</para>
 
-<para>A channel consists of two elements: a bzipped Tar archive
-containing the Nix expressions, and a manifest created by
-<command>nix-push</command>.  These must be stored under
-<literal><replaceable>url</replaceable>/nixexprs.tar.bz2</literal> and
-<literal><replaceable>url</replaceable>/MANIFEST</literal>,
-respectively.</para>
-
 </refsection>
 
 <refsection><title>Examples</title>
@@ -163,4 +156,49 @@ $ nix-instantiate --eval -E '(import &lt;nixpkgs> {}).lib.nixpkgsVersion'
 
 </refsection>
 
+<refsection><title>Channel format</title>
+
+<para>A channel URL should point to a directory containing the
+following files:</para>
+
+<variablelist>
+
+  <varlistentry><term><filename>nixexprs.tar.xz</filename></term>
+
+    <listitem><para>A tarball containing Nix expressions and files
+    referenced by them (such as build scripts and patches). At
+    top-level, the tarball should contain a single directory. That
+    directory must contain a file <filename>default.nix</filename>
+    that serves as the channel’s “entry point”.</para></listitem>
+
+  </varlistentry>
+
+  <varlistentry><term><filename>binary-cache-url</filename></term>
+
+    <listitem><para>A file containing the URL to a binary cache (such
+    as <uri>https://cache.nixos.org</uri>. Nix will automatically
+    check this cache for pre-built binaries, if the user has
+    sufficient rights to add binary caches. For instance, in a
+    multi-user Nix setup, the binary caches provided by the channels
+    of the root user are used automatically, but caches corresponding
+    to the channels of non-root users are ignored. Binary caches can
+    be created and maintained using
+    <command>nix-push</command>.</para></listitem>
+
+  </varlistentry>
+
+  <varlistentry><term><filename>MANIFEST.bz2</filename></term>
+
+    <listitem><para>(Deprecated in favour of binary caches.) A
+    manifest as created by <command>nix-push</command>. Only used if
+    <filename>binary-cache-url</filename> is not present or if the
+    <filename>nix.conf</filename> option
+    <option>force-manifest</option> is set.</para></listitem>
+
+  </varlistentry>
+
+</variablelist>
+
+</refsection>
+
 </refentry>
diff --git a/doc/manual/command-ref/nix-install-package.xml b/doc/manual/command-ref/nix-install-package.xml
index 7d5cd996e44a..f7802a95d55e 100644
--- a/doc/manual/command-ref/nix-install-package.xml
+++ b/doc/manual/command-ref/nix-install-package.xml
@@ -3,7 +3,7 @@
       xmlns:xi="http://www.w3.org/2001/XInclude"
       version="5.0"
       xml:id="sec-nix-install-package">
-  
+
 <refmeta>
   <refentrytitle>nix-install-package</refentrytitle>
   <manvolnum>1</manvolnum>
@@ -47,8 +47,7 @@
 <para>The command <command>nix-install-package</command> interactively
 installs a Nix Package file (<filename>*.nixpkg</filename>), which is
 a small file that contains a store path to be installed along with the
-URL of a <link linkend="sec-nix-push"><command>nix-push</command>
-manifest</link>.  The Nix Package file is either
+URL of a binary cache.  The Nix Package file is either
 <replaceable>file</replaceable>, or automatically downloaded from
 <replaceable>url</replaceable> if the <option>--url</option> switch is
 used.</para>
@@ -76,7 +75,7 @@ to restart itself with <command>xterm</command>,
 <refsection><title>Options</title>
 
 <variablelist>
-  
+
   <varlistentry><term><option>--non-interactive</option></term>
 
     <listitem><para>Do not open a new terminal window and do not ask
@@ -139,14 +138,14 @@ The elements are as follows:
 <variablelist>
 
   <varlistentry><term><literal>NIXPKG1</literal></term>
-  
+
     <listitem><para>The version of the Nix Package
     file.</para></listitem>
 
   </varlistentry>
 
   <varlistentry><term><replaceable>manifestURL</replaceable></term>
-  
+
     <listitem><para>The manifest to be pulled by
     <command>nix-pull</command>.  The manifest must contain
     <replaceable>outPath</replaceable>.</para></listitem>
@@ -154,21 +153,21 @@ The elements are as follows:
   </varlistentry>
 
   <varlistentry><term><replaceable>name</replaceable></term>
-  
+
     <listitem><para>The symbolic name and version of the
     package.</para></listitem>
 
   </varlistentry>
 
   <varlistentry><term><replaceable>system</replaceable></term>
-  
+
     <listitem><para>The platform identifier of the platform for which
     this binary package is intended.</para></listitem>
 
   </varlistentry>
 
   <varlistentry><term><replaceable>drvPath</replaceable></term>
-  
+
     <listitem><para>The path in the Nix store of the derivation from
     which <replaceable>outPath</replaceable> was built.  Not currently
     used.</para></listitem>
@@ -176,17 +175,21 @@ The elements are as follows:
   </varlistentry>
 
   <varlistentry><term><replaceable>outPath</replaceable></term>
-  
-    <listitem><para>The path in the Nix store of the package.  After
-    <command>nix-install-package</command> has obtained the manifest
-    from <replaceable>manifestURL</replaceable>, it performs a
-    <literal>nix-env -i</literal> <replaceable>outPath</replaceable>
-    to install the binary package.</para></listitem>
+
+    <listitem><para>The path in the Nix store of the
+    package.</para></listitem>
+
+  </varlistentry>
+
+  <varlistentry><term><replaceable>binaryCacheURL</replaceable></term>
+
+    <listitem><para>The URL of a binary cache containing the closure
+    of <replaceable>outPath</replaceable>.</para></listitem>
 
   </varlistentry>
 
 </variablelist>
-  
+
 </para>
 
 <para>An example follows:
diff --git a/doc/manual/command-ref/nix-pull.xml b/doc/manual/command-ref/nix-pull.xml
index 598c651b5091..eb471677b63f 100644
--- a/doc/manual/command-ref/nix-pull.xml
+++ b/doc/manual/command-ref/nix-pull.xml
@@ -13,7 +13,7 @@
 
 <refnamediv>
   <refname>nix-pull</refname>
-  <refpurpose>pull substitutes from a network cache</refpurpose>
+  <refpurpose>register availability of pre-built binaries (deprecated)</refpurpose>
 </refnamediv>
 
 <refsynopsisdiv>
@@ -26,6 +26,9 @@
 
 <refsection><title>Description</title>
 
+<note><para>This command and the use of manifests is deprecated. It is
+better to use binary caches.</para></note>
+
 <para>The command <command>nix-pull</command> obtains a list of
 pre-built store paths from the URL <replaceable>url</replaceable>, and
 for each of these store paths, registers a substitute derivation that
@@ -43,7 +46,7 @@ with the files created by <replaceable>nix-push</replaceable>.</para>
 <refsection><title>Examples</title>
 
 <screen>
-$ nix-pull http://nix.cs.uu.nl/dist/nix/nixpkgs-0.5pre753/MANIFEST</screen>
+$ nix-pull https://nixos.org/releases/nixpkgs/nixpkgs-15.05pre54468.69858d7/MANIFEST</screen>
 
 </refsection>
 
diff --git a/doc/manual/command-ref/nix-push.xml b/doc/manual/command-ref/nix-push.xml
index c19f44a615a8..a3a3c9623e3c 100644
--- a/doc/manual/command-ref/nix-push.xml
+++ b/doc/manual/command-ref/nix-push.xml
@@ -260,7 +260,7 @@ The properties that are currently supported are:
     <listitem><para>Each binary cache has a priority (defaulting to
     50).  Binary caches are checked for binaries in order of ascending
     priority; thus a higher number denotes a lower priority.  The
-    binary cache <uri>http://cache.nixos.org</uri> has priority
+    binary cache <uri>https://cache.nixos.org</uri> has priority
     40.</para></listitem>
 
   </varlistentry>
@@ -278,14 +278,14 @@ URL <replaceable>url</replaceable> has a binary for
 <replaceable>p</replaceable>, Nix fetches
 <replaceable>url/h</replaceable>, where <replaceable>h</replaceable>
 is the hash part of <replaceable>p</replaceable>.  Thus, if we have a
-cache <uri>http://cache.nixos.org</uri> and we want to obtain
-the store path
+cache <uri>https://cache.nixos.org</uri> and we want to obtain the
+store path
 <screen>
 /nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
 </screen>
 then Nix will attempt to fetch
 <screen>
-http://cache.nixos.org/a8922c0h87iilxzzvwn2hmv8x210aqb9.narinfo
+https://cache.nixos.org/a8922c0h87iilxzzvwn2hmv8x210aqb9.narinfo
 </screen>
 (Commands such as <command>nix-env -qas</command> will issue an HTTP
 HEAD request, since it only needs to know if the
@@ -389,7 +389,7 @@ The fields are as follows:
 references exist (e.g.,
 <filename>/nix/store/2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16</filename>),
 Nix will fetch <screen>
-http://cache.nixos.org/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
+https://cache.nixos.org/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
 </screen> and decompress and unpack it to
 <filename>/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7</filename>.</para>
 
diff --git a/doc/manual/command-ref/utilities.xml b/doc/manual/command-ref/utilities.xml
index d5650fd38f43..be2fe6e2d235 100644
--- a/doc/manual/command-ref/utilities.xml
+++ b/doc/manual/command-ref/utilities.xml
@@ -13,7 +13,9 @@ work with Nix.</para>
 <xi:include href="nix-collect-garbage.xml" />
 <xi:include href="nix-copy-closure.xml" />
 <xi:include href="nix-daemon.xml" />
+<!--
 <xi:include href="nix-generate-patches.xml" />
+-->
 <xi:include href="nix-hash.xml" />
 <xi:include href="nix-install-package.xml" />
 <xi:include href="nix-instantiate.xml" />
@@ -21,4 +23,4 @@ work with Nix.</para>
 <xi:include href="nix-pull.xml" />
 <xi:include href="nix-push.xml" />
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/doc/manual/expressions/custom-builder.xml b/doc/manual/expressions/custom-builder.xml
deleted file mode 100644
index c26deac40f4a..000000000000
--- a/doc/manual/expressions/custom-builder.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<section xmlns="http://docbook.org/ns/docbook"
-      xmlns:xlink="http://www.w3.org/1999/xlink"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      version="5.0"
-      xml:id="sec-custom-builder">
-
-<title>Customizing the Generic Builder</title>
-
-<para>The operation of the generic builder can be modified in many
-places by setting certain variables.  These <emphasis>hook
-variables</emphasis> are typically set to the name of some shell
-function defined by you.  For instance, to perform some additional
-steps after <command>make install</command> you would set the
-<varname>postInstall</varname> variable:
-
-<programlisting>
-postInstall=myPostInstall
-
-myPostInstall() {
-    mkdir $out/share/extra
-    cp extrafiles/* $out/share/extra
-}</programlisting>
-
-</para>
-
-</section>
\ No newline at end of file
diff --git a/doc/manual/expressions/debug-build.xml b/doc/manual/expressions/debug-build.xml
index 508cb2c1930e..0c1f4e6719b2 100644
--- a/doc/manual/expressions/debug-build.xml
+++ b/doc/manual/expressions/debug-build.xml
@@ -6,13 +6,14 @@
 
 <title>Debugging Build Failures</title>
 
-<para>At the beginning of each phase, the set of all shell variables
-is written to the file <filename>env-vars</filename> at the top-level
-build directory.  This is useful for debugging: it allows you to
-recreate the environment in which a build was performed.  For
-instance, if a build fails, then assuming you used the
-<option>-K</option> flag, you can go to the output directory and
-<quote>switch</quote> to the environment of the builder:
+<para>At the beginning of each phase of the build (such as unpacking,
+building or installing), the set of all shell variables is written to
+the file <filename>env-vars</filename> at the top-level build
+directory.  This is useful for debugging: it allows you to recreate
+the environment in which a build was performed.  For instance, if a
+build fails, then assuming you used the <option>-K</option> flag, you
+can go to the output directory and <quote>switch</quote> to the
+environment of the builder:
 
 <screen>
 $ nix-build -K ./foo.nix
@@ -30,4 +31,4 @@ $ make
 
 </para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/doc/manual/expressions/derivations.xml b/doc/manual/expressions/derivations.xml
index b57c33f4e3a9..90e2786faaab 100644
--- a/doc/manual/expressions/derivations.xml
+++ b/doc/manual/expressions/derivations.xml
@@ -110,12 +110,12 @@ buildInputs = [ pkg pkg.headers ];
 
 </itemizedlist>
 
-<para>The function <function>mkDerivation</function> in the standard
-environment is a wrapper around <function>derivation</function> that
-adds a default value for <varname>system</varname> and always uses
-Bash as the builder, to which the supplied builder is passed as a
-command-line argument.  See <xref linkend='sec-standard-environment'
-/>.</para>
+<para>The function <function>mkDerivation</function> in the Nixpkgs
+standard environment is a wrapper around
+<function>derivation</function> that adds a default value for
+<varname>system</varname> and always uses Bash as the builder, to
+which the supplied builder is passed as a command-line argument.  See
+the Nixpkgs manual for details.</para>
 
 <para>The builder is executed as follows:
 
@@ -208,4 +208,4 @@ command-line argument.  See <xref linkend='sec-standard-environment'
 
 <xi:include href="advanced-attributes.xml" />
 
-</section>
\ No newline at end of file
+</section>
diff --git a/doc/manual/expressions/generic-builder.xml b/doc/manual/expressions/generic-builder.xml
index f8567a042d47..db7ff405d8b1 100644
--- a/doc/manual/expressions/generic-builder.xml
+++ b/doc/manual/expressions/generic-builder.xml
@@ -71,7 +71,7 @@ genericBuild <co xml:id='ex-hello-builder2-co-3' /></programlisting>
     generic builder is smart enough to figure out whether to unpack
     the sources using <command>gzip</command>,
     <command>bzip2</command>, etc.  It can be customised in many ways;
-    see <xref linkend='sec-standard-environment' />.</para>
+    see the Nixpkgs manual for details.</para>
 
   </callout>
 
@@ -95,4 +95,4 @@ In fact, <varname>mkDerivation</varname> provides a default builder
 that looks exactly like that, so it is actually possible to omit the
 builder for Hello entirely.</para>
 
-</section>
\ No newline at end of file
+</section>
diff --git a/doc/manual/expressions/simple-building-testing.xml b/doc/manual/expressions/simple-building-testing.xml
index cc90409b5e93..e0dd98b7e67e 100644
--- a/doc/manual/expressions/simple-building-testing.xml
+++ b/doc/manual/expressions/simple-building-testing.xml
@@ -83,4 +83,6 @@ Just pass the option <link linkend='opt-max-jobs'><option>-j
 in parallel, or set.  Typically this should be the number of
 CPUs.</para>
 
-</section>
\ No newline at end of file
+<xi:include href="debug-build.xml" />
+
+</section>
diff --git a/doc/manual/expressions/standard-env.xml b/doc/manual/expressions/standard-env.xml
deleted file mode 100644
index 2571f43fccba..000000000000
--- a/doc/manual/expressions/standard-env.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<chapter xmlns="http://docbook.org/ns/docbook"
-      xmlns:xlink="http://www.w3.org/1999/xlink"
-      xmlns:xi="http://www.w3.org/2001/XInclude"
-      version="5.0"
-      xml:id='sec-standard-environment'>
-
-<title>The Standard Environment</title>
-
-
-<para>The standard environment is used by passing it as an input
-called <envar>stdenv</envar> to the derivation, and then doing
-
-<programlisting>
-source $stdenv/setup</programlisting>
-
-at the top of the builder.</para>
-
-<para>Apart from adding the aforementioned commands to the
-<envar>PATH</envar>, <filename>setup</filename> also does the
-following:
-
-<itemizedlist>
-
-  <listitem><para>All input packages specified in the
-  <envar>buildInputs</envar> environment variable have their
-  <filename>/bin</filename> subdirectory added to <envar>PATH</envar>,
-  their <filename>/include</filename> subdirectory added to the C/C++
-  header file search path, and their <filename>/lib</filename>
-  subdirectory added to the linker search path.  This can be extended.
-  For instance, when the <command>pkgconfig</command> package is
-  used, the subdirectory <filename>/lib/pkgconfig</filename> of each
-  input is added to the <envar>PKG_CONFIG_PATH</envar> environment
-  variable.</para></listitem>
-
-  <listitem><para>The environment variable
-  <envar>NIX_CFLAGS_STRIP</envar> is set so that the compiler strips
-  debug information from object files.  This can be disabled by
-  setting <envar>NIX_STRIP_DEBUG</envar> to
-  <literal>0</literal>.</para></listitem>
-
-</itemizedlist>
-
-</para>
-
-<para>The <filename>setup</filename> script also exports a function
-called <function>genericBuild</function> that knows how to build
-typical Autoconf-style packages.  It can be customised to perform
-builds for any type of package.  It is advisable to use
-<function>genericBuild</function> since it provides facilities that
-are almost always useful such as unpacking of sources, patching of
-sources, nested logging, etc.</para>
-
-<para>The definitive, up-to-date documentation of the generic builder
-is the source itself, which resides in
-<filename>pkgs/stdenv/generic/setup.sh</filename>.</para>
-
-<xi:include href="custom-builder.xml" />
-<xi:include href="debug-build.xml" />
-
-</chapter>
\ No newline at end of file
diff --git a/doc/manual/expressions/writing-nix-expressions.xml b/doc/manual/expressions/writing-nix-expressions.xml
index 6b797c200992..6646dddf0842 100644
--- a/doc/manual/expressions/writing-nix-expressions.xml
+++ b/doc/manual/expressions/writing-nix-expressions.xml
@@ -22,6 +22,5 @@ manual</link>.</para></note>
 
 <xi:include href="simple-expression.xml" />
 <xi:include href="expression-language.xml" />
-<xi:include href="standard-env.xml" />
 
 </part>
diff --git a/doc/manual/installation/multi-user.xml b/doc/manual/installation/multi-user.xml
index 312f5966452d..69ae1ef27041 100644
--- a/doc/manual/installation/multi-user.xml
+++ b/doc/manual/installation/multi-user.xml
@@ -23,11 +23,11 @@ daemon</emphasis> running under the owner of the Nix store/database
 that performs the operation.</para>
 
 <note><para>Multi-user mode has one important limitation: only
-<systemitem class="username">root</systemitem> can run <command
-linkend="sec-nix-pull">nix-pull</command> to register the availability
-of pre-built binaries.  However, those registrations are shared by all
-users, so they still get the benefit from <command>nix-pull</command>s
-done by <systemitem class="username">root</systemitem>.</para></note>
+<systemitem class="username">root</systemitem> and a set of trusted
+users specified in <filename>nix.conf</filename> can specify arbitrary
+binary caches. So while unprivileged users may install packages from
+arbitrary Nix expressions, they may not get pre-built
+binaries.</para></note>
 
 
 <simplesect>
diff --git a/doc/manual/introduction/about-nix.xml b/doc/manual/introduction/about-nix.xml
index 56ec39916b6c..efd6cf2bb347 100644
--- a/doc/manual/introduction/about-nix.xml
+++ b/doc/manual/introduction/about-nix.xml
@@ -166,8 +166,8 @@ cache</emphasis>, a web server that provides pre-built binaries. For
 instance, when asked to build
 <literal>/nix/store/b6gvzjyb2pg0…-firefox-33.1</literal> from source,
 Nix would first check if the file
-<uri>http://cache.nixos.org/b6gvzjyb2pg0….narinfo</uri> exists, and if
-so, fetch the pre-built binary referenced from there; otherwise, it
+<uri>https://cache.nixos.org/b6gvzjyb2pg0….narinfo</uri> exists, and
+if so, fetch the pre-built binary referenced from there; otherwise, it
 would fall back to building from source.</para>
 
 </simplesect>
diff --git a/doc/manual/local.mk b/doc/manual/local.mk
index 4caef57783c0..3d7e7fed9631 100644
--- a/doc/manual/local.mk
+++ b/doc/manual/local.mk
@@ -7,9 +7,11 @@ XSLTPROC = $(xsltproc) --nonet $(xmlflags) \
   --param admon.style \'\' \
   --param callout.graphics.extension \'.gif\' \
   --param contrib.inline.enabled 0 \
-  --stringparam generate.toc "book toc"
+  --stringparam generate.toc "book toc" \
+  --param keep.relative.image.uris 0
 
-docbookxsl = http://docbook.sourceforge.net/release/xsl-ns/1.78.1/
+docbookxsl = http://docbook.sourceforge.net/release/xsl-ns/1.78.1
+docbookrng = http://docbook.org/xml/5.0/rng/docbook.rng
 
 MANUAL_SRCS := $(call rwildcard, $(d), *.xml)
 
@@ -26,7 +28,7 @@ $(d)/version.txt:
 $(d)/manual.is-valid: $(d)/manual.xmli
 	$(trace-gen) $(XSLTPROC) --novalid --stringparam profile.condition manual \
 	  $(docbookxsl)/profiling/profile.xsl $< 2> /dev/null | \
-	  $(xmllint) --nonet --noout --relaxng http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng -
+	  $(xmllint) --nonet --noout --relaxng $(docbookrng) -
 	@touch $@
 
 clean-files += $(d)/manual.xmli $(d)/version.txt $(d)/manual.is-valid
@@ -38,7 +40,7 @@ dist-files += $(d)/manual.xmli $(d)/version.txt $(d)/manual.is-valid
 man-pages := $(foreach n, \
   nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \
   nix-collect-garbage.1 nix-push.1 nix-pull.1 \
-  nix-prefetch-url.1 nix-channel.1 nix-generate-patches.1 \
+  nix-prefetch-url.1 nix-channel.1 \
   nix-install-package.1 nix-hash.1 nix-copy-closure.1 \
   nix.conf.5 nix-daemon.8, \
   $(d)/$(n))
diff --git a/doc/manual/manual.xml b/doc/manual/manual.xml
index 5c46f303a11c..b784bb5f3c22 100644
--- a/doc/manual/manual.xml
+++ b/doc/manual/manual.xml
@@ -41,7 +41,7 @@
   <xi:include href="installation/installation.xml" />
   <xi:include href="packages/package-management.xml" />
   <xi:include href="expressions/writing-nix-expressions.xml" />
-  <xi:include href="builds/build-farm.xml" />
+  <xi:include href="advanced-topics/advanced-topics.xml" />
   <xi:include href="command-ref/command-ref.xml" />
   <xi:include href="troubleshooting/troubleshooting.xml" />
   <xi:include href="glossary/glossary.xml" />
diff --git a/doc/manual/packages/basic-package-mgmt.xml b/doc/manual/packages/basic-package-mgmt.xml
index 69c955c1dd11..540d3ec223cc 100644
--- a/doc/manual/packages/basic-package-mgmt.xml
+++ b/doc/manual/packages/basic-package-mgmt.xml
@@ -28,40 +28,71 @@ Nix expressions called the Nix Package collection that contains
 packages ranging from basic development stuff such as GCC and Glibc,
 to end-user applications like Mozilla Firefox.  (Nix is however not
 tied to the Nix Package collection; you could write your own Nix
-expressions based on it, or completely new ones.)  You can download
-the latest version from <link
-xlink:href='http://nixos.org/nixpkgs/download.html' />.</para>
+expressions based on it, or completely new ones.)</para>
+
+<para>You can manually download the latest version of Nixpkgs from
+<link xlink:href='http://nixos.org/nixpkgs/download.html'/>. However,
+it’s much more convenient to use the Nixpkgs
+<emphasis>channel</emphasis>, since it makes it easy to stay up to
+date with new versions of Nixpkgs. (Channels are described in more
+detail in <xref linkend="sec-channels"/>.) Nixpkgs is automatically
+added to your list of “subscribed” channels when when you install
+Nix. If this is not the case for some reason, you can add it as
+follows:
 
-<para>Assuming that you have downloaded and unpacked a release of Nix
-Packages, you can view the set of available packages in the release:
+<screen>
+$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable
+$ nix-channel --update
+</screen>
+
+</para>
+
+<note><para>On NixOS, you’re automatically subscribed to a NixOS
+channel corresponding to your NixOS major release
+(e.g. <uri>http://nixos.org/channels/nixos-14.12</uri>). A NixOS
+channel is identical to the Nixpkgs channel, except that it contains
+only Linux binaries and is updated only if a set of regression tests
+succeed.</para></note>
+
+<para>You can view the set of available packages in Nixpkgs:
 
 <screen>
-$ nix-env -qaf nixpkgs-<replaceable>version</replaceable> '*'
-ant-blackdown-1.4.2
+$ nix-env -qa
 aterm-2.2
 bash-3.0
 binutils-2.15
 bison-1.875d
 blackdown-1.4.2
 bzip2-1.0.2
-...</screen>
-
-where <literal>nixpkgs-<replaceable>version</replaceable></literal> is
-where you’ve unpacked the release.  The flag <option>-q</option>
-specifies a query operation; <option>-a</option> means that you want
-to show the “available” (i.e., installable) packages, as opposed to
-the installed packages; and <option>-f</option>
-<filename>nixpkgs-<replaceable>version</replaceable></filename>
-specifies the source of the packages.  The argument
-<literal>'*'</literal> shows all installable packages. (The quotes are
-necessary to prevent shell expansion.)  You can also select specific
-packages by name:
+…</screen>
+
+The flag <option>-q</option> specifies a query operation, and
+<option>-a</option> means that you want to show the “available” (i.e.,
+installable) packages, as opposed to the installed packages. If you
+downloaded Nixpkgs yourself, or if you checked it out from GitHub,
+then you need to pass the path to your Nixpkgs tree using the
+<option>-f</option> flag:
+
+<screen>
+$ nix-env -qaf <replaceable>/path/to/nixpkgs</replaceable>
+</screen>
+
+where <replaceable>/path/to/nixpkgs</replaceable> is where you’ve
+unpacked or checked out Nixpkgs.</para>
+
+<para>You can select specific packages by name:
+
+<screen>
+$ nix-env -qa firefox
+firefox-34.0.5
+firefox-with-plugins-34.0.5
+</screen>
+
+and using regular expressions:
 
 <screen>
-$ nix-env -qaf nixpkgs-<replaceable>version</replaceable> gcc
-gcc-3.4.6
-gcc-4.0.3
-gcc-4.1.1</screen>
+$ nix-env -qa 'firefox.*'
+</screen>
 
 </para>
 
@@ -70,12 +101,12 @@ available packages, i.e., whether they are installed into the user
 environment and/or present in the system:
 
 <screen>
-$ nix-env -qasf nixpkgs-<replaceable>version</replaceable> '*'
-...
+$ nix-env -qas
+…
 -PS bash-3.0
 --S binutils-2.15
 IPS bison-1.875d
-...</screen>
+…</screen>
 
 The first character (<literal>I</literal>) indicates whether the
 package is installed in your current user environment.  The second
@@ -88,40 +119,33 @@ just means that Nix knows that it can fetch a pre-built package from
 somewhere (typically a network server) instead of building it
 locally.</para>
 
-<para>So now that we have a set of Nix expressions we can build the
-packages contained in them.  This is done using <literal>nix-env
--i</literal>.  For instance,
+<para>You can install a package using <literal>nix-env -i</literal>.
+For instance,
 
 <screen>
-$ nix-env -f nixpkgs-<replaceable>version</replaceable> -i subversion</screen>
+$ nix-env -i subversion</screen>
 
 will install the package called <literal>subversion</literal> (which
 is, of course, the <link
 xlink:href='http://subversion.tigris.org/'>Subversion version
 management system</link>).</para>
 
-<para>When you do this for the first time, Nix will start building
-Subversion and all its dependencies.  This will take quite a while —
-typically an hour or two on modern machines.  Fortunately, there is a
-faster way (so do a Ctrl-C on that install operation!): you just need
-to tell Nix that pre-built binaries of all those packages are
-available somewhere.  This is done using the
-<command>nix-pull</command> command, which must be supplied with a URL
-containing a <emphasis>manifest</emphasis> describing what binaries
-are available.  This URL should correspond to the Nix Packages release
-that you’re using.  For instance, if you obtained a release from <link
-xlink:href='http://nixos.org/releases/nixpkgs/nixpkgs-0.12pre11712-4lrp7j8x'
-/>, then you should do:
-
-<screen>
-$ nix-pull http://nixos.org/releases/nixpkgs/nixpkgs-0.12pre11712-4lrp7j8x/MANIFEST</screen>
-
-If you then issue the installation command, it should start
-downloading binaries from <systemitem
-class='fqdomainname'>nixos.org</systemitem>, instead of building
-them from source.  This might still take a while since all
-dependencies must be downloaded, but on a reasonably fast connection
-such as a DSL line it’s on the order of a few minutes.</para>
+<note><para>When you ask Nix to install a package, it will first try
+to get it in pre-compiled form from a <emphasis>binary
+cache</emphasis>. By default, Nix will use the binary cache
+<uri>https://cache.nixos.org</uri>; it contains binaries for most
+packages in Nixpkgs. Only if no binary is available in the binary
+cache, Nix will build the package from source. So if <literal>nix-env
+-i subversion</literal> results in Nix building stuff from source,
+then either the package is not built for your platform by the Nixpkgs
+build servers, or your version of Nixpkgs is too old or too new. For
+instance, if you have a very recent checkout of Nixpkgs, then the
+Nixpkgs build servers may not have had a chance to build everything
+and upload the resulting binaries to
+<uri>https://cache.nixos.org</uri>. The Nixpkgs channel is only
+updated after all binaries have been uploaded to the cache, so if you
+stick to the Nixpkgs channel (rather than using a Git checkout of the
+Nixpkgs tree), you will get binaries for most packages.</para></note>
 
 <para>Naturally, packages can also be uninstalled:
 
@@ -134,7 +158,7 @@ $ nix-env -e subversion</screen>
 release of Nix Packages, you can do:
 
 <screen>
-$ nix-env -f nixpkgs-<replaceable>version</replaceable> -u subversion</screen>
+$ nix-env -u subversion</screen>
 
 This will <emphasis>only</emphasis> upgrade Subversion if there is a
 “newer” version in the new set of Nix expressions, as
@@ -149,17 +173,17 @@ whatever version is already installed.</para>
 versions:
 
 <screen>
-$ nix-env -f nixpkgs-<replaceable>version</replaceable> -u '*'</screen>
+$ nix-env -u</screen>
 
 </para>
 
 <para>Sometimes it’s useful to be able to ask what
 <command>nix-env</command> would do, without actually doing it.  For
 instance, to find out what packages would be upgraded by
-<literal>nix-env -u '*'</literal>, you can do
+<literal>nix-env -u</literal>, you can do
 
 <screen>
-$ nix-env ... -u '*' --dry-run
+$ nix-env -u --dry-run
 (dry run; not doing anything)
 upgrading `libxslt-1.1.0' to `libxslt-1.1.10'
 upgrading `graphviz-1.10' to `graphviz-1.12'
@@ -167,4 +191,4 @@ upgrading `coreutils-5.0' to `coreutils-5.2.1'</screen>
 
 </para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/doc/manual/packages/channels.xml b/doc/manual/packages/channels.xml
index 094e11fe3b15..15c119fcb1f9 100644
--- a/doc/manual/packages/channels.xml
+++ b/doc/manual/packages/channels.xml
@@ -8,10 +8,9 @@
 
 <para>If you want to stay up to date with a set of packages, it’s not
 very convenient to manually download the latest set of Nix expressions
-for those packages, use <command>nix-pull</command> to register
-pre-built binaries (if available), and upgrade using
-<command>nix-env</command>.  Fortunately, there’s a better way:
-<emphasis>Nix channels</emphasis>.</para>
+for those packages and upgrade using <command>nix-env</command>.
+Fortunately, there’s a better way: <emphasis>Nix
+channels</emphasis>.</para>
 
 <para>A Nix channel is just a URL that points to a place that contains
 a set of Nix expressions and a manifest.  Using the command <link
@@ -23,35 +22,36 @@ URL.</para>
 <command>nix-channel --add</command>, e.g.,
 
 <screen>
-$ nix-channel --add http://nixos.org/channels/nixpkgs-unstable</screen>
+$ nix-channel --add https://nixos.org/channels/nixpkgs-unstable</screen>
 
 subscribes you to a channel that always contains that latest version
-of the Nix Packages collection.  (Instead of
-<literal>nixpkgs-unstable</literal> you could also subscribe to
-<literal>nixpkgs-stable</literal>, which should have a higher level of
-stability, but right now is just outdated.)  Subscribing really just
-means that the URL is added to the file
-<filename>~/.nix-channels</filename>.  Right now there is no command
-to “unsubscribe”; you should just edit that file manually
-and delete the offending URL.</para>
+of the Nix Packages collection.  (Subscribing really just means that
+the URL is added to the file <filename>~/.nix-channels</filename>,
+where it is read by subsequent calls to <command>nix-channel
+--update</command>.) You can “unsubscribe” using <command>nix-channel
+--remove</command>:
+
+<screen>
+$ nix-channel --remove nixpkgs
+</screen>
+</para>
 
 <para>To obtain the latest Nix expressions available in a channel, do
 
 <screen>
 $ nix-channel --update</screen>
 
-This downloads the Nix expressions in every channel (downloaded from
-<literal><replaceable>url</replaceable>/nixexprs.tar.bz2</literal>)
-and registers any available pre-built binaries in every channel
-(by <command>nix-pull</command>ing
-<literal><replaceable>url</replaceable>/MANIFEST</literal>).  It also
-makes the union of each channel’s Nix expressions the default for
-<command>nix-env</command> operations.  Consequently, you can then say
+This downloads and unpacks the Nix expressions in every channel
+(downloaded from <literal><replaceable>url</replaceable>/nixexprs.tar.bz2</literal>).
+It also makes the union of each channel’s Nix expressions available by
+default to <command>nix-env</command> operations (via the symlink
+<filename>~/.nix-defexpr/channels</filename>).  Consequently, you can
+then say
 
 <screen>
-$ nix-env -u '*'</screen>
+$ nix-env -u</screen>
 
 to upgrade all packages in your profile to the latest versions
 available in the subscribed channels.</para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/doc/manual/packages/garbage-collection.xml b/doc/manual/packages/garbage-collection.xml
index ae28c485f076..03b8e4c976c1 100644
--- a/doc/manual/packages/garbage-collection.xml
+++ b/doc/manual/packages/garbage-collection.xml
@@ -37,7 +37,14 @@ generations, e.g.,
 <screen>
 $ nix-env --delete-generations 10 11 14</screen>
 
-</para>
+To delete all generations older than a specified number of days
+(except the current generation), use the <literal>d</literal>
+suffix. For example,
+
+<screen>
+$ nix-env --delete-generations 14d</screen>
+
+deletes all generations older than two weeks.</para>
 
 <para>After removing appropriate old generations you can run the
 garbage collector as follows:
@@ -67,4 +74,4 @@ is a quick and easy way to clean up your system.</para>
 
 <xi:include href="garbage-collector-roots.xml" />
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/doc/manual/packages/profiles.xml b/doc/manual/packages/profiles.xml
index ad5e92aeb64b..60660056fb8e 100644
--- a/doc/manual/packages/profiles.xml
+++ b/doc/manual/packages/profiles.xml
@@ -30,7 +30,7 @@ store.</para>
 <figure xml:id='fig-user-environments'><title>User environments</title>
   <mediaobject>
     <imageobject>
-      <imagedata fileref='figures/user-environments.png' format='PNG' />
+      <imagedata fileref='../figures/user-environments.png' format='PNG' />
     </imageobject>
   </mediaobject>
 </figure>
@@ -73,9 +73,9 @@ generated based on the current one.  For instance, generation 43 was
 created from generation 42 when we did
 
 <screen>
-$ nix-env -i subversion mozilla</screen>
+$ nix-env -i subversion firefox</screen>
 
-on a set of Nix expressions that contained Mozilla and a new version
+on a set of Nix expressions that contained Firefox and a new version
 of Subversion.</para>
 
 <para>Generations are grouped together into
@@ -156,4 +156,4 @@ $ nix-env -p /nix/var/nix/profiles/other-profile -i subversion</screen>
 This will <emphasis>not</emphasis> change the
 <command>~/.nix-profile</command> symlink.</para>
 
-</chapter>
\ No newline at end of file
+</chapter>
diff --git a/doc/manual/release-notes/rl-1.8.xml b/doc/manual/release-notes/rl-1.8.xml
index 310aa54796d6..b812915a95cd 100644
--- a/doc/manual/release-notes/rl-1.8.xml
+++ b/doc/manual/release-notes/rl-1.8.xml
@@ -4,7 +4,7 @@
       version="5.0"
       xml:id="ssec-relnotes-1.8">
 
-<title>Release 1.8 (TBA)</title>
+<title>Release 1.8 (December 9, 2014)</title>
 
 <itemizedlist>
 
@@ -13,6 +13,10 @@
   --serve</command> on the remote machine. This requires build slaves
   to be updated to Nix 1.8.</para></listitem>
 
+  <listitem><para>Nix now uses HTTPS instead of HTTP to access the
+  default binary cache,
+  <literal>cache.nixos.org</literal>.</para></listitem>
+
   <listitem><para><command>nix-env</command> selectors are now regular
   expressions. For instance, you can do
 
diff --git a/doc/manual/style.css b/doc/manual/style.css
index f805aeab076c..53fd9d5709c3 100644
--- a/doc/manual/style.css
+++ b/doc/manual/style.css
@@ -23,6 +23,11 @@ h1 /* title */
     font-size: 200%;
 }
 
+div.part h1
+{
+    font-size: 240%;
+}
+
 h2 /* chapters, appendices, subtitle */
 {
     font-size: 180%;
@@ -30,7 +35,7 @@ h2 /* chapters, appendices, subtitle */
 
 div.part
 {
-    margin-top: 2em;
+    margin-top: 4em;
 }
 
 /* Extra space between chapters, appendices. */
@@ -61,6 +66,12 @@ div.appendix h3
     margin-top: 1.5em;
 }
 
+div.refentry\.separator
+{
+    margin-top: 2.5em;
+    margin-bottom: 2em;
+}
+
 div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */
 {
     margin-top: 1.4em;
diff --git a/doc/manual/troubleshooting/links-nix-store.xml b/doc/manual/troubleshooting/links-nix-store.xml
index c81477bd4f27..c768889567d0 100644
--- a/doc/manual/troubleshooting/links-nix-store.xml
+++ b/doc/manual/troubleshooting/links-nix-store.xml
@@ -20,7 +20,7 @@ in <filename>/nix/store</filename>, as can be seen using <command>ls
 -l</command>:
 
 <screen>
-$ ls -l /nix/store
+$ ls -ld /nix/store
 drwxrwxrwt 32000 nix nix 4620288 Sep 8 15:08 store</screen>
 
 The <literal>ext2</literal> file system is limited to an inode link
@@ -35,9 +35,9 @@ machines).</para>
 the <option>--max-links</option> option.</para>
 
 <para>Real solution: put the Nix store on a file system that supports
-more than 32,000 subdirectories per directory, such as ReiserFS.
-(This doesn’t solve the <literal>st_nlink</literal> limit, but
-ReiserFS lies to the kernel by reporting a link count of 1 if it
-exceeds the limit.)</para>
+more than 32,000 subdirectories per directory, such as ext4.  (This
+doesn’t solve the <literal>st_nlink</literal> limit, but ext4 lies to
+the kernel by reporting a link count of 1 if it exceeds the
+limit.)</para>
 
 </section>
diff --git a/doc/signing.txt b/doc/signing.txt
index 1d042e95e220..7403cac470b2 100644
--- a/doc/signing.txt
+++ b/doc/signing.txt
@@ -1,6 +1,6 @@
 Generate a private key:
 
-$ (umask 277 && openssl genrsa -out /nix/etc/nix/signing-key.sec 2048)
+$ (umask 277 && openssl genrsa -out /etc/nix/signing-key.sec 2048)
 
 The private key should be kept secret (only readable to the Nix daemon
 user).
@@ -8,7 +8,7 @@ user).
 
 Generate the corresponding public key:
 
-$ openssl rsa -in /nix/etc/nix/signing-key.sec -pubout > /nix/etc/nix/signing-key.pub
+$ openssl rsa -in /etc/nix/signing-key.sec -pubout > /etc/nix/signing-key.pub
 
 The public key should be copied to all machines to which you want to
 export store paths.
diff --git a/mk/functions.mk b/mk/functions.mk
index 45d917399391..c48775db8c3b 100644
--- a/mk/functions.mk
+++ b/mk/functions.mk
@@ -10,5 +10,5 @@ filename-to-dep = $(dir $1).$(notdir $1).dep
 # empty string if not found.
 find-program = $(shell for i in $$(IFS=: ; echo $$PATH); do p=$$i/$(strip $1); if [ -e $$p ]; then echo $$p; break; fi; done)
 
-# Remove trailing slash.
+# Ensure that the given string ends in a single slash.
 add-trailing-slash = $(patsubst %/,%,$(1))/
diff --git a/mk/jars.mk b/mk/jars.mk
index 99470f37435b..c8513e664ed5 100644
--- a/mk/jars.mk
+++ b/mk/jars.mk
@@ -1,4 +1,5 @@
 define build-jar
+
   $(1)_NAME ?= $(1)
 
   _d := $$(strip $$($(1)_DIR))
@@ -7,14 +8,20 @@ define build-jar
 
   $(1)_TMPDIR := $$(_d)/.$$($(1)_NAME).jar.tmp
 
-  $$($(1)_PATH): $$($(1)_SOURCES)
+  _jars := $$(foreach jar, $$($(1)_JARS), $$($$(jar)_PATH))
+
+  $$($(1)_PATH): $$($(1)_SOURCES) $$(_jars) $$($(1)_EXTRA_DEPS)| $$($(1)_ORDER_AFTER)
 	@rm -rf $$($(1)_TMPDIR)
 	@mkdir -p $$($(1)_TMPDIR)
-	$$(trace-javac) javac $(GLOBAL_JAVACFLAGS) $$($(1)_JAVACFLAGS) -d $$($(1)_TMPDIR) $$($(1)_SOURCES)
-	$$(trace-jar) jar cf $$($(1)_PATH) -C $$($(1)_TMPDIR) .
+	$$(trace-javac) javac $(GLOBAL_JAVACFLAGS) $$($(1)_JAVACFLAGS) -d $$($(1)_TMPDIR) \
+	  $$(foreach fn, $$($(1)_SOURCES), '$$(fn)') \
+	  -cp "$$(subst $$(space),,$$(foreach jar,$$($(1)_JARS),$$($$(jar)_PATH):))$$$$CLASSPATH"
+	@echo -e '$$(subst $$(newline),\n,$$($(1)_MANIFEST))' > $$($(1)_PATH).manifest
+	$$(trace-jar) jar cfm $$($(1)_PATH) $$($(1)_PATH).manifest -C $$($(1)_TMPDIR) .
+	@rm $$($(1)_PATH).manifest
 	@rm -rf $$($(1)_TMPDIR)
 
-  $(1)_INSTALL_DIR ?= $$(libdir)/java
+  $(1)_INSTALL_DIR ?= $$(jardir)
 
   $(1)_INSTALL_PATH := $$($(1)_INSTALL_DIR)/$$($(1)_NAME).jar
 
diff --git a/mk/lib.mk b/mk/lib.mk
index f7c8c6b3aa84..4ad5c636c8d4 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -14,17 +14,40 @@ dist-files :=
 OS = $(shell uname -s)
 
 
+# Hack to define a literal space.
+space :=
+space +=
+
+
+# Hack to define a literal newline.
+define newline
+
+
+endef
+
+
 # Default installation paths.
 prefix ?= /usr/local
 libdir ?= $(prefix)/lib
 bindir ?= $(prefix)/bin
 libexecdir ?= $(prefix)/libexec
 datadir ?= $(prefix)/share
+jardir ?= $(datadir)/java
 localstatedir ?= $(prefix)/var
 sysconfdir ?= $(prefix)/etc
 mandir ?= $(prefix)/share/man
 
 
+# Initialise support for build directories.
+builddir ?=
+
+ifdef builddir
+  buildprefix = $(builddir)/
+else
+  buildprefix =
+endif
+
+
 # Pass -fPIC if we're building dynamic libraries.
 BUILD_SHARED_LIBS ?= 1
 
@@ -44,7 +67,6 @@ ifeq ($(BUILD_SHARED_LIBS), 1)
   SET_RPATH_TO_LIBS ?= 1
 endif
 
-
 # Pass -g if we want debug info.
 BUILD_DEBUG ?= 1
 
diff --git a/mk/libraries.mk b/mk/libraries.mk
index 3b292e988dca..3cd7a53107bd 100644
--- a/mk/libraries.mk
+++ b/mk/libraries.mk
@@ -49,9 +49,9 @@ endif
 #   built, otherwise a static library.
 define build-library
   $(1)_NAME ?= $(1)
-  _d := $$(strip $$($(1)_DIR))
+  _d := $(buildprefix)$$(strip $$($(1)_DIR))
   _srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src)))
-  $(1)_OBJS := $$(addsuffix .o, $$(basename $$(_srcs)))
+  $(1)_OBJS := $$(addprefix $(buildprefix), $$(addsuffix .o, $$(basename $$(_srcs))))
   _libs := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_PATH))
 
   ifeq (CYGWIN,$(findstring CYGWIN,$(OS)))
@@ -86,9 +86,12 @@ define build-library
     $(1)_PATH := $$(_d)/$$($(1)_NAME).$(SO_EXT)
 
     $$($(1)_PATH): $$($(1)_OBJS) $$(_libs) | $$(_d)/
-	$$(trace-ld) $(CXX) -o $$@ -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE))
+	$$(trace-ld) $(CXX) -o $$(abspath $$@) -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE)) $$($(1)_LDFLAGS_UNINSTALLED)
 
-    $(1)_LDFLAGS_USE += -L$$(_d) -Wl,-rpath,$$(abspath $$(_d)) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))
+    ifneq ($(OS), Darwin)
+      $(1)_LDFLAGS_USE += -Wl,-rpath,$$(abspath $$(_d))
+    endif
+    $(1)_LDFLAGS_USE += -L$$(_d) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))
 
     $(1)_INSTALL_PATH := $(DESTDIR)$$($(1)_INSTALL_DIR)/$$($(1)_NAME).$(SO_EXT)
 
@@ -100,10 +103,12 @@ define build-library
 	$$(trace-ld) $(CXX) -o $$@ -shared $$(GLOBAL_LDFLAGS) $$($(1)_OBJS) $$($(1)_LDFLAGS) $$($(1)_LDFLAGS_PROPAGATED) $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_LDFLAGS_USE_INSTALLED))
 
     $(1)_LDFLAGS_USE_INSTALLED += -L$$(DESTDIR)$$($(1)_INSTALL_DIR) -l$$(patsubst lib%,%,$$(strip $$($(1)_NAME)))
-    ifeq ($(SET_RPATH_TO_LIBS), 1)
-      $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath,$$($(1)_INSTALL_DIR)
-    else
-      $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath-link,$$($(1)_INSTALL_DIR)
+    ifneq ($(OS), Darwin)
+      ifeq ($(SET_RPATH_TO_LIBS), 1)
+        $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath,$$($(1)_INSTALL_DIR)
+      else
+        $(1)_LDFLAGS_USE_INSTALLED += -Wl,-rpath-link,$$($(1)_INSTALL_DIR)
+      endif
     endif
 
     ifdef $(1)_FORCE_INSTALL
diff --git a/mk/patterns.mk b/mk/patterns.mk
index 6b2cfd017050..3219d9629fbf 100644
--- a/mk/patterns.mk
+++ b/mk/patterns.mk
@@ -1,8 +1,11 @@
-%.o: %.cc
+$(buildprefix)%.o: %.cc
+	@mkdir -p "$(dir $@)"
 	$(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP
 
-%.o: %.cpp
+$(buildprefix)%.o: %.cpp
+	@mkdir -p "$(dir $@)"
 	$(trace-cxx) $(CXX) -o $@ -c $< $(GLOBAL_CXXFLAGS) $(GLOBAL_CXXFLAGS_PCH) $(CXXFLAGS) $($@_CXXFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP
 
-%.o: %.c
+$(buildprefix)%.o: %.c
+	@mkdir -p "$(dir $@)"
 	$(trace-cc) $(CC) -o $@ -c $< $(GLOBAL_CFLAGS) $(CFLAGS) $($@_CFLAGS) -MMD -MF $(call filename-to-dep, $@) -MP
diff --git a/mk/programs.mk b/mk/programs.mk
index 72afdf95251b..3ac64494e3a5 100644
--- a/mk/programs.mk
+++ b/mk/programs.mk
@@ -23,9 +23,9 @@ programs-list :=
 # - $(1)_INSTALL_DIR: the directory where the program will be
 #   installed; defaults to $(bindir).
 define build-program
-  _d := $$($(1)_DIR)
+  _d := $(buildprefix)$$($(1)_DIR)
   _srcs := $$(sort $$(foreach src, $$($(1)_SOURCES), $$(src)))
-  $(1)_OBJS := $$(addsuffix .o, $$(basename $$(_srcs)))
+  $(1)_OBJS := $$(addprefix $(buildprefix), $$(addsuffix .o, $$(basename $$(_srcs))))
   _libs := $$(foreach lib, $$($(1)_LIBS), $$($$(lib)_PATH))
   $(1)_PATH := $$(_d)/$(1)
 
diff --git a/mk/templates.mk b/mk/templates.mk
index ab99168bb7a5..c7ac7afbff27 100644
--- a/mk/templates.mk
+++ b/mk/templates.mk
@@ -8,8 +8,12 @@ define instantiate-template
 
 endef
 
+ifneq ($(MAKECMDGOALS), clean)
+
 %.h: %.h.in
 	$(trace-gen) rm -f $@ && ./config.status --quiet --header=$@
 
 %: %.in
 	$(trace-gen) rm -f $@ && ./config.status --quiet --file=$@
+
+endif
diff --git a/release.nix b/release.nix
index af0e2362baf8..a08cf7a96c81 100644
--- a/release.nix
+++ b/release.nix
@@ -122,15 +122,16 @@ let
       in
 
       runCommand "nix-binary-tarball-${version}"
-        { exportReferencesGraph = [ "closure" toplevel ];
+        { exportReferencesGraph = [ "closure1" toplevel "closure2" cacert ];
           buildInputs = [ perl ];
           meta.description = "Distribution-independent Nix bootstrap binaries for ${system}";
         }
         ''
-          storePaths=$(perl ${pathsFromGraph} ./closure)
-          printRegistration=1 perl ${pathsFromGraph} ./closure > $TMPDIR/reginfo
+          storePaths=$(perl ${pathsFromGraph} ./closure1 ./closure2)
+          printRegistration=1 perl ${pathsFromGraph} ./closure1 ./closure2 > $TMPDIR/reginfo
           substitute ${./scripts/install-nix-from-closure.sh} $TMPDIR/install \
-            --subst-var-by nix ${toplevel}
+            --subst-var-by nix ${toplevel} \
+            --subst-var-by cacert ${cacert}
           chmod +x $TMPDIR/install
           dir=nix-${version}-${system}
           fn=$out/$dir.tar.bz2
diff --git a/scripts/download-from-binary-cache.pl.in b/scripts/download-from-binary-cache.pl.in
index e272f139cf8c..6285a0503682 100644
--- a/scripts/download-from-binary-cache.pl.in
+++ b/scripts/download-from-binary-cache.pl.in
@@ -42,9 +42,16 @@ my $curlIdCount = 1;
 my %requests;
 my %scheduled;
 my $caBundle = $ENV{"SSL_CERT_FILE"} // $ENV{"CURL_CA_BUNDLE"} // $ENV{"OPENSSL_X509_CERT_FILE"};
+$caBundle = "/etc/ssl/certs/ca-bundle.crt" if !$caBundle && -f "/etc/ssl/certs/ca-bundle.crt";
+$caBundle = "/etc/ssl/certs/ca-certificates.crt" if !$caBundle && -f "/etc/ssl/certs/ca-certificates.crt";
 
 my $userName = getpwuid($<) || $ENV{"USER"} or die "cannot figure out user name";
 
+sub isTrue {
+    my ($x) = @_;
+    return $x eq "true" || $x eq "1";
+}
+
 my $requireSignedBinaryCaches = ($Nix::Config::config{"signed-binary-caches"} // "0") ne "0";
 
 my $curlConnectTimeout = int(
@@ -67,6 +74,7 @@ sub addRequest {
     $curl->setopt(CURLOPT_WRITEDATA, $fh);
     $curl->setopt(CURLOPT_FOLLOWLOCATION, 1);
     $curl->setopt(CURLOPT_CAINFO, $caBundle) if defined $caBundle;
+    $curl->setopt(CURLOPT_SSL_VERIFYPEER, 0) unless isTrue($Nix::Config::config{"verify-https-binary-caches"} // "1");
     $curl->setopt(CURLOPT_USERAGENT, "Nix/$Nix::Config::version");
     $curl->setopt(CURLOPT_NOBODY, 1) if $head;
     $curl->setopt(CURLOPT_FAILONERROR, 1);
@@ -218,7 +226,7 @@ sub getAvailableCaches {
     }
 
     my @urls = strToList($Nix::Config::config{"binary-caches"} //
-        ($Nix::Config::storeDir eq "/nix/store" ? "http://cache.nixos.org" : ""));
+        ($Nix::Config::storeDir eq "/nix/store" ? "https://cache.nixos.org" : ""));
 
     my $urlsFiles = $Nix::Config::config{"binary-cache-files"}
         // "$Nix::Config::stateDir/profiles/per-user/$userName/channels/binary-caches/*";
diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh
index 60ec1ea93219..c9ba9a2a280a 100644
--- a/scripts/install-nix-from-closure.sh
+++ b/scripts/install-nix-from-closure.sh
@@ -5,6 +5,7 @@ set -e
 dest="/nix"
 self="$(dirname "$0")"
 nix="@nix@"
+cacert="@cacert@"
 
 if ! [ -e $self/.reginfo ]; then
     echo "$0: incomplete installer (.reginfo is missing)" >&2
@@ -66,26 +67,25 @@ fi
 
 . $nix/etc/profile.d/nix.sh
 
-if ! $nix/bin/nix-env -i $nix; then
+if ! $nix/bin/nix-env -i "$nix"; then
     echo "$0: unable to install Nix into your default profile" >&2
     exit 1
 fi
 
+# Install an SSL certificate bundle.
+if [ -z "$SSL_CERT_FILE" -o ! -f "$SSL_CERT_FILE" ]; then
+    $nix/bin/nix-env -i "$cacert"
+    export SSL_CERT_FILE="$HOME/.nix-profile/etc/ca-bundle.crt"
+fi
+
 # Subscribe the user to the Nixpkgs channel and fetch it.
 if ! $nix/bin/nix-channel --list | grep -q "^nixpkgs "; then
-    if [ -n "$SSL_CERT_FILE" ]; then
-        $nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
-    else
-        $nix/bin/nix-channel --add http://nixos.org/channels/nixpkgs-unstable
-    fi
+    $nix/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable
 fi
 if [ -z "$_NIX_INSTALLER_TEST" ]; then
     $nix/bin/nix-channel --update nixpkgs
 fi
 
-# Install an SSL certificate bundle.
-$nix/bin/nix-env -iA nixpkgs.cacert || true
-
 # Make the shell source nix.sh during login.
 p=$NIX_LINK/etc/profile.d/nix.sh
 
diff --git a/scripts/nix-profile.sh.in b/scripts/nix-profile.sh.in
index 7dd7968c314a..a91b54bd589f 100644
--- a/scripts/nix-profile.sh.in
+++ b/scripts/nix-profile.sh.in
@@ -10,9 +10,9 @@ if [ -n "$HOME" ]; then
 
     export PATH=$NIX_LINK/bin:$NIX_LINK/sbin:$PATH
 
-    # Subscribe the root user to the Nixpkgs channel by default.
+    # Subscribe the user to the Nixpkgs channel by default.
     if [ ! -e $HOME/.nix-channels ]; then
-        echo "http://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
+        echo "https://nixos.org/channels/nixpkgs-unstable nixpkgs" > $HOME/.nix-channels
     fi
 
     # Append ~/.nix-defexpr/channels/nixpkgs to $NIX_PATH so that
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 2ff9756108ad..298f6a3a60e3 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -247,7 +247,6 @@ EvalState::EvalState(const Strings & _searchPath)
 EvalState::~EvalState()
 {
     fileEvalCache.clear();
-    printCanaries();
 }
 
 
@@ -1514,26 +1513,6 @@ void EvalState::printStats()
 }
 
 
-void EvalState::printCanaries()
-{
-#if HAVE_BOEHMGC
-    if (!settings.get("debug-gc", false)) return;
-
-    GC_gcollect();
-
-    if (gcCanaries.empty()) {
-        printMsg(lvlError, "all canaries have been garbage-collected");
-        return;
-    }
-
-    printMsg(lvlError, "the following canaries have not been garbage-collected:");
-
-    for (auto i : gcCanaries)
-        printMsg(lvlError, format("  %1%") % i->string.s);
-#endif
-}
-
-
 size_t valueSize(Value & v)
 {
     std::set<const void *> seen;
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 8bf65c2c55de..78942927fd24 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -287,8 +287,6 @@ public:
     /* Print statistics. */
     void printStats();
 
-    void printCanaries();
-
 private:
 
     unsigned long nrEnvs;
@@ -320,12 +318,6 @@ private:
     friend struct ExprOpConcatLists;
     friend struct ExprSelect;
     friend void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v);
-
-#if HAVE_BOEHMGC
-    std::set<Value *> gcCanaries;
-    friend void canaryFinalizer(GC_PTR obj, GC_PTR client_data);
-    friend void prim_gcCanary(EvalState & state, const Pos & pos, Value * * args, Value & v);
-#endif
 };
 
 
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index e7b79604699b..cd7b287e29c3 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -417,32 +417,6 @@ static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value
 }
 
 
-#if HAVE_BOEHMGC
-void canaryFinalizer(GC_PTR obj, GC_PTR client_data)
-{
-    Value * v = (Value *) obj;
-    EvalState & state(* (EvalState *) client_data);
-    printMsg(lvlError, format("canary ‘%1%’ garbage-collected") % v->string.s);
-    auto i = state.gcCanaries.find(v);
-    assert(i != state.gcCanaries.end());
-    state.gcCanaries.erase(i);
-}
-#endif
-
-
-void prim_gcCanary(EvalState & state, const Pos & pos, Value * * args, Value & v)
-{
-    string s = state.forceStringNoCtx(*args[0], pos);
-    state.mkList(v, 1);
-    Value * canary = v.list.elems[0] = state.allocValue();
-#if HAVE_BOEHMGC
-    state.gcCanaries.insert(canary);
-    GC_register_finalizer(canary, canaryFinalizer, &state, 0, 0);
-#endif
-    mkString(*canary, s);
-}
-
-
 void prim_valueSize(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
     /* We're not forcing the argument on purpose. */
@@ -756,8 +730,12 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va
 {
     PathSet context;
     Path path = state.coerceToPath(pos, *args[0], context);
-    if (!context.empty())
-        throw EvalError(format("string ‘%1%’ cannot refer to other paths, at %2%") % path % pos);
+    try {
+        realiseContext(context);
+    } catch (InvalidPathError & e) {
+        throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
+            % path % e.path % pos);
+    }
     mkString(v, readFile(path).c_str());
 }
 
@@ -1556,7 +1534,6 @@ void EvalState::createBaseEnv()
 
     // Debugging
     addPrimOp("__trace", 2, prim_trace);
-    addPrimOp("__gcCanary", 1, prim_gcCanary);
     addPrimOp("__valueSize", 1, prim_valueSize);
 
     // Paths
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index bf5688a1e606..9c74a614e2e4 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -16,7 +16,6 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <signal.h>
-#include <spawn.h>
 
 extern char * * environ;
 
@@ -293,8 +292,9 @@ int handleExceptions(const string & programName, std::function<void()> fun)
 
 RunPager::RunPager()
 {
-    string pager = getEnv("PAGER");
-    if (!isatty(STDOUT_FILENO) || pager.empty()) return;
+    if (!isatty(STDOUT_FILENO)) return;
+    string pager = getEnv("PAGER", "default");
+    if (pager == "" || pager == "cat") return;
 
     /* Ignore SIGINT. The pager will handle it (and we'll get
        SIGPIPE). */
@@ -309,35 +309,18 @@ RunPager::RunPager()
     Pipe toPager;
     toPager.create();
 
-    // FIXME: should do this in the child environment.
-    if (!getenv("LESS"))
-        setenv("LESS", "FRSXMK", 1);
-
-    /* Start the pager using posix_spawn. */
-    pid_t pid_;
-    const char * argv[] = { "sh", "-c", pager.c_str(), 0 };
-
-    posix_spawn_file_actions_t fileActions;
-    int err = posix_spawn_file_actions_init(&fileActions);
-    if (err) throw SysError(err, "creating POSIX file actions");
-    err = posix_spawn_file_actions_adddup2(&fileActions, toPager.readSide, STDIN_FILENO);
-    if (err) throw SysError(err, "adding to POSIX file actions");
-
-    posix_spawnattr_t spawnAttrs;
-    err = posix_spawnattr_init(&spawnAttrs);
-    if (err) throw SysError(err, "creating POSIX spawn attrs");
-#ifdef POSIX_SPAWN_USEVFORK
-    err = posix_spawnattr_setflags(&spawnAttrs, POSIX_SPAWN_USEVFORK);
-    if (err) throw SysError(err, "setting POSIX spawn attr flag");
-#endif
-
-    err = posix_spawn(&pid_, "/bin/sh", &fileActions, &spawnAttrs, (char * const *) argv, environ);
-
-    posix_spawn_file_actions_destroy(&fileActions);
-    posix_spawnattr_destroy(&spawnAttrs);
-
-    if (err) throw SysError(err, format("running ‘%1%’") % pager);
-    pid = pid_;
+    pid = startProcess([&]() {
+        if (dup2(toPager.readSide, STDIN_FILENO) == -1)
+            throw SysError("dupping stdin");
+        if (!getenv("LESS"))
+            setenv("LESS", "FRSXMK", 1);
+        if (pager != "default")
+            execl("/bin/sh", "sh", "-c", pager.c_str(), NULL);
+        execlp("pager", "pager", NULL);
+        execlp("less", "less", NULL);
+        execlp("more", "more", NULL);
+        throw SysError(format("executing ‘%1%’") % pager);
+    });
 
     if (dup2(toPager.writeSide, STDOUT_FILENO) == -1)
         throw SysError("dupping stdout");
@@ -346,10 +329,14 @@ RunPager::RunPager()
 
 RunPager::~RunPager()
 {
-    if (pid != -1) {
-        std::cout.flush();
-        close(STDOUT_FILENO);
-        pid.wait(true);
+    try {
+        if (pid != -1) {
+            std::cout.flush();
+            close(STDOUT_FILENO);
+            pid.wait(true);
+        }
+    } catch (...) {
+        ignoreException();
     }
 }
 
diff --git a/src/libmain/stack.cc b/src/libmain/stack.cc
index b670e695d140..41b617d98be2 100644
--- a/src/libmain/stack.cc
+++ b/src/libmain/stack.cc
@@ -32,7 +32,7 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
         if (diff < 0) diff = -diff;
         if (diff < 4096) {
             char msg[] = "error: stack overflow (possible infinite recursion)\n";
-            write(2, msg, strlen(msg));
+            (void) write(2, msg, strlen(msg));
             _exit(1); // maybe abort instead?
         }
     }
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 539d0b21b278..08f44b392b00 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -415,18 +415,6 @@ static void commonChildInit(Pipe & logPipe)
 }
 
 
-/* Convert a string list to an array of char pointers.  Careful: the
-   string list should outlive the array. */
-const char * * strings2CharPtrs(const Strings & ss)
-{
-    const char * * arr = new const char * [ss.size() + 1];
-    const char * * p = arr;
-    foreach (Strings::const_iterator, i, ss) *p++ = i->c_str();
-    *p = 0;
-    return arr;
-}
-
-
 //////////////////////////////////////////////////////////////////////
 
 
@@ -816,8 +804,8 @@ private:
     /* Start building a derivation. */
     void startBuilder();
 
-    /* Initialise the builder's process. */
-    void initChild();
+    /* Run the builder's process. */
+    void runChild();
 
     friend int childEntry(void *);
 
@@ -1914,9 +1902,11 @@ void DerivationGoal::startBuilder()
     builderOut.create();
 
     /* Fork a child to build the package. */
+    ProcessOptions options;
+    options.allowVfork = !buildUser.enabled();
     pid = startProcess([&]() {
-        initChild();
-    });
+        runChild();
+    }, options);
 
     /* parent */
     pid.setSeparatePG(true);
@@ -1936,7 +1926,7 @@ void DerivationGoal::startBuilder()
 }
 
 
-void DerivationGoal::initChild()
+void DerivationGoal::runChild()
 {
     /* Warning: in the child we should absolutely not make any SQLite
        calls! */
@@ -1986,9 +1976,11 @@ void DerivationGoal::initChild()
 
             /* Set the hostname etc. to fixed values. */
             char hostname[] = "localhost";
-            sethostname(hostname, sizeof(hostname));
+            if (sethostname(hostname, sizeof(hostname)) == -1)
+                throw SysError("cannot set host name");
             char domainname[] = "(none)"; // kernel default
-            setdomainname(domainname, sizeof(domainname));
+            if (setdomainname(domainname, sizeof(domainname)) == -1)
+                throw SysError("cannot set domain name");
 
             /* Make all filesystems private.  This is necessary
                because subtrees may have been mounted as "shared"
@@ -2122,11 +2114,7 @@ void DerivationGoal::initChild()
         Strings envStrs;
         foreach (Environment::const_iterator, i, env)
             envStrs.push_back(rewriteHashes(i->first + "=" + i->second, rewritesToTmp));
-        const char * * envArr = strings2CharPtrs(envStrs);
-
-        Path program = drv.builder.c_str();
-        std::vector<const char *> args; /* careful with c_str()! */
-        string user; /* must be here for its c_str()! */
+        auto envArr = stringsToCharPtrs(envStrs);
 
         /* If we are running in `build-users' mode, then switch to the
            user we allocated above.  Make sure that we drop all root
@@ -2135,8 +2123,6 @@ void DerivationGoal::initChild()
            setuid() when run as root sets the real, effective and
            saved UIDs. */
         if (buildUser.enabled()) {
-            printMsg(lvlChatty, format("switching to user ‘%1%’") % buildUser.getUser());
-
             if (setgroups(0, 0) == -1)
                 throw SysError("cannot clear the set of supplementary groups");
 
@@ -2152,29 +2138,25 @@ void DerivationGoal::initChild()
         }
 
         /* Fill in the arguments. */
+        Strings args;
         string builderBasename = baseNameOf(drv.builder);
-        args.push_back(builderBasename.c_str());
-        foreach (Strings::iterator, i, drv.args) {
-            auto re = rewriteHashes(*i, rewritesToTmp);
-            auto cstr = new char[re.length()+1];
-            std::strcpy(cstr, re.c_str());
-
-            args.push_back(cstr);
-        }
-        args.push_back(0);
+        args.push_back(builderBasename);
+        foreach (Strings::iterator, i, drv.args)
+            args.push_back(rewriteHashes(*i, rewritesToTmp));
+        auto argArr = stringsToCharPtrs(args);
 
         restoreSIGPIPE();
 
         /* Indicate that we managed to set up the build environment. */
-        writeToStderr("\n");
+        writeFull(STDERR_FILENO, "\n");
 
         /* Execute the program.  This should not return. */
-        execve(program.c_str(), (char * *) &args[0], (char * *) envArr);
+        execve(drv.builder.c_str(), (char * *) &argArr[0], (char * *) &envArr[0]);
 
         throw SysError(format("executing ‘%1%’") % drv.builder);
 
     } catch (std::exception & e) {
-        writeToStderr("while setting up the build environment: " + string(e.what()) + "\n");
+        writeFull(STDERR_FILENO, "while setting up the build environment: " + string(e.what()) + "\n");
         _exit(1);
     }
 }
@@ -2487,7 +2469,7 @@ void DerivationGoal::handleChildOutput(int fd, const string & data)
             BZ2_bzWrite(&err, bzLogFile, (unsigned char *) data.data(), data.size());
             if (err != BZ_OK) throw Error(format("cannot write to compressed log file (BZip2 error = %1%)") % err);
         } else if (fdLogFile != -1)
-            writeFull(fdLogFile, (unsigned char *) data.data(), data.size());
+            writeFull(fdLogFile, data);
     }
 
     if (hook && fd == hook->fromHook.readSide)
@@ -2797,7 +2779,7 @@ void SubstitutionGoal::tryToRun()
     args.push_back("--substitute");
     args.push_back(storePath);
     args.push_back(destPath);
-    const char * * argArr = strings2CharPtrs(args);
+    auto argArr = stringsToCharPtrs(args);
 
     /* Fork the substitute program. */
     pid = startProcess([&]() {
@@ -2807,7 +2789,7 @@ void SubstitutionGoal::tryToRun()
         if (dup2(outPipe.writeSide, STDOUT_FILENO) == -1)
             throw SysError("cannot dup output pipe into stdout");
 
-        execv(sub.c_str(), (char * *) argArr);
+        execv(sub.c_str(), (char * *) &argArr[0]);
 
         throw SysError(format("executing ‘%1%’") % sub);
     });
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 49cb11d23290..7959a592d987 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -191,7 +191,7 @@ void LocalStore::addTempRoot(const Path & path)
     lockFile(fdTempRoots, ltWrite, true);
 
     string s = path + '\0';
-    writeFull(fdTempRoots, (const unsigned char *) s.data(), s.size());
+    writeFull(fdTempRoots, s);
 
     /* Downgrade to a read lock. */
     debug(format("downgrading to read lock on ‘%1%’") % fnTempRoots);
@@ -231,7 +231,7 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
         if (lockFile(*fd, ltWrite, false)) {
             printMsg(lvlError, format("removing stale temporary roots file ‘%1%’") % path);
             unlink(path.c_str());
-            writeFull(*fd, (const unsigned char *) "d", 1);
+            writeFull(*fd, "d");
             continue;
         }
 
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index fc48c0405650..3ad80bc4e6f4 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -358,7 +358,8 @@ LocalStore::~LocalStore()
             i->second.to.close();
             i->second.from.close();
             i->second.error.close();
-            i->second.pid.wait(true);
+            if (i->second.pid != -1)
+                i->second.pid.wait(true);
         }
     } catch (...) {
         ignoreException();
@@ -498,7 +499,7 @@ void LocalStore::makeStoreWritable()
         if (unshare(CLONE_NEWNS) == -1)
             throw SysError("setting up a private mount namespace");
 
-        if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1)
+        if (mount(0, settings.nixStore.c_str(), "none", MS_REMOUNT | MS_BIND, 0) == -1)
             throw SysError(format("remounting %1% writable") % settings.nixStore);
     }
 #endif
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index f26684afacb9..9db37e8f9aaa 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -33,7 +33,7 @@ void deleteLockFile(const Path & path, int fd)
        other processes waiting on this lock that the lock is stale
        (deleted). */
     unlink(path.c_str());
-    writeFull(fd, (const unsigned char *) "d", 1);
+    writeFull(fd, "d");
     /* Note that the result of unlink() is ignored; removing the lock
        file is an optimisation, not a necessity. */
 }
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index cabde051bd02..d08913246321 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -110,7 +110,7 @@ void RemoteStore::connectToDaemon()
        applications... */
     AutoCloseFD fdPrevDir = open(".", O_RDONLY);
     if (fdPrevDir == -1) throw SysError("couldn't open current directory");
-    chdir(dirOf(socketPath).c_str());
+    if (chdir(dirOf(socketPath).c_str()) == -1) throw SysError(format("couldn't change to directory of ‘%1%’") % socketPath);
     Path socketPathRel = "./" + baseNameOf(socketPath);
 
     struct sockaddr_un addr;
diff --git a/src/libutil/types.hh b/src/libutil/types.hh
index 030996a060e2..160884ee1ad7 100644
--- a/src/libutil/types.hh
+++ b/src/libutil/types.hh
@@ -73,7 +73,6 @@ class SysError : public Error
 public:
     int errNo;
     SysError(const FormatOrString & fs);
-    SysError(int errNo, const FormatOrString & fs);
 };
 
 
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 60be02cd4647..dcdb438e03b2 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -45,14 +45,8 @@ BaseError & BaseError::addPrefix(const FormatOrString & fs)
 
 
 SysError::SysError(const FormatOrString & fs)
-    : SysError(errno, fs)
-{
-}
-
-
-SysError::SysError(int errNo, const FormatOrString & fs)
-    : Error(format("%1%: %2%") % fs.s % strerror(errNo))
-    , errNo(errNo)
+    : Error(format("%1%: %2%") % fs.s % strerror(errno))
+    , errNo(errno)
 {
 }
 
@@ -271,7 +265,7 @@ void writeFile(const Path & path, const string & s)
     AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
     if (fd == -1)
         throw SysError(format("opening file ‘%1%’") % path);
-    writeFull(fd, (unsigned char *) s.data(), s.size());
+    writeFull(fd, s);
 }
 
 
@@ -298,7 +292,7 @@ string readLine(int fd)
 void writeLine(int fd, string s)
 {
     s += '\n';
-    writeFull(fd, (const unsigned char *) s.data(), s.size());
+    writeFull(fd, s);
 }
 
 
@@ -489,18 +483,13 @@ void warnOnce(bool & haveWarned, const FormatOrString & fs)
 }
 
 
-static void defaultWriteToStderr(const unsigned char * buf, size_t count)
-{
-    writeFull(STDERR_FILENO, buf, count);
-}
-
-
 void writeToStderr(const string & s)
 {
     try {
-        auto p = _writeToStderr;
-        if (!p) p = defaultWriteToStderr;
-        p((const unsigned char *) s.data(), s.size());
+        if (_writeToStderr)
+            _writeToStderr((const unsigned char *) s.data(), s.size());
+        else
+            writeFull(STDERR_FILENO, s);
     } catch (SysError & e) {
         /* Ignore failing writes to stderr if we're in an exception
            handler, otherwise throw an exception.  We need to ignore
@@ -512,7 +501,7 @@ void writeToStderr(const string & s)
 }
 
 
-void (*_writeToStderr) (const unsigned char * buf, size_t count) = defaultWriteToStderr;
+void (*_writeToStderr) (const unsigned char * buf, size_t count) = 0;
 
 
 void readFull(int fd, unsigned char * buf, size_t count)
@@ -546,6 +535,12 @@ void writeFull(int fd, const unsigned char * buf, size_t count)
 }
 
 
+void writeFull(int fd, const string & s)
+{
+    writeFull(fd, (const unsigned char *) s.data(), s.size());
+}
+
+
 string drainFD(int fd)
 {
     string result;
@@ -831,6 +826,9 @@ void killUser(uid_t uid)
        users to which the current process can send signals.  So we
        fork a process, switch to uid, and send a mass kill. */
 
+    ProcessOptions options;
+    options.allowVfork = false;
+
     Pid pid = startProcess([&]() {
 
         if (setuid(uid) == -1)
@@ -853,7 +851,7 @@ void killUser(uid_t uid)
         }
 
         _exit(0);
-    });
+    }, options);
 
     int status = pid.wait(true);
     if (status != 0)
@@ -869,46 +867,64 @@ void killUser(uid_t uid)
 //////////////////////////////////////////////////////////////////////
 
 
-pid_t startProcess(std::function<void()> fun,
-    bool dieWithParent, const string & errorPrefix, bool runExitHandlers)
+/* Wrapper around vfork to prevent the child process from clobbering
+   the caller's stack frame in the parent. */
+static pid_t doFork(bool allowVfork, std::function<void()> fun) __attribute__((noinline));
+static pid_t doFork(bool allowVfork, std::function<void()> fun)
 {
+#ifdef __linux__
+    pid_t pid = allowVfork ? vfork() : fork();
+#else
     pid_t pid = fork();
-    if (pid == -1) throw SysError("unable to fork");
+#endif
+    if (pid != 0) return pid;
+    fun();
+    abort();
+}
 
-    if (pid == 0) {
-        _writeToStderr = 0;
+
+pid_t startProcess(std::function<void()> fun, const ProcessOptions & options)
+{
+    auto wrapper = [&]() {
+        if (!options.allowVfork) _writeToStderr = 0;
         try {
 #if __linux__
-            if (dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
+            if (options.dieWithParent && prctl(PR_SET_PDEATHSIG, SIGKILL) == -1)
                 throw SysError("setting death signal");
 #endif
             restoreAffinity();
             fun();
         } catch (std::exception & e) {
             try {
-                std::cerr << errorPrefix << e.what() << "\n";
+                std::cerr << options.errorPrefix << e.what() << "\n";
             } catch (...) { }
         } catch (...) { }
-        if (runExitHandlers)
+        if (options.runExitHandlers)
             exit(1);
         else
             _exit(1);
-    }
+    };
+
+    pid_t pid = doFork(options.allowVfork, wrapper);
+    if (pid == -1) throw SysError("unable to fork");
 
     return pid;
 }
 
 
+std::vector<const char *> stringsToCharPtrs(const Strings & ss)
+{
+    std::vector<const char *> res;
+    for (auto & s : ss) res.push_back(s.c_str());
+    res.push_back(0);
+    return res;
+}
+
+
 string runProgram(Path program, bool searchPath, const Strings & args)
 {
     checkInterrupt();
 
-    std::vector<const char *> cargs; /* careful with c_str()! */
-    cargs.push_back(program.c_str());
-    for (Strings::const_iterator i = args.begin(); i != args.end(); ++i)
-        cargs.push_back(i->c_str());
-    cargs.push_back(0);
-
     /* Create a pipe. */
     Pipe pipe;
     pipe.create();
@@ -918,6 +934,10 @@ string runProgram(Path program, bool searchPath, const Strings & args)
         if (dup2(pipe.writeSide, STDOUT_FILENO) == -1)
             throw SysError("dupping stdout");
 
+        Strings args_(args);
+        args_.push_front(program);
+        auto cargs = stringsToCharPtrs(args_);
+
         if (searchPath)
             execvp(program.c_str(), (char * *) &cargs[0]);
         else
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 628b8a0e1f09..186ee71f45d0 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -171,6 +171,7 @@ extern void (*_writeToStderr) (const unsigned char * buf, size_t count);
    requested number of bytes. */
 void readFull(int fd, unsigned char * buf, size_t count);
 void writeFull(int fd, const unsigned char * buf, size_t count);
+void writeFull(int fd, const string & s);
 
 MakeError(EndOfFile, Error)
 
@@ -269,8 +270,16 @@ void killUser(uid_t uid);
 
 /* Fork a process that runs the given function, and return the child
    pid to the caller. */
-pid_t startProcess(std::function<void()> fun, bool dieWithParent = true,
-    const string & errorPrefix = "error: ", bool runExitHandlers = false);
+struct ProcessOptions
+{
+    string errorPrefix;
+    bool dieWithParent;
+    bool runExitHandlers;
+    bool allowVfork;
+    ProcessOptions() : errorPrefix("error: "), dieWithParent(true), runExitHandlers(false), allowVfork(true) { };
+};
+
+pid_t startProcess(std::function<void()> fun, const ProcessOptions & options = ProcessOptions());
 
 
 /* Run a program and return its stdout in a string (i.e., like the
@@ -280,6 +289,11 @@ string runProgram(Path program, bool searchPath = false,
 
 MakeError(ExecError, Error)
 
+/* Convert a list of strings to a null-terminated vector of char
+   *'s. The result must not be accessed beyond the lifetime of the
+   list of strings. */
+std::vector<const char *> stringsToCharPtrs(const Strings & ss);
+
 /* Close all file descriptors except stdin, stdout, stderr, and those
    listed in the given set.  Good practice in child processes. */
 void closeMostFDs(const set<int> & exceptions);
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 3864ab935de0..bed7de0859a3 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -513,11 +513,11 @@ static void performOp(bool trusted, unsigned int clientVersion,
     }
 
     case wopOptimiseStore:
-	startWork();
-	store->optimiseStore();
-	stopWork();
-	writeInt(1, to);
-	break;
+        startWork();
+        store->optimiseStore();
+        stopWork();
+        writeInt(1, to);
+        break;
 
     default:
         throw Error(format("invalid operation %1%") % op);
@@ -610,6 +610,8 @@ static void processConnection(bool trusted)
         assert(!canSendStderr);
     };
 
+    canSendStderr = false;
+    _isInterrupted = false;
     printMsg(lvlDebug, format("%1% operations") % opCount);
 }
 
@@ -696,7 +698,8 @@ static PeerInfo getPeerInfo(int remote)
 
 static void daemonLoop(char * * argv)
 {
-    chdir("/");
+    if (chdir("/") == -1)
+        throw SysError("cannot change current directory");
 
     /* Get rid of children automatically; don't let them become
        zombies. */
@@ -726,7 +729,8 @@ static void daemonLoop(char * * argv)
         /* Urgh, sockaddr_un allows path names of only 108 characters.
            So chdir to the socket directory so that we can pass a
            relative path name. */
-        chdir(dirOf(socketPath).c_str());
+        if (chdir(dirOf(socketPath).c_str()) == -1)
+            throw SysError("cannot change current directory");
         Path socketPathRel = "./" + baseNameOf(socketPath);
 
         struct sockaddr_un addr;
@@ -746,7 +750,8 @@ static void daemonLoop(char * * argv)
         if (res == -1)
             throw SysError(format("cannot bind to socket ‘%1%’") % socketPath);
 
-        chdir("/"); /* back to the root */
+        if (chdir("/") == -1) /* back to the root */
+            throw SysError("cannot change current directory");
 
         if (listen(fdSocket, 5) == -1)
             throw SysError(format("cannot listen on socket ‘%1%’") % socketPath);
@@ -799,6 +804,11 @@ static void daemonLoop(char * * argv)
                 % (peer.uidKnown ? user : "<unknown>"));
 
             /* Fork a child to handle the connection. */
+            ProcessOptions options;
+            options.errorPrefix = "unexpected Nix daemon error: ";
+            options.dieWithParent = false;
+            options.runExitHandlers = true;
+            options.allowVfork = false;
             startProcess([&]() {
                 fdSocket.close();
 
@@ -821,7 +831,7 @@ static void daemonLoop(char * * argv)
                 processConnection(trusted);
 
                 exit(0);
-            }, false, "unexpected Nix daemon error: ", true);
+            }, options);
 
         } catch (Interrupted & e) {
             throw;
@@ -832,15 +842,6 @@ static void daemonLoop(char * * argv)
 }
 
 
-void run(Strings args)
-{
-    for (Strings::iterator i = args.begin(); i != args.end(); ) {
-        string arg = *i++;
-    }
-
-}
-
-
 int main(int argc, char * * argv)
 {
     return handleExceptions(argv[0], [&]() {
diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc
index 9a6e178f514e..e7214e657bd5 100644
--- a/src/nix-instantiate/nix-instantiate.cc
+++ b/src/nix-instantiate/nix-instantiate.cc
@@ -86,8 +86,6 @@ void processExpr(EvalState & state, const Strings & attrPaths,
             }
         }
     }
-
-    state.printCanaries();
 }
 
 
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index c91bca97d534..87bc8c379de5 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -488,7 +488,7 @@ static void opReadLog(Strings opFlags, Strings opArgs)
             if (pathExists(logPath)) {
                 /* !!! Make this run in O(1) memory. */
                 string log = readFile(logPath);
-                writeFull(STDOUT_FILENO, (const unsigned char *) log.data(), log.size());
+                writeFull(STDOUT_FILENO, log);
                 found = true;
                 break;
             }
diff --git a/tests/remote-builds.nix b/tests/remote-builds.nix
index 2cd5ccfc6d45..0f16026a428a 100644
--- a/tests/remote-builds.nix
+++ b/tests/remote-builds.nix
@@ -25,7 +25,7 @@ let
         system = "i686-linux";
         PATH = "''${utils}/bin";
         builder = "''${utils}/bin/sh";
-        args = [ "-c" "if [ ${toString nr} = 5 ]; then echo FAIL; exit 1; fi; echo Hello; mkdir $out $foo; cat /proc/sys/kernel/hostname > $out/host; ln -s $out $foo/bar; sleep 5" ];
+        args = [ "-c" "if [ ${toString nr} = 5 ]; then echo FAIL; exit 1; fi; echo Hello; mkdir $out $foo; cat /proc/sys/kernel/hostname > $out/host; ln -s $out $foo/bar; sleep 10" ];
         outputs = [ "out" "foo" ];
       }
     '';