about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--doc/manual/advanced-topics/distributed-builds.xml8
-rw-r--r--doc/manual/command-ref/conf-file.xml6
-rw-r--r--doc/manual/command-ref/env-common.xml9
-rw-r--r--doc/manual/command-ref/nix-channel.xml4
-rw-r--r--doc/manual/command-ref/nix-install-package.xml208
-rw-r--r--doc/manual/command-ref/nix-push.xml449
-rw-r--r--doc/manual/command-ref/nix-store.xml3
-rw-r--r--doc/manual/command-ref/utilities.xml2
-rw-r--r--doc/manual/expressions/builtins.xml11
-rw-r--r--doc/manual/expressions/derivations.xml2
-rw-r--r--doc/manual/introduction/quick-start.xml12
-rw-r--r--doc/manual/local.mk4
-rw-r--r--doc/manual/packages/one-click.xml37
-rw-r--r--doc/manual/packages/package-management.xml1
-rw-r--r--misc/docker/Dockerfile4
-rw-r--r--release.nix1
-rw-r--r--scripts/download-from-binary-cache.pl.in632
-rw-r--r--scripts/local.mk2
-rwxr-xr-xscripts/nix-install-package.in127
-rwxr-xr-xscripts/nix-push.in296
-rwxr-xr-xscripts/show-duplication.pl73
-rw-r--r--src/libmain/shared.cc1
-rw-r--r--src/libstore/binary-cache-store.cc2
-rw-r--r--src/libstore/build.cc4
-rw-r--r--src/libstore/download.cc43
-rw-r--r--src/libstore/download.hh11
-rw-r--r--src/libstore/globals.cc1
-rw-r--r--src/libstore/globals.hh3
-rw-r--r--src/libstore/http-binary-cache-store.cc2
-rw-r--r--src/libstore/local-fs-store.cc8
-rw-r--r--src/libstore/local-store.cc54
-rw-r--r--src/libstore/local-store.hh4
-rw-r--r--src/libstore/nar-accessor.cc2
-rw-r--r--src/libstore/nar-info-disk-cache.cc13
-rw-r--r--src/libstore/nar-info.cc7
-rw-r--r--src/libstore/remote-store.cc35
-rw-r--r--src/libstore/schema.sql3
-rw-r--r--src/libstore/sqlite.cc13
-rw-r--r--src/libstore/sqlite.hh10
-rw-r--r--src/libstore/store-api.cc60
-rw-r--r--src/libstore/store-api.hh75
-rw-r--r--src/nix-daemon/nix-daemon.cc46
-rw-r--r--src/nix-store/nix-store.cc8
-rw-r--r--src/nix/path-info.cc1
-rw-r--r--src/nix/verify.cc6
-rw-r--r--tests/binary-cache.sh6
-rw-r--r--tests/common.sh.in7
-rw-r--r--tests/dump-db.sh3
-rw-r--r--tests/init.sh5
-rw-r--r--tests/install-package.sh20
-rw-r--r--tests/local.mk4
-rw-r--r--tests/nix-channel.sh2
-rw-r--r--tests/nix-push.sh12
-rw-r--r--tests/referrers.sh2
-rw-r--r--tests/remote-store.sh2
-rw-r--r--tests/repair.sh2
-rw-r--r--tests/user-envs.sh5
58 files changed, 309 insertions, 2066 deletions
diff --git a/.gitignore b/.gitignore
index 2b90b549ba8a..69152741e001 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,11 +34,9 @@ Makefile.config
 
 # /scripts/
 /scripts/nix-profile.sh
-/scripts/nix-push
 /scripts/nix-switch
 /scripts/nix-collect-garbage
 /scripts/nix-prefetch-url
-/scripts/nix-install-package
 /scripts/nix-channel
 /scripts/nix-build
 /scripts/nix-copy-closure
diff --git a/doc/manual/advanced-topics/distributed-builds.xml b/doc/manual/advanced-topics/distributed-builds.xml
index 1f8d98f5d8fe..f8583700393c 100644
--- a/doc/manual/advanced-topics/distributed-builds.xml
+++ b/doc/manual/advanced-topics/distributed-builds.xml
@@ -11,9 +11,9 @@ 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>
+<literal>x86_64-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>
+<literal>x86_64-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
@@ -30,7 +30,7 @@ variable</link>.</para>
 <example xml:id='ex-remote-systems'><title>Remote machine configuration:
 <filename>remote-systems.conf</filename></title>
 <programlisting>
-nix@mcflurry.labs.cs.uu.nl  powerpc-darwin  /home/nix/.ssh/id_quarterpounder_auto  2
+nix@mcflurry.labs.cs.uu.nl  x86_64-darwin   /home/nix/.ssh/id_quarterpounder_auto  2
 nix@scratchy.labs.cs.uu.nl  i686-linux      /home/nix/.ssh/id_scratchy_auto        8 1 kvm
 nix@itchy.labs.cs.uu.nl     i686-linux      /home/nix/.ssh/id_scratchy_auto        8 2
 nix@poochie.labs.cs.uu.nl   i686-linux      /home/nix/.ssh/id_scratchy_auto        8 2 kvm perf
@@ -59,7 +59,7 @@ bits of information:
   <filename>~/.ssh/config</filename>.</para></listitem>
 
   <listitem><para>A comma-separated list of Nix platform type
-  identifiers, such as <literal>powerpc-darwin</literal>.  It is
+  identifiers, such as <literal>x86_64-darwin</literal>.  It is
   possible for a machine to support multiple platform types, e.g.,
   <literal>i686-linux,x86_64-linux</literal>.</para></listitem>
 
diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index 4c8f3d9d3809..fb7bdf573397 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -430,15 +430,15 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
     <listitem><para>This option specifies the canonical Nix system
     name of the current installation, such as
     <literal>i686-linux</literal> or
-    <literal>powerpc-darwin</literal>.  Nix can only build derivations
+    <literal>x86_64-darwin</literal>.  Nix can only build derivations
     whose <literal>system</literal> attribute equals the value
     specified here.  In general, it never makes sense to modify this
     value from its default, since you can use it to ‘lie’ about the
     platform you are building on (e.g., perform a Mac OS build on a
     Linux machine; the result would obviously be wrong).  It only
     makes sense if the Nix binaries can run on multiple platforms,
-    e.g., ‘universal binaries’ that run on <literal>powerpc-darwin</literal> and
-    <literal>i686-darwin</literal>.</para>
+    e.g., ‘universal binaries’ that run on <literal>x86_64-linux</literal> and
+    <literal>i686-linux</literal>.</para>
 
     <para>It defaults to the canonical Nix system name detected by
     <filename>configure</filename> at build time.</para></listitem>
diff --git a/doc/manual/command-ref/env-common.xml b/doc/manual/command-ref/env-common.xml
index 27efef945f15..c757cb17bd10 100644
--- a/doc/manual/command-ref/env-common.xml
+++ b/doc/manual/command-ref/env-common.xml
@@ -129,15 +129,6 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
 </varlistentry>
 
 
-<varlistentry><term><envar>NIX_DB_DIR</envar></term>
-
-  <listitem><para>Overrides the location of the Nix database (default
-  <filename><replaceable>$NIX_STATE_DIR</replaceable>/db</filename>, i.e.,
-  <filename><replaceable>prefix</replaceable>/var/nix/db</filename>).</para></listitem>
-
-</varlistentry>
-
-
 <varlistentry><term><envar>NIX_CONF_DIR</envar></term>
 
   <listitem><para>Overrides the location of the Nix configuration
diff --git a/doc/manual/command-ref/nix-channel.xml b/doc/manual/command-ref/nix-channel.xml
index 0a1f2a8b722d..9acf44e52984 100644
--- a/doc/manual/command-ref/nix-channel.xml
+++ b/doc/manual/command-ref/nix-channel.xml
@@ -180,9 +180,7 @@ following files:</para>
     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>
+    to the channels of non-root users are ignored.</para></listitem>
 
   </varlistentry>
 
diff --git a/doc/manual/command-ref/nix-install-package.xml b/doc/manual/command-ref/nix-install-package.xml
deleted file mode 100644
index e17166caaaf3..000000000000
--- a/doc/manual/command-ref/nix-install-package.xml
+++ /dev/null
@@ -1,208 +0,0 @@
-<refentry 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-nix-install-package">
-
-<refmeta>
-  <refentrytitle>nix-install-package</refentrytitle>
-  <manvolnum>1</manvolnum>
-  <refmiscinfo class="source">Nix</refmiscinfo>
-  <refmiscinfo class="version"><xi:include href="../version.txt" parse="text"/></refmiscinfo>
-</refmeta>
-
-<refnamediv>
-  <refname>nix-install-package</refname>
-  <refpurpose>install a Nix Package file</refpurpose>
-</refnamediv>
-
-<refsynopsisdiv>
-  <cmdsynopsis>
-    <command>nix-install-package</command>
-    <arg><option>--non-interactive</option></arg>
-    <arg>
-      <group choice='req'>
-        <arg choice='plain'><option>--profile</option></arg>
-        <arg choice='plain'><option>-p</option></arg>
-      </group>
-      <replaceable>path</replaceable>
-    </arg>
-    <arg><option>--set</option></arg>
-    <sbr />
-    <group choice='req'>
-      <arg choice='req'>
-        <option>--url</option>
-        <arg choice='plain'><replaceable>url</replaceable></arg>
-      </arg>
-      <arg choice='req'>
-        <arg choice='plain'><replaceable>file</replaceable></arg>
-      </arg>
-    </group>
-  </cmdsynopsis>
-</refsynopsisdiv>
-
-
-<refsection><title>Description</title>
-
-<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 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>
-
-<para><command>nix-install-package</command> is used in <link
-linkend="sec-one-click">one-click installs</link> to download and
-install pre-built binary packages with all necessary dependencies.
-<command>nix-install-package</command> is intended to be associated
-with the MIME type <literal>application/nix-package</literal> in a web
-browser so that it is invoked automatically when you click on
-<filename>*.nixpkg</filename> files.  When invoked, it restarts itself
-in a terminal window (since otherwise it would be invisible when run
-from a browser), asks the user to confirm whether to install the
-package, and if so downloads and installs the package into the user’s
-current profile.</para>
-
-<para>To obtain a window, <command>nix-install-package</command> tries
-to restart itself with <command>xterm</command>,
-<command>konsole</command> and
-<command>gnome-terminal</command>.</para>
-
-</refsection>
-
-
-<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
-    for confirmation.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--profile</option></term>
-    <term><option>-p</option></term>
-
-    <listitem><para>Install the package into the specified profile
-    rather than the user’s current profile.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--set</option></term>
-
-    <listitem><para>Install the package as the profile so that the
-    profile contains exactly the contents of the package.</para></listitem>
-
-  </varlistentry>
-
-</variablelist>
-
-</refsection>
-
-
-<refsection><title>Examples</title>
-
-<para>To install <filename>subversion-1.4.0.nixpkg</filename> into the
-user’s current profile, without any prompting:
-
-<screen>
-$ nix-install-package --non-interactive subversion-1.4.0.nixpkg</screen>
-
-</para>
-
-<para>To install the same package from some URL into a different
-profile:
-
-<screen>
-$ nix-install-package --non-interactive -p /nix/var/nix/profiles/eelco \
-    --url http://nix.cs.uu.nl/dist/nix/nixpkgs-0.10pre6622/pkgs/subversion-1.4.0-i686-linux.nixpkg</screen>
-
-</para>
-
-</refsection>
-
-
-<refsection><title>Format of <literal>nixpkg</literal> files</title>
-
-<para>A Nix Package file consists of a single line with the following
-format:
-
-<screen>
-NIXPKG1 <replaceable>manifestURL</replaceable> <replaceable>name</replaceable> <replaceable>system</replaceable> <replaceable>drvPath</replaceable> <replaceable>outPath</replaceable></screen>
-
-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>Obsolete.</para></listitem>
-
-  </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>
-
-  </varlistentry>
-
-  <varlistentry><term><replaceable>outPath</replaceable></term>
-
-    <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:
-
-<screen>
-NIXPKG1 http://.../nixpkgs-0.10pre6622/MANIFEST subversion-1.4.0 i686-darwin \
-  /nix/store/4kh60jkp...-subversion-1.4.0.drv \
-  /nix/store/nkw7wpgb...-subversion-1.4.0</screen>
-
-(The line breaks (<literal>\</literal>) are for presentation purposes
-and not part of the actual file.)
-
-</para>
-
-</refsection>
-
-
-</refentry>
diff --git a/doc/manual/command-ref/nix-push.xml b/doc/manual/command-ref/nix-push.xml
deleted file mode 100644
index 0749824a0ad4..000000000000
--- a/doc/manual/command-ref/nix-push.xml
+++ /dev/null
@@ -1,449 +0,0 @@
-<refentry 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-nix-push">
-
-<refmeta>
-  <refentrytitle>nix-push</refentrytitle>
-  <manvolnum>1</manvolnum>
-  <refmiscinfo class="source">Nix</refmiscinfo>
-  <refmiscinfo class="version"><xi:include href="../version.txt" parse="text"/></refmiscinfo>
-</refmeta>
-
-<refnamediv>
-  <refname>nix-push</refname>
-  <refpurpose>generate a binary cache</refpurpose>
-</refnamediv>
-
-<refsynopsisdiv>
-  <cmdsynopsis>
-    <command>nix-push</command>
-    <arg choice='plain'><option>--dest</option> <replaceable>dest-dir</replaceable></arg>
-    <arg><option>--bzip2</option></arg>
-    <arg><option>--none</option></arg>
-    <arg><option>--force</option></arg>
-    <arg><option>--link</option></arg>
-    <arg><option>--manifest</option></arg>
-    <arg><option>--manifest-path</option> <replaceable>filename</replaceable></arg>
-    <arg><option>--url-prefix</option> <replaceable>url</replaceable></arg>
-    <arg><option>--key-file</option> <replaceable>path</replaceable></arg>
-    <arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
-  </cmdsynopsis>
-</refsynopsisdiv>
-
-
-<refsection><title>Description</title>
-
-<para>The command <command>nix-push</command> produces a
-<emphasis>binary cache</emphasis>, a directory containing compressed
-Nix archives (NARs) plus some metadata of the closure of the specified
-store paths.  This directory can then be made available through a web
-server to other Nix installations, allowing them to skip building from
-source and instead download binaries from the cache
-automatically.</para>
-
-<para><command>nix-push</command> performs the following actions.
-
-<orderedlist>
-
-  <listitem><para>Each path in <replaceable>paths</replaceable> is
-  built (using <link
-  linkend='rsec-nix-store-realise'><command>nix-store
-  --realise</command></link>).</para></listitem>
-
-  <listitem><para>All paths in the closure of
-  <replaceable>paths</replaceable> are determined (using
-  <command>nix-store --query --requisites
-  --include-outputs</command>).  Note that since the
-  <option>--include-outputs</option> flag is used, if
-  <replaceable>paths</replaceable> includes a store derivation, you
-  get a combined source/binary distribution (e.g., source tarballs
-  will be included).</para></listitem>
-
-  <listitem><para>All store paths determined in the previous step are
-  packaged into a NAR (using <command>nix-store --dump</command>) and
-  compressed using <command>xz</command> or <command>bzip2</command>.
-  The resulting files have the extension <filename>.nar.xz</filename>
-  or <filename>.nar.bz2</filename>.  Also for each store path, Nix
-  generates a file with extension <filename>.narinfo</filename>
-  containing metadata such as the references, cryptographic hash and
-  size of each path.</para></listitem>
-
-  <listitem><para>Optionally, a single <emphasis>manifest</emphasis>
-  file is created that contains the same metadata as the
-  <filename>.narinfo</filename> files.  This is for compatibility with
-  Nix versions prior to 1.2.</para></listitem>
-
-  <listitem><para>A file named <option>nix-cache-info</option> is
-  placed in the destination directory.  The existence of this file
-  marks the directory as a binary cache.</para></listitem>
-
-</orderedlist>
-
-</para>
-
-</refsection>
-
-
-<refsection><title>Options</title>
-
-<variablelist>
-
-  <varlistentry><term><option>--dest</option> <replaceable>dest-dir</replaceable></term>
-
-    <listitem><para>Set the destination directory to
-    <replaceable>dir</replaceable>, which is created if it does not
-    exist.  This flag is required.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--bzip2</option></term>
-
-    <listitem><para>Compress NARs using <command>bzip2</command>
-    instead of <command>xz</command>.  The latter compresses about 30%
-    better on typical archives, decompresses about twice as fast, but
-    compresses a lot slower and is not supported by Nix prior to
-    version 1.2.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--none</option></term>
-
-    <listitem><para>Do not compress NARs.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--force</option></term>
-
-    <listitem><para>Overwrite <filename>.narinfo</filename> files if
-    they already exist.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--link</option></term>
-
-    <listitem><para>By default, NARs are generated in the Nix store
-    and then copied to <replaceable>dest-dir</replaceable>.  If this
-    option is given, hard links are used instead.  This only works if
-    <replaceable>dest-dir</replaceable> is on the same filesystem as
-    the Nix store.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--manifest</option></term>
-
-    <listitem><para>Force the generation of a manifest suitable for
-    use by old versions of Nix.  The manifest is stored as
-    <filename><replaceable>dest-dir</replaceable>/MANIFEST</filename>.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--manifest-path</option> <replaceable>filename</replaceable></term>
-
-    <listitem><para>Like <option>--manifest</option>, but store the
-    manifest in <replaceable>filename</replaceable>.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--url-prefix</option> <replaceable>url</replaceable></term>
-
-    <listitem><para>Manifests are expected to contain the absolute
-    URLs of NARs.  For generating these URLs, the prefix
-    <replaceable>url</replaceable> is used.  It defaults to
-    <uri>file://<replaceable>dest-dir</replaceable></uri>.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><option>--key-file</option> <replaceable>path</replaceable></term>
-
-    <listitem><para>Sign the binary cache using the secret key stored
-    in <replaceable>path</replaceable>. This secret key must have been
-    created using <command
-    linkend="rsec-nix-store-generate-binary-cache-key">nix-store
-    --generate-binary-cache-key</command>. Users of this binary cache
-    should add the corresponding public key to the option
-    <option>binary-cache-public-keys</option> in
-    <filename>nix.conf</filename>.</para></listitem>
-
-  </varlistentry>
-
-</variablelist>
-
-</refsection>
-
-
-<refsection><title>Examples</title>
-
-<para>To add the closure of Thunderbird to a binary cache:
-
-<screen>
-$ nix-push --dest /tmp/cache $(nix-build -A thunderbird)
-</screen>
-
-Assuming that <filename>/tmp/cache</filename> is exported by a web
-server as <uri>http://example.org/cache</uri>, you can then use this
-cache on another machine to speed up the installation of Thunderbird:
-
-<screen>
-$ nix-build -A thunderbird --option binary-caches http://example.org/cache
-</screen>
-
-Alternatively, you could add <literal>binary-caches =
-http://example.org/cache</literal> to
-<filename>nix.conf</filename>.</para>
-
-<para>To also include build-time dependencies (such as source
-tarballs):
-
-<screen>
-$ nix-push --dest /tmp/cache $(nix-instantiate -A thunderbird)
-</screen>
-
-</para>
-
-<para>To generate a signed binary cache, you must first generate a key
-pair, in this example called <literal>cache.example.org-1</literal>,
-storing the secret key in <filename>./sk</filename> and the public key
-in <filename>./pk</filename>:
-
-<screen>
-$ nix-store --generate-binary-cache-key cache.example.org-1 sk pk
-
-$ cat sk
-cache.example.org-1:jcMRQYFo8pQKzTtimpQLIPeHkMYZjfhB24hGfwF+u9PuX8H8FO7q564+X3G/JDlqqIqGar3OXRRwS9N3Wh3vbw==
-
-$ cat pk
-cache.example.org-1:7l/B/BTu6ueuPl9xvyQ5aqiKhmq9zl0UcEvTd1od728=
-</screen>
-
-You can then generate a binary cache signed with the secret key:
-
-<screen>
-$ nix-push --dest /tmp/cache --key-file ./sk $(type -p firefox)
-</screen>
-
-Users who wish to verify the integrity of binaries downloaded from
-your cache would add the following to their
-<filename>nix.conf</filename>:
-
-<programlisting>
-binary-caches = http://cache.example.org
-signed-binary-caches = *
-binary-cache-public-keys = cache.example.org-1:7l/B/BTu6ueuPl9xvyQ5aqiKhmq9zl0UcEvTd1od728=
-</programlisting>
-
-Nix will then ignore any binary that has a missing, incorrect or
-unrecognised signature.</para>
-
-</refsection>
-
-
-<refsection><title>Binary cache format and operation</title>
-
-<para>A binary cache with URL <replaceable>url</replaceable> only
-denotes a valid binary cache if the file
-<uri><replaceable>url</replaceable>/nix-cache-info</uri> exists.  If
-this file does not exist (or cannot be downloaded), the cache is
-ignored.  If it does exist, it must be a text file containing cache
-properties.  Here’s an example:
-
-<screen>
-StoreDir: /nix/store
-WantMassQuery: 1
-Priority: 10
-</screen>
-
-The properties that are currently supported are:
-
-<variablelist>
-
-  <varlistentry><term><literal>StoreDir</literal></term>
-
-    <listitem><para>The path of the Nix store to which this binary
-    cache applies.  Binaries are not relocatable — a binary built for
-    <filename>/nix/store</filename> won’t generally work in
-    <filename>/home/alice/store</filename> — so to prevent binaries
-    from being used in a wrong store, a binary cache is only used if
-    its <literal>StoreDir</literal> matches the local Nix
-    configuration.  The default is
-    <filename>/nix/store</filename>.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>WantMassQuery</literal></term>
-
-    <listitem><para>Query operations such as <command>nix-env
-    -qas</command> can cause thousands of cache queries, and thus
-    thousands of HTTP requests, to determine which packages are
-    available in binary form.  While these requests are small, not
-    every server may appreciate a potential onslaught of queries.  If
-    <literal>WantMassQuery</literal> is set to <literal>0</literal>
-    (default), “mass queries” such as <command>nix-env -qas</command>
-    will skip this cache.  Thus a package may appear not to have a
-    binary substitute.  However, the binary will still be used when
-    you actually install the package.  If
-    <literal>WantMassQuery</literal> is set to <literal>1</literal>,
-    mass queries will use this cache.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>Priority</literal></term>
-
-    <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>https://cache.nixos.org</uri> has priority
-    40.</para></listitem>
-
-  </varlistentry>
-
-</variablelist>
-
-</para>
-
-<para>Every time Nix needs to build some store path
-<replaceable>p</replaceable>, it will check each configured binary
-cache to see if it has a NAR file for <replaceable>p</replaceable>,
-until it finds one.  If no cache has a NAR, Nix will fall back to
-building the path from source (if applicable).  To see if a cache with
-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>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>
-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
-<filename>.narinfo</filename> file exists.)  The
-<filename>.narinfo</filename> file is a simple text file that looks
-like this:
-
-<screen>
-StorePath: /nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7
-URL: nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
-Compression: bzip2
-FileHash: sha256:0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70
-FileSize: 24473768
-NarHash: sha256:0s491y1h9hxj5ghiizlxk7ax6jwbha00zwn7lpyd5xg5bhf60vzg
-NarSize: 109521136
-References: 2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16 ...
-Deriver: 7akyyc87ka32xwmqza9dvyg5pwx3j212-glibc-2.7.drv
-Sig: cache.example.org-1:WepnSp2UT0odDpR3NRjPVhJBHmdBgSBSTbHpdh4SCz92nGXwFY82bkPEmISoC0hGqBXDXEmB6y3Ohgna3mMgDg==
-</screen>
-
-The fields are as follows:
-
-<variablelist>
-
-  <varlistentry><term><literal>StorePath</literal></term>
-
-    <listitem><para>The full store path, including the name part
-    (e.g., <literal>glibc-2.7</literal>).  It must match the
-    requested store path.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>URL</literal></term>
-
-    <listitem><para>The URL of the NAR, relative to the binary cache
-    URL.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>Compression</literal></term>
-
-    <listitem><para>The compression method; either
-    <literal>xz</literal> or
-    <literal>bzip2</literal>.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>FileHash</literal></term>
-
-    <listitem><para>The SHA-256 hash of the compressed
-    NAR.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>FileSize</literal></term>
-
-    <listitem><para>The size of the compressed NAR.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>NarHash</literal></term>
-
-    <listitem><para>The SHA-256 hash of the uncompressed NAR.  This is
-    equal to the hash of the store path as returned by
-    <command>nix-store -q --hash
-    <replaceable>p</replaceable></command>.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>NarSize</literal></term>
-
-    <listitem><para>The size of the uncompressed NAR.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>References</literal></term>
-
-    <listitem><para>The references of the store path, without the Nix
-    store prefix.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>Deriver</literal></term>
-
-    <listitem><para>The deriver of the store path, without the Nix
-    store prefix.  This field is optional.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>System</literal></term>
-
-    <listitem><para>The Nix platform type of this binary, if known.
-    This field is optional.</para></listitem>
-
-  </varlistentry>
-
-  <varlistentry><term><literal>Sig</literal></term>
-
-    <listitem><para>A signature of the the form
-    <literal><replaceable>key-name</replaceable>:<replaceable>sig</replaceable></literal>,
-    where <replaceable>key-name</replaceable> is the symbolic name of
-    the key pair used to sign and verify the cache
-    (e.g. <literal>cache.example.org-1</literal>), and
-    <replaceable>sig</replaceable> is the actual signature, computed
-    over the <varname>StorePath</varname>, <varname>NarHash</varname>,
-    <varname>NarSize</varname> and <varname>References</varname>
-    fields using the <link
-    xlink:href="http://ed25519.cr.yp.to/">Ed25519 public-key signature
-    system</link>.</para></listitem>
-
-  </varlistentry>
-
-</variablelist>
-
-</para>
-
-<para>Thus, in our example, after recursively ensuring that the
-references exist (e.g.,
-<filename>/nix/store/2ma2k0ys8knh4an48n28vigcmc2z8773-linux-headers-2.6.23.16</filename>),
-Nix will fetch <screen>
-https://cache.nixos.org/nar/0zzjpdz46mdn74v09m053yczlz4am038g8r74iy8w43gx8801h70.nar.bz2
-</screen> and decompress and unpack it to
-<filename>/nix/store/a8922c0h87iilxzzvwn2hmv8x210aqb9-glibc-2.7</filename>.</para>
-
-</refsection>
-
-
-</refentry>
diff --git a/doc/manual/command-ref/nix-store.xml b/doc/manual/command-ref/nix-store.xml
index 346718588b77..0f6172defb38 100644
--- a/doc/manual/command-ref/nix-store.xml
+++ b/doc/manual/command-ref/nix-store.xml
@@ -1390,8 +1390,7 @@ parameters:
 
 </orderedlist>
 
-For an example, see the manual page for <command
-linkend="sec-nix-push">nix-push</command>.</para>
+</para>
 
 </refsection>
 
diff --git a/doc/manual/command-ref/utilities.xml b/doc/manual/command-ref/utilities.xml
index 25e457e4e554..893f5b5b5260 100644
--- a/doc/manual/command-ref/utilities.xml
+++ b/doc/manual/command-ref/utilities.xml
@@ -14,9 +14,7 @@ work with Nix.</para>
 <xi:include href="nix-copy-closure.xml" />
 <xi:include href="nix-daemon.xml" />
 <xi:include href="nix-hash.xml" />
-<xi:include href="nix-install-package.xml" />
 <xi:include href="nix-instantiate.xml" />
 <xi:include href="nix-prefetch-url.xml" />
-<xi:include href="nix-push.xml" />
 
 </chapter>
diff --git a/doc/manual/expressions/builtins.xml b/doc/manual/expressions/builtins.xml
index eae5f5a029bf..6ac802343236 100644
--- a/doc/manual/expressions/builtins.xml
+++ b/doc/manual/expressions/builtins.xml
@@ -142,7 +142,7 @@ if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
     evaluates to the Nix platform identifier for the Nix installation
     on which the expression is being evaluated, such as
     <literal>"i686-linux"</literal> or
-    <literal>"powerpc-darwin"</literal>.</para></listitem>
+    <literal>"x86_64-darwin"</literal>.</para></listitem>
 
   </varlistentry>
 
@@ -853,7 +853,14 @@ builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]
     len</replaceable> lies beyond the end of the string, only the
     substring up to the end of the string is returned.
     <replaceable>start</replaceable> must be
-    non-negative.</para></listitem>
+    non-negative. For example,
+
+<programlisting>
+builtins.substring 0 3 "nixos"
+</programlisting>
+
+   evaluates to <literal>"nix"</literal>.
+   </para></listitem>
 
   </varlistentry>
 
diff --git a/doc/manual/expressions/derivations.xml b/doc/manual/expressions/derivations.xml
index f2a73dccfe18..5efe2213e370 100644
--- a/doc/manual/expressions/derivations.xml
+++ b/doc/manual/expressions/derivations.xml
@@ -16,7 +16,7 @@ of which specify the inputs of the build.</para>
   <listitem xml:id="attr-system"><para>There must be an attribute named
   <varname>system</varname> whose value must be a string specifying a
   Nix platform identifier, such as <literal>"i686-linux"</literal> or
-  <literal>"powerpc-darwin"</literal><footnote><para>To figure out
+  <literal>"x86_64-darwin"</literal><footnote><para>To figure out
   your platform identifier, look at the line <quote>Checking for the
   canonical Nix system name</quote> in the output of Nix's
   <filename>configure</filename> script.</para></footnote> The build
diff --git a/doc/manual/introduction/quick-start.xml b/doc/manual/introduction/quick-start.xml
index 0d13651e0ab3..5ae9f6ad543b 100644
--- a/doc/manual/introduction/quick-start.xml
+++ b/doc/manual/introduction/quick-start.xml
@@ -95,18 +95,6 @@ The latter command will upgrade each installed package for which there
 is a “newer” version (as determined by comparing the version
 numbers).</para></step>
 
-<!--
-<step><para>You can also install specific packages directly from
-your web browser.  For instance, you can go to <link
-xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest"
-/> and click on any link for the individual packages for your
-platform.  Associate <literal>application/nix-package</literal> with
-the program <command>nix-install-package</command>.  A window should
-appear asking you whether it’s okay to install the package.  Say
-<literal>Y</literal>.  The package and all its dependencies will be
-installed.</para></step>
--->
-
 <step><para>If you're unhappy with the result of a
 <command>nix-env</command> action (e.g., an upgraded package turned
 out not to work properly), you can go back:
diff --git a/doc/manual/local.mk b/doc/manual/local.mk
index 3c4fc52dfd67..d89555899a70 100644
--- a/doc/manual/local.mk
+++ b/doc/manual/local.mk
@@ -39,9 +39,9 @@ dist-files += $(d)/manual.xmli $(d)/version.txt $(d)/manual.is-valid
 # Generate man pages.
 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-collect-garbage.1 \
   nix-prefetch-url.1 nix-channel.1 \
-  nix-install-package.1 nix-hash.1 nix-copy-closure.1 \
+  nix-hash.1 nix-copy-closure.1 \
   nix.conf.5 nix-daemon.8, \
   $(d)/$(n))
 
diff --git a/doc/manual/packages/one-click.xml b/doc/manual/packages/one-click.xml
deleted file mode 100644
index cef9a2bbff4e..000000000000
--- a/doc/manual/packages/one-click.xml
+++ /dev/null
@@ -1,37 +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-one-click">
-
-<title>One-Click Installation</title>
-
-<para>Often, when you want to install a specific package (e.g., from
-the <link
-xlink:href="http://nixos.org/nixpkgs/">Nix
-Packages collection</link>), subscribing to a channel is a bit
-cumbersome.  And channels don’t help you at all if you want to install
-an older version of a package than the one provided by the current
-contents of the channel, or a package that has been removed from the
-channel.  That’s when <emphasis>one-click installs</emphasis> come in
-handy: you can just go to the web page that contains the package,
-click on it, and it will be installed with all the necessary
-dependencies.</para>
-
-<para>For instance, you can go to <link
-xlink:href="http://hydra.nixos.org/jobset/nixpkgs/trunk/channel/latest"
-/> and click on any link for the individual packages for your
-platform.  The first time you do this, your browser will ask what to
-do with <literal>application/nix-package</literal> files.  You should
-open them with <filename>/nix/bin/nix-install-package</filename>.
-This will open a window that asks you to confirm that you want to
-install the package.  When you answer <literal>Y</literal>, the
-package and all its dependencies will be installed.  This is a binary
-deployment mechanism — you get packages pre-compiled for the selected
-platform type.</para>
-
-<para>You can also install <literal>application/nix-package</literal>
-files from the command line directly.  See <xref
-linkend='sec-nix-install-package' /> for details.</para>
-
-</chapter>
\ No newline at end of file
diff --git a/doc/manual/packages/package-management.xml b/doc/manual/packages/package-management.xml
index 5cc5c381bb43..61e55faeb311 100644
--- a/doc/manual/packages/package-management.xml
+++ b/doc/manual/packages/package-management.xml
@@ -18,7 +18,6 @@ who want to <emphasis>create</emphasis> packages should consult
 <xi:include href="profiles.xml" />
 <xi:include href="garbage-collection.xml" />
 <xi:include href="channels.xml" />
-<xi:include href="one-click.xml" />
 <xi:include href="sharing-packages.xml" />
 
 </part>
diff --git a/misc/docker/Dockerfile b/misc/docker/Dockerfile
index 098633fc3c86..20171d250207 100644
--- a/misc/docker/Dockerfile
+++ b/misc/docker/Dockerfile
@@ -5,7 +5,9 @@ RUN wget -O- http://nixos.org/releases/nix/nix-1.11.2/nix-1.11.2-x86_64-linux.ta
     && for i in $(seq 1 30); do echo "nixbld$i:x:$((30000 + $i)):30000:::" >> /etc/passwd; done \
     && mkdir -m 0755 /nix && USER=root sh nix-*-x86_64-linux/install \
     && echo ". /root/.nix-profile/etc/profile.d/nix.sh" >> /etc/profile \
-    && rm -r /nix-*-x86_64-linux
+    && rm -r /nix-*-x86_64-linux \
+    && apk --update add bash tar \
+    && rm -rf /var/cache/apk/*
 
 ONBUILD ENV \
     ENV=/etc/profile \
diff --git a/release.nix b/release.nix
index 1da34443dd4f..8b8d96a2ec55 100644
--- a/release.nix
+++ b/release.nix
@@ -236,7 +236,6 @@ let
     tests.evalNixOS =
       pkgs.runCommand "eval-nixos" { buildInputs = [ build.x86_64-linux ]; }
         ''
-          export NIX_DB_DIR=$TMPDIR
           export NIX_STATE_DIR=$TMPDIR
           nix-store --init
 
diff --git a/scripts/download-from-binary-cache.pl.in b/scripts/download-from-binary-cache.pl.in
deleted file mode 100644
index a4f858610aca..000000000000
--- a/scripts/download-from-binary-cache.pl.in
+++ /dev/null
@@ -1,632 +0,0 @@
-#! @perl@ -w @perlFlags@
-
-use utf8;
-use DBI;
-use DBD::SQLite;
-use File::Basename;
-use IO::Select;
-use Nix::Config;
-use Nix::Store;
-use Nix::Utils;
-use Nix::Manifest;
-use WWW::Curl::Easy;
-use WWW::Curl::Multi;
-use strict;
-
-STDERR->autoflush(1);
-binmode STDERR, ":encoding(utf8)";
-
-Nix::Config::readConfig;
-
-my @caches;
-my $gotCaches = 0;
-
-my $maxParallelRequests = int($Nix::Config::config{"binary-caches-parallel-connections"} // 25);
-$maxParallelRequests = 1 if $maxParallelRequests < 1;
-
-my $ttlNegative = 24 * 3600; # when to purge negative lookups from the database
-my $ttlNegativeUse = 3600; # how long negative lookups are valid for non-"have" lookups
-my $didExpiration = 0;
-
-my $showAfter = 5; # show that we're waiting for a request after this many seconds
-
-my $debug = ($Nix::Config::config{"debug-subst"} // "") eq 1 || ($Nix::Config::config{"untrusted-debug-subst"} // "") eq 1;
-
-my $cacheFileURLs = ($ENV{"_NIX_CACHE_FILE_URLS"} // "") eq 1; # for testing
-
-my ($dbh, $queryCache, $insertNAR, $queryNAR, $insertNARExistence, $queryNARExistence, $expireNARExistence);
-
-my $curlm = WWW::Curl::Multi->new;
-my $activeRequests = 0;
-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";
-
-my $userAgent = "Nix/$Nix::Config::version";
-
-sub isTrue {
-    my ($x) = @_;
-    return $x eq "true" || $x eq "1";
-}
-
-# FIXME: this should be cache URLs required to have valid signatures,
-# or "*" to require signatures on all binary caches.
-# FIXME: should binary caches using a key in
-# ‘binary-cache-public-keys’ be trusted by default?
-my $requireSignedBinaryCaches = ($Nix::Config::config{"signed-binary-caches"} // "0") ne "0";
-
-my $curlConnectTimeout = int(
-    $Nix::Config::config{"untrusted-connect-timeout"} //
-    $Nix::Config::config{"connect-timeout"} //
-    $ENV{"NIX_CONNECT_TIMEOUT"} // 0);
-
-
-sub addRequest {
-    my ($storePath, $url, $head) = @_;
-
-    my $curl = WWW::Curl::Easy->new;
-    my $curlId = $curlIdCount++;
-    $requests{$curlId} = { storePath => $storePath, url => $url, handle => $curl, content => "", type => $head ? "HEAD" : "GET"
-                         , shown => 0, started => time() };
-
-    $curl->setopt(CURLOPT_PRIVATE, $curlId);
-    $curl->setopt(CURLOPT_URL, $url);
-    open (my $fh, ">", \$requests{$curlId}->{content});
-    $curl->setopt(CURLOPT_WRITEDATA, $fh);
-    $curl->setopt(CURLOPT_FOLLOWLOCATION, 1);
-    $curl->setopt(CURLOPT_CAINFO, $caBundle) if defined $caBundle;
-
-    unless (isTrue($Nix::Config::config{"verify-https-binary-caches"} // "1")) {
-        $curl->setopt(CURLOPT_SSL_VERIFYPEER, 0);
-        $curl->setopt(CURLOPT_SSL_VERIFYHOST, 0);
-    }
-
-    $curl->setopt(CURLOPT_USERAGENT, $userAgent);
-    $curl->setopt(CURLOPT_NOBODY, 1) if $head;
-    $curl->setopt(CURLOPT_FAILONERROR, 1);
-    $curl->setopt(CURLOPT_CONNECTTIMEOUT, $curlConnectTimeout);
-    $curl->setopt(CURLOPT_TIMEOUT, 20 * 60);
-
-    if ($activeRequests >= $maxParallelRequests) {
-        $scheduled{$curlId} = 1;
-    } else {
-        $curlm->add_handle($curl);
-        $activeRequests++;
-    }
-
-    return $requests{$curlId};
-}
-
-
-sub processRequests {
-    while ($activeRequests) {
-        my ($rfds, $wfds, $efds) = $curlm->fdset();
-        #print STDERR "R = @{$rfds}, W = @{$wfds}, E = @{$efds}\n";
-
-        # Sleep until we can read or write some data.
-        if (scalar @{$rfds} + scalar @{$wfds} + scalar @{$efds} > 0) {
-            IO::Select->select(IO::Select->new(@{$rfds}), IO::Select->new(@{$wfds}), IO::Select->new(@{$efds}), 1.0);
-        }
-
-        if ($curlm->perform() != $activeRequests) {
-            while (my ($id, $result) = $curlm->info_read) {
-                if ($id) {
-                    my $request = $requests{$id} or die;
-                    my $handle = $request->{handle};
-                    $request->{result} = $result;
-                    $request->{httpStatus} = $handle->getinfo(CURLINFO_RESPONSE_CODE);
-
-                    print STDERR "$request->{type} on $request->{url} [$request->{result}, $request->{httpStatus}]\n" if $debug;
-
-                    $activeRequests--;
-                    delete $request->{handle};
-
-                    if (scalar(keys %scheduled) > 0) {
-                        my $id2 = (keys %scheduled)[0];
-                        $curlm->add_handle($requests{$id2}->{handle});
-                        $activeRequests++;
-                        delete $scheduled{$id2};
-                    }
-                }
-            }
-        }
-
-        my $time = time();
-        while (my ($key, $request) = each %requests) {
-            next unless defined $request->{handle};
-            next if $request->{shown};
-            if ($time > $request->{started} + $showAfter) {
-                print STDERR "still waiting for ‘$request->{url}’ after $showAfter seconds...\n";
-                $request->{shown} = 1;
-            }
-        }
-    }
-}
-
-
-sub initCache {
-    my $dbPath = "$Nix::Config::stateDir/binary-cache-v3.sqlite";
-
-    unlink "$Nix::Config::stateDir/binary-cache-v1.sqlite";
-    unlink "$Nix::Config::stateDir/binary-cache-v2.sqlite";
-
-    # Open/create the database.
-    $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "")
-        or die "cannot open database ‘$dbPath’";
-    $dbh->{RaiseError} = 1;
-    $dbh->{PrintError} = 0;
-
-    $dbh->sqlite_busy_timeout(60 * 60 * 1000);
-
-    $dbh->do("pragma synchronous = off"); # we can always reproduce the cache
-    $dbh->do("pragma journal_mode = truncate");
-
-    # Initialise the database schema, if necessary.
-    $dbh->do(<<EOF);
-        create table if not exists BinaryCaches (
-            id        integer primary key autoincrement not null,
-            url       text unique not null,
-            timestamp integer not null,
-            storeDir  text not null,
-            wantMassQuery integer not null,
-            priority  integer not null
-        );
-EOF
-
-    $dbh->do(<<EOF);
-        create table if not exists NARs (
-            cache            integer not null,
-            storePath        text not null,
-            url              text not null,
-            compression      text not null,
-            fileHash         text,
-            fileSize         integer,
-            narHash          text,
-            narSize          integer,
-            refs             text,
-            deriver          text,
-            signedBy         text,
-            timestamp        integer not null,
-            primary key (cache, storePath),
-            foreign key (cache) references BinaryCaches(id) on delete cascade
-        );
-EOF
-
-    $dbh->do(<<EOF);
-        create table if not exists NARExistence (
-            cache            integer not null,
-            storePath        text not null,
-            exist            integer not null,
-            timestamp        integer not null,
-            primary key (cache, storePath),
-            foreign key (cache) references BinaryCaches(id) on delete cascade
-        );
-EOF
-
-    $dbh->do("create index if not exists NARExistenceByExistTimestamp on NARExistence (exist, timestamp)");
-
-    $queryCache = $dbh->prepare("select id, storeDir, wantMassQuery, priority from BinaryCaches where url = ?") or die;
-
-    $insertNAR = $dbh->prepare(
-        "insert or replace into NARs(cache, storePath, url, compression, fileHash, fileSize, narHash, " .
-        "narSize, refs, deriver, signedBy, timestamp) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") or die;
-
-    $queryNAR = $dbh->prepare("select * from NARs where cache = ? and storePath = ?") or die;
-
-    $insertNARExistence = $dbh->prepare(
-        "insert or replace into NARExistence(cache, storePath, exist, timestamp) values (?, ?, ?, ?)") or die;
-
-    $queryNARExistence = $dbh->prepare("select exist, timestamp from NARExistence where cache = ? and storePath = ?") or die;
-
-    $expireNARExistence = $dbh->prepare("delete from NARExistence where exist = ? and timestamp < ?") or die;
-}
-
-
-sub getAvailableCaches {
-    return if $gotCaches;
-    $gotCaches = 1;
-
-    sub strToList {
-        my ($s) = @_;
-        return map { s/\/+$//; $_ } split(/ /, $s);
-    }
-
-    my @urls = strToList($Nix::Config::config{"binary-caches"} //
-        ($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/*";
-    foreach my $urlFile (glob $urlsFiles) {
-        next unless -f $urlFile;
-        open FILE, "<$urlFile" or die "cannot open ‘$urlFile’\n";
-        my $url = <FILE>; chomp $url;
-        close FILE;
-        push @urls, strToList($url);
-    }
-
-    push @urls, strToList($Nix::Config::config{"extra-binary-caches"} // "");
-
-    # Allow Nix daemon users to override the binary caches to a subset
-    # of those listed in the config file.  Note that ‘untrusted-*’
-    # denotes options passed by the client.
-    my @trustedUrls = uniq(@urls, strToList($Nix::Config::config{"trusted-binary-caches"} // ""));
-
-    if (defined $Nix::Config::config{"untrusted-binary-caches"}) {
-        my @untrustedUrls = strToList $Nix::Config::config{"untrusted-binary-caches"};
-        @urls = ();
-        foreach my $url (@untrustedUrls) {
-            die "binary cache ‘$url’ is not trusted (please add it to ‘trusted-binary-caches’ in $Nix::Config::confDir/nix.conf)\n"
-                unless scalar(grep { $url eq $_ } @trustedUrls) > 0;
-            push @urls, $url;
-        }
-    }
-
-    my @untrustedUrls = strToList $Nix::Config::config{"untrusted-extra-binary-caches"} // "";
-    foreach my $url (@untrustedUrls) {
-        unless (scalar(grep { $url eq $_ } @trustedUrls) > 0) {
-            warn "binary cache ‘$url’ is not trusted (please add it to ‘trusted-binary-caches’ in $Nix::Config::confDir/nix.conf)\n";
-            next;
-        }
-        push @urls, $url;
-    }
-
-    foreach my $url (uniq @urls) {
-
-        # FIXME: not atomic.
-        $queryCache->execute($url);
-        my $res = $queryCache->fetchrow_hashref();
-        if (defined $res) {
-            next if $res->{storeDir} ne $Nix::Config::storeDir;
-            push @caches, { id => $res->{id}, url => $url, wantMassQuery => $res->{wantMassQuery}, priority => $res->{priority} };
-            next;
-        }
-
-        # Get the cache info file.
-        my $request = addRequest(undef, $url . "/nix-cache-info");
-        processRequests;
-
-        if ($request->{result} != 0) {
-            print STDERR "could not download ‘$request->{url}’ (" .
-                ($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
-            next;
-        }
-
-        my $storeDir = "/nix/store";
-        my $wantMassQuery = 0;
-        my $priority = 50;
-        foreach my $line (split "\n", $request->{content}) {
-            unless ($line =~ /^(.*): (.*)$/) {
-                print STDERR "bad cache info file ‘$request->{url}’\n";
-                return undef;
-            }
-            if ($1 eq "StoreDir") { $storeDir = $2; }
-            elsif ($1 eq "WantMassQuery") { $wantMassQuery = int($2); }
-            elsif ($1 eq "Priority") { $priority = int($2); }
-        }
-
-        $dbh->do("insert or replace into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)",
-                 {}, $url, time(), $storeDir, $wantMassQuery, $priority);
-        $queryCache->execute($url);
-        $res = $queryCache->fetchrow_hashref() or die;
-        next if $storeDir ne $Nix::Config::storeDir;
-        push @caches, { id => $res->{id}, url => $url, wantMassQuery => $wantMassQuery, priority => $priority };
-    }
-
-    @caches = sort { $a->{priority} <=> $b->{priority} } @caches;
-
-    expireNegative();
-}
-
-
-sub shouldCache {
-    my ($url) = @_;
-    return $cacheFileURLs || $url !~ /^file:/;
-}
-
-
-sub processNARInfo {
-    my ($storePath, $cache, $request) = @_;
-
-    if ($request->{result} != 0) {
-        if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
-            print STDERR "could not download ‘$request->{url}’ (" .
-                ($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
-        } else {
-            $insertNARExistence->execute($cache->{id}, basename($storePath), 0, time())
-                if shouldCache $request->{url};
-        }
-        return undef;
-    }
-
-    my $narInfo = parseNARInfo($storePath, $request->{content}, $requireSignedBinaryCaches, $request->{url});
-    return undef unless defined $narInfo;
-
-    die if $requireSignedBinaryCaches && !defined $narInfo->{signedBy};
-
-    # Cache the result.
-    $insertNAR->execute(
-        $cache->{id}, basename($storePath), $narInfo->{url}, $narInfo->{compression},
-        $narInfo->{fileHash}, $narInfo->{fileSize}, $narInfo->{narHash}, $narInfo->{narSize},
-        join(" ", @{$narInfo->{refs}}), $narInfo->{deriver}, $narInfo->{signedBy}, time())
-        if shouldCache $request->{url};
-
-    return $narInfo;
-}
-
-
-sub getCachedInfoFrom {
-    my ($storePath, $cache) = @_;
-
-    $queryNAR->execute($cache->{id}, basename($storePath));
-    my $res = $queryNAR->fetchrow_hashref();
-    return undef unless defined $res;
-
-    # We may previously have cached this info when signature checking
-    # was disabled.  In that case, ignore the cached info.
-    return undef if $requireSignedBinaryCaches && !defined $res->{signedBy};
-
-    return
-        { url => $res->{url}
-        , compression => $res->{compression}
-        , fileHash => $res->{fileHash}
-        , fileSize => $res->{fileSize}
-        , narHash => $res->{narHash}
-        , narSize => $res->{narSize}
-        , refs => [ split " ", $res->{refs} ]
-        , deriver => $res->{deriver}
-        , signedBy => $res->{signedBy}
-        } if defined $res;
-}
-
-
-sub negativeHit {
-    my ($storePath, $cache) = @_;
-    $queryNARExistence->execute($cache->{id}, basename($storePath));
-    my $res = $queryNARExistence->fetchrow_hashref();
-    return defined $res && $res->{exist} == 0 && time() - $res->{timestamp} < $ttlNegativeUse;
-}
-
-
-sub positiveHit {
-    my ($storePath, $cache) = @_;
-    return 1 if defined getCachedInfoFrom($storePath, $cache);
-    $queryNARExistence->execute($cache->{id}, basename($storePath));
-    my $res = $queryNARExistence->fetchrow_hashref();
-    return defined $res && $res->{exist} == 1;
-}
-
-
-sub expireNegative {
-    return if $didExpiration;
-    $didExpiration = 1;
-    my $time = time();
-    # Round up to the next multiple of the TTL to ensure that we do
-    # expiration only once per time interval.  E.g. if $ttlNegative ==
-    # 3600, we expire entries at most once per hour.  This is
-    # presumably faster than expiring a few entries per request (and
-    # thus doing a transaction).
-    my $limit = (int($time / $ttlNegative) - 1) * $ttlNegative;
-    $expireNARExistence->execute($limit, 0);
-    print STDERR "expired ", $expireNARExistence->rows, " negative entries\n" if $debug;
-}
-
-
-sub printInfo {
-    my ($storePath, $info) = @_;
-    print "$storePath\n";
-    print $info->{deriver} ? "$Nix::Config::storeDir/$info->{deriver}" : "", "\n";
-    print scalar @{$info->{refs}}, "\n";
-    print "$Nix::Config::storeDir/$_\n" foreach @{$info->{refs}};
-    print $info->{fileSize} || 0, "\n";
-    print $info->{narSize} || 0, "\n";
-}
-
-
-sub infoUrl {
-    my ($binaryCacheUrl, $storePath) = @_;
-    my $pathHash = substr(basename($storePath), 0, 32);
-    my $infoUrl = "$binaryCacheUrl/$pathHash.narinfo";
-}
-
-
-sub printInfoParallel {
-    my @paths = @_;
-
-    # First print all paths for which we have cached info.
-    my @left;
-    foreach my $storePath (@paths) {
-        my $found = 0;
-        foreach my $cache (@caches) {
-            my $info = getCachedInfoFrom($storePath, $cache);
-            if (defined $info) {
-                printInfo($storePath, $info);
-                $found = 1;
-                last;
-            }
-        }
-        push @left, $storePath if !$found;
-    }
-
-    return if scalar @left == 0;
-
-    foreach my $cache (@caches) {
-
-        my @left2;
-        %requests = ();
-        foreach my $storePath (@left) {
-            if (negativeHit($storePath, $cache)) {
-                push @left2, $storePath;
-                next;
-            }
-            addRequest($storePath, infoUrl($cache->{url}, $storePath));
-        }
-
-        processRequests;
-
-        foreach my $request (values %requests) {
-            my $info = processNARInfo($request->{storePath}, $cache, $request);
-            if (defined $info) {
-                printInfo($request->{storePath}, $info);
-            } else {
-                push @left2, $request->{storePath};
-            }
-        }
-
-        @left = @left2;
-    }
-}
-
-
-sub printSubstitutablePaths {
-    my @paths = @_;
-
-    # First look for paths that have cached info.
-    my @left;
-    foreach my $storePath (@paths) {
-        my $found = 0;
-        foreach my $cache (@caches) {
-            next unless $cache->{wantMassQuery};
-            if (positiveHit($storePath, $cache)) {
-                print "$storePath\n";
-                $found = 1;
-                last;
-            }
-        }
-        push @left, $storePath if !$found;
-    }
-
-    return if scalar @left == 0;
-
-    # For remaining paths, do HEAD requests.
-    foreach my $cache (@caches) {
-        next unless $cache->{wantMassQuery};
-        my @left2;
-        %requests = ();
-        foreach my $storePath (@left) {
-            if (negativeHit($storePath, $cache)) {
-                push @left2, $storePath;
-                next;
-            }
-            addRequest($storePath, infoUrl($cache->{url}, $storePath), 1);
-        }
-
-        processRequests;
-
-        foreach my $request (values %requests) {
-            if ($request->{result} != 0) {
-                if ($request->{result} != 37 && $request->{httpStatus} != 404 && $request->{httpStatus} != 403) {
-                    print STDERR "could not check ‘$request->{url}’ (" .
-                        ($request->{result} != 0 ? "Curl error $request->{result}" : "HTTP status $request->{httpStatus}") . ")\n";
-                } else {
-                    $insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 0, time())
-                        if shouldCache $request->{url};
-                }
-                push @left2, $request->{storePath};
-            } else {
-                $insertNARExistence->execute($cache->{id}, basename($request->{storePath}), 1, time())
-                    if shouldCache $request->{url};
-                print "$request->{storePath}\n";
-            }
-        }
-
-        @left = @left2;
-    }
-}
-
-
-sub downloadBinary {
-    my ($storePath, $destPath) = @_;
-
-    foreach my $cache (@caches) {
-        my $info = getCachedInfoFrom($storePath, $cache);
-
-        unless (defined $info) {
-            next if negativeHit($storePath, $cache);
-            my $request = addRequest($storePath, infoUrl($cache->{url}, $storePath));
-            processRequests;
-            $info = processNARInfo($storePath, $cache, $request);
-        }
-
-        next unless defined $info;
-
-        my $decompressor;
-        if ($info->{compression} eq "bzip2") { $decompressor = "| $Nix::Config::bzip2 -d"; }
-        elsif ($info->{compression} eq "xz") { $decompressor = "| $Nix::Config::xz -d"; }
-        elsif ($info->{compression} eq "none") { $decompressor = ""; }
-        else {
-            print STDERR "unknown compression method ‘$info->{compression}’\n";
-            next;
-        }
-        my $url = "$cache->{url}/$info->{url}"; # FIXME: handle non-relative URLs
-        die if $requireSignedBinaryCaches && !defined $info->{signedBy};
-        print STDERR "\n*** Downloading ‘$url’ ", ($requireSignedBinaryCaches ? "(signed by ‘$info->{signedBy}’) " : ""), "to ‘$storePath’...\n";
-        checkURL $url;
-        if (system("$Nix::Config::curl --fail --location --connect-timeout $curlConnectTimeout -A '$userAgent' '$url' $decompressor | $Nix::Config::binDir/nix-store --restore $destPath") != 0) {
-            warn "download of ‘$url’ failed" . ($! ? ": $!" : "") . "\n";
-            next;
-        }
-
-        # Tell Nix about the expected hash so it can verify it.
-        die unless defined $info->{narHash} && $info->{narHash} ne "";
-        print "$info->{narHash}\n";
-
-        print STDERR "\n";
-        return;
-    }
-
-    print STDERR "could not download ‘$storePath’ from any binary cache\n";
-    exit 1;
-}
-
-
-# Bail out right away if binary caches are disabled.
-exit 0 if
-    ($Nix::Config::config{"use-binary-caches"} // "true") eq "false" ||
-    ($Nix::Config::config{"untrusted-use-binary-caches"} // "true") eq "false";
-print "\n";
-flush STDOUT;
-
-initCache();
-
-
-if ($ARGV[0] eq "--query") {
-
-    while (<STDIN>) {
-        getAvailableCaches;
-        chomp;
-        my ($cmd, @args) = split " ", $_;
-
-        if ($cmd eq "have") {
-            print STDERR "checking binary caches for existence of @args\n" if $debug;
-            printSubstitutablePaths(@args);
-            print "\n";
-        }
-
-        elsif ($cmd eq "info") {
-            print STDERR "checking binary caches for info on @args\n" if $debug;
-            printInfoParallel(@args);
-            print "\n";
-        }
-
-        else { die "unknown command ‘$cmd’"; }
-
-        flush STDOUT;
-    }
-
-}
-
-elsif ($ARGV[0] eq "--substitute") {
-    my $storePath = $ARGV[1] or die;
-    my $destPath = $ARGV[2] or die;
-    getAvailableCaches;
-    downloadBinary($storePath, $destPath);
-}
-
-else {
-    die;
-}
diff --git a/scripts/local.mk b/scripts/local.mk
index edaf44cc492d..fef256451d8b 100644
--- a/scripts/local.mk
+++ b/scripts/local.mk
@@ -2,8 +2,6 @@ nix_bin_scripts := \
   $(d)/nix-build \
   $(d)/nix-channel \
   $(d)/nix-copy-closure \
-  $(d)/nix-install-package \
-  $(d)/nix-push
 
 bin-scripts += $(nix_bin_scripts)
 
diff --git a/scripts/nix-install-package.in b/scripts/nix-install-package.in
deleted file mode 100755
index ba349774af54..000000000000
--- a/scripts/nix-install-package.in
+++ /dev/null
@@ -1,127 +0,0 @@
-#! @perl@ -w @perlFlags@
-
-use utf8;
-use strict;
-use Nix::Config;
-use Nix::Utils;
-
-binmode STDERR, ":encoding(utf8)";
-
-
-# Parse the command line arguments.
-my @args = @ARGV;
-
-my $source;
-my $fromURL = 0;
-my @extraNixEnvArgs = ();
-my $interactive = 1;
-my $op = "--install";
-
-while (scalar @args) {
-    my $arg = shift @args;
-    if ($arg eq "--help") {
-        exec "man nix-install-package" or die;
-    }
-    elsif ($arg eq "--url") {
-        $fromURL = 1;
-    }
-    elsif ($arg eq "--profile" || $arg eq "-p") {
-        my $profile = shift @args;
-        die "$0: ‘--profile’ requires an argument\n" if !defined $profile;
-        push @extraNixEnvArgs, "-p", $profile;
-    }
-    elsif ($arg eq "--set") {
-        $op = "--set";
-    }
-    elsif ($arg eq "--non-interactive") {
-        $interactive = 0;
-    }
-    else {
-        $source = $arg;
-    }
-}
-
-die "$0: please specify a .nixpkg file or URL\n" unless defined $source;
-
-
-# Re-execute in a terminal, if necessary, so that if we're executed
-# from a web browser, the user gets to see us.
-if ($interactive && !defined $ENV{"NIX_HAVE_TERMINAL"}) {
-    $ENV{"NIX_HAVE_TERMINAL"} = "1";
-    $ENV{"LD_LIBRARY_PATH"} = "";
-    foreach my $term ("xterm", "konsole", "gnome-terminal", "xterm") {
-        exec($term, "-e", "$Nix::Config::binDir/nix-install-package", @ARGV);
-    }
-    die "cannot execute ‘xterm’";
-}
-
-
-my $tmpDir = mkTempDir("nix-install-package");
-
-
-sub barf {
-    my $msg = shift;
-    print "\nInstallation failed: $msg\n";
-    <STDIN> if $interactive;
-    exit 1;
-}
-
-
-# Download the package description, if necessary.
-my $pkgFile = $source;
-if ($fromURL) {
-    $pkgFile = "$tmpDir/tmp.nixpkg";
-    system("@curl@", "-L", "--silent", $source, "-o", $pkgFile) == 0
-        or barf "curl failed: $?";
-}
-
-
-# Read and parse the package file.
-open PKGFILE, "<$pkgFile" or barf "cannot open ‘$pkgFile’: $!";
-my $contents = <PKGFILE>;
-close PKGFILE;
-
-my $nameRE = "(?: [A-Za-z0-9\+\-\.\_\?\=]+ )"; # see checkStoreName()
-my $systemRE = "(?: [A-Za-z0-9\+\-\_]+ )";
-my $pathRE = "(?: \/ [\/A-Za-z0-9\+\-\.\_\?\=]* )";
-
-# Note: $pathRE doesn't check that whether we're looking at a valid
-# store path.  We'll let nix-env do that.
-
-$contents =~
-    / ^ \s* (\S+) \s+ (\S+) \s+ ($nameRE) \s+ ($systemRE) \s+ ($pathRE) \s+ ($pathRE) ( \s+ ($Nix::Utils::urlRE) )?  /x
-    or barf "invalid package contents";
-my $version = $1;
-my $manifestURL = $2;
-my $drvName = $3;
-my $system = $4;
-my $drvPath = $5;
-my $outPath = $6;
-my $binaryCacheURL = $8;
-
-barf "invalid package version ‘$version’" unless $version eq "NIXPKG1";
-
-
-if ($interactive) {
-    # Ask confirmation.
-    print "Do you want to install ‘$drvName’ (Y/N)? ";
-    my $reply = <STDIN>;
-    chomp $reply;
-    exit if $reply ne "y" && $reply ne "Y";
-}
-
-
-die "$0: package does not supply a binary cache\n" unless defined $binaryCacheURL;
-
-push @extraNixEnvArgs, "--option", "extra-binary-caches", $binaryCacheURL;
-
-
-print "\nInstalling package...\n";
-system("$Nix::Config::binDir/nix-env", $op, $outPath, "--force-name", $drvName, @extraNixEnvArgs) == 0
-    or barf "nix-env failed: $?";
-
-
-if ($interactive) {
-    print "\nInstallation succeeded! Press Enter to continue.\n";
-    <STDIN>;
-}
diff --git a/scripts/nix-push.in b/scripts/nix-push.in
deleted file mode 100755
index 54456ac9512e..000000000000
--- a/scripts/nix-push.in
+++ /dev/null
@@ -1,296 +0,0 @@
-#! @perl@ -w @perlFlags@
-
-use utf8;
-use strict;
-use File::Basename;
-use File::Path qw(mkpath);
-use File::stat;
-use File::Copy;
-use MIME::Base64;
-use Nix::Config;
-use Nix::Store;
-use Nix::Manifest;
-use Nix::Utils;
-
-binmode STDERR, ":encoding(utf8)";
-
-my $tmpDir = mkTempDir("nix-push");
-
-my $nixExpr = "$tmpDir/create-nars.nix";
-
-
-# Parse the command line.
-my $compressionType = "xz";
-my $force = 0;
-my $destDir;
-my $writeManifest = 0;
-my $manifestPath;
-my $archivesURL;
-my $link = 0;
-my $secretKeyFile;
-my @roots;
-my @buildArgs;
-
-for (my $n = 0; $n < scalar @ARGV; $n++) {
-    my $arg = $ARGV[$n];
-
-    if ($arg eq "--help") {
-        exec "man nix-push" or die;
-    } elsif ($arg eq "--bzip2") {
-        $compressionType = "bzip2";
-    } elsif ($arg eq "--none") {
-        $compressionType = "none";
-    } elsif ($arg eq "--force") {
-        $force = 1;
-    } elsif ($arg eq "--dest") {
-        $n++;
-        die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
-        $destDir = $ARGV[$n];
-        mkpath($destDir, 0, 0755);
-    } elsif ($arg eq "--manifest") {
-        $writeManifest = 1;
-    } elsif ($arg eq "--manifest-path") {
-        $n++;
-        die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
-        $manifestPath = $ARGV[$n];
-        $writeManifest = 1;
-        mkpath(dirname($manifestPath), 0, 0755);
-    } elsif ($arg eq "--url-prefix") {
-        $n++;
-        die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
-        $archivesURL = $ARGV[$n];
-    } elsif ($arg eq "--link") {
-        $link = 1;
-    } elsif ($arg eq "--key-file") {
-        $n++;
-        die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
-        $secretKeyFile = $ARGV[$n];
-    } elsif ($arg eq "--max-jobs" || $arg eq "-j") {
-        $n++;
-        die "$0: ‘$arg’ requires an argument\n" unless $n < scalar @ARGV;
-        push @buildArgs, ($arg, $ARGV[$n]);
-    } elsif (substr($arg, 0, 1) eq "-") {
-        die "$0: unknown flag ‘$arg’\n";
-    } else {
-        push @roots, $arg;
-    }
-}
-
-die "$0: please specify a destination directory\n" if !defined $destDir;
-
-$archivesURL = "file://$destDir" unless defined $archivesURL;
-
-
-# From the given store paths, determine the set of requisite store
-# paths, i.e, the paths required to realise them.
-my %storePaths;
-
-foreach my $path (@roots) {
-    # Get all paths referenced by the normalisation of the given
-    # Nix expression.
-    my $pid = open(READ,
-        "$Nix::Config::binDir/nix-store --query --requisites --force-realise " .
-        "--include-outputs '$path'|") or die;
-
-    while (<READ>) {
-        chomp;
-        die "bad: $_" unless /^\//;
-        $storePaths{$_} = "";
-    }
-
-    close READ or die "nix-store failed: $?";
-}
-
-my @storePaths = keys %storePaths;
-
-
-# Don't create archives for files that are already in the binary cache.
-my @storePaths2;
-my %narFiles;
-foreach my $storePath (@storePaths) {
-    my $pathHash = substr(basename($storePath), 0, 32);
-    my $narInfoFile = "$destDir/$pathHash.narinfo";
-    if (!$force && -e $narInfoFile) {
-        my $narInfo = parseNARInfo($storePath, readFile($narInfoFile), 0, $narInfoFile) or die "cannot read ‘$narInfoFile’\n";
-        my $narFile = "$destDir/$narInfo->{url}";
-        if (-e $narFile) {
-            print STDERR "skipping existing $storePath\n";
-            # Add the NAR info to $narFiles if we're writing a
-            # manifest.
-            $narFiles{$storePath} = [
-                { url => ("$archivesURL/" . basename $narInfo->{url})
-                  , hash => $narInfo->{fileHash}
-                  , size => $narInfo->{fileSize}
-                  , compressionType => $narInfo->{compression}
-                  , narHash => $narInfo->{narHash}
-                  , narSize => $narInfo->{narSize}
-                  , references => join(" ", map { "$Nix::Config::storeDir/$_" } @{$narInfo->{refs}})
-                  , deriver => $narInfo->{deriver} ? "$Nix::Config::storeDir/$narInfo->{deriver}" : undef
-                  }
-            ] if $writeManifest;
-            next;
-        }
-    }
-    push @storePaths2, $storePath;
-}
-
-
-# Create a list of Nix derivations that turn each path into a Nix
-# archive.
-open NIX, ">$nixExpr";
-print NIX "[";
-
-foreach my $storePath (@storePaths2) {
-    die unless ($storePath =~ /\/[0-9a-z]{32}[^\"\\\$]*$/);
-
-    # Construct a Nix expression that creates a Nix archive.
-    my $nixexpr =
-        "(import <nix/nar.nix> " .
-        "{ storePath = builtins.storePath \"$storePath\"; hashAlgo = \"sha256\"; compressionType = \"$compressionType\"; }) ";
-
-    print NIX $nixexpr;
-}
-
-print NIX "]";
-close NIX;
-
-
-# Build the Nix expression.
-print STDERR "building compressed archives...\n";
-my @narPaths;
-my $pid = open(READ, "-|", "$Nix::Config::binDir/nix-build", $nixExpr, "-o", "$tmpDir/result", @buildArgs)
-    or die "cannot run nix-build";
-while (<READ>) {
-    chomp;
-    die unless /^\//;
-    push @narPaths, $_;
-}
-close READ or die "nix-build failed: $?";
-
-
-# Write the cache info file.
-my $cacheInfoFile = "$destDir/nix-cache-info";
-if (! -e $cacheInfoFile) {
-    open FILE, ">$cacheInfoFile" or die "cannot create $cacheInfoFile: $!";
-    print FILE "StoreDir: $Nix::Config::storeDir\n";
-    print FILE "WantMassQuery: 0\n"; # by default, don't hit this cache for "nix-env -qas"
-    close FILE;
-}
-
-
-# Copy the archives and the corresponding NAR info files.
-print STDERR "copying archives...\n";
-
-my $totalNarSize = 0;
-my $totalCompressedSize = 0;
-
-for (my $n = 0; $n < scalar @storePaths2; $n++) {
-    my $storePath = $storePaths2[$n];
-    my $narDir = $narPaths[$n];
-    my $baseName = basename $storePath;
-
-    # Get info about the store path.
-    my ($deriver, $narHash, $time, $narSize, $refs) = queryPathInfo($storePath, 1);
-
-    # In some exceptional cases (such as VM tests that use the Nix
-    # store of the host), the database doesn't contain the hash.  So
-    # compute it.
-    if ($narHash =~ /^sha256:0*$/) {
-        my $nar = "$tmpDir/nar";
-        system("$Nix::Config::binDir/nix-store --dump $storePath > $nar") == 0
-            or die "cannot dump $storePath\n";
-        $narHash = `$Nix::Config::binDir/nix-hash --type sha256 --base32 --flat $nar`;
-        die "cannot hash ‘$nar’" if $? != 0;
-        chomp $narHash;
-        $narHash = "sha256:$narHash";
-        $narSize = stat("$nar")->size;
-        unlink $nar or die;
-    }
-
-    $totalNarSize += $narSize;
-
-    # Get info about the compressed NAR.
-    open HASH, "$narDir/nar-compressed-hash" or die "cannot open nar-compressed-hash";
-    my $compressedHash = <HASH>;
-    chomp $compressedHash;
-    $compressedHash =~ /^[0-9a-z]+$/ or die "invalid hash";
-    close HASH;
-
-    my $narName = "$compressedHash.nar" . ($compressionType eq "xz" ? ".xz" : $compressionType eq "bzip2" ? ".bz2" : "");
-
-    my $narFile = "$narDir/$narName";
-    (-f $narFile) or die "NAR file for $storePath not found";
-
-    my $compressedSize = stat($narFile)->size;
-    $totalCompressedSize += $compressedSize;
-
-    printf STDERR "%s [%.2f MiB, %.1f%%]\n", $storePath,
-        $compressedSize / (1024 * 1024), $compressedSize / $narSize * 100;
-
-    # Copy the compressed NAR.
-    my $dst = "$destDir/$narName";
-    if (! -f $dst) {
-        my $tmp = "$destDir/.tmp.$$.$narName";
-        if ($link) {
-            link($narFile, $tmp) or die "cannot link $tmp to $narFile: $!\n";
-        } else {
-            copy($narFile, $tmp) or die "cannot copy $narFile to $tmp: $!\n";
-        }
-        rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
-    }
-
-    # Write the info file.
-    my $info;
-    $info .= "StorePath: $storePath\n";
-    $info .= "URL: $narName\n";
-    $info .= "Compression: $compressionType\n";
-    $info .= "FileHash: sha256:$compressedHash\n";
-    $info .= "FileSize: $compressedSize\n";
-    $info .= "NarHash: $narHash\n";
-    $info .= "NarSize: $narSize\n";
-    $info .= "References: " . join(" ", map { basename $_ } @{$refs}) . "\n";
-    if (defined $deriver) {
-        $info .= "Deriver: " . basename $deriver . "\n";
-        if (isValidPath($deriver)) {
-            my $drv = derivationFromPath($deriver);
-            $info .= "System: $drv->{platform}\n";
-        }
-    }
-
-    if (defined $secretKeyFile) {
-        my $secretKey = readFile $secretKeyFile;
-        my $fingerprint = fingerprintPath($storePath, $narHash, $narSize, $refs);
-        my $sig = signString($secretKey, $fingerprint);
-        $info .= "Sig: $sig\n";
-    }
-
-    my $pathHash = substr(basename($storePath), 0, 32);
-
-    $dst = "$destDir/$pathHash.narinfo";
-    if ($force || ! -f $dst) {
-        my $tmp = "$destDir/.tmp.$$.$pathHash.narinfo";
-        open INFO, ">$tmp" or die;
-        print INFO "$info" or die;
-        close INFO or die;
-        rename($tmp, $dst) or die "cannot rename $tmp to $dst: $!\n";
-    }
-
-    $narFiles{$storePath} = [
-        { url => "$archivesURL/$narName"
-        , hash => "sha256:$compressedHash"
-        , size => $compressedSize
-        , compressionType => $compressionType
-        , narHash => "$narHash"
-        , narSize => $narSize
-        , references => join(" ", @{$refs})
-        , deriver => $deriver
-        }
-    ] if $writeManifest;
-}
-
-printf STDERR "total compressed size %.2f MiB, %.1f%%\n",
-    $totalCompressedSize / (1024 * 1024), $totalCompressedSize / ($totalNarSize || 1) * 100;
-
-
-# Optionally write a manifest.
-writeManifest($manifestPath // "$destDir/MANIFEST", \%narFiles, \()) if $writeManifest;
diff --git a/scripts/show-duplication.pl b/scripts/show-duplication.pl
deleted file mode 100755
index 0604c6696c7a..000000000000
--- a/scripts/show-duplication.pl
+++ /dev/null
@@ -1,73 +0,0 @@
-#! /usr/bin/perl -w
-
-if (scalar @ARGV != 1) {
-    print "syntax: show-duplication.pl PATH\n";
-    exit 1;
-}
-
-my $root = $ARGV[0];
-
-
-my $nameRE = "(?:(?:[A-Za-z0-9\+\_]|(?:-[^0-9]))+)";
-my $versionRE = "(?:[A-Za-z0-9\.\-]+)";
-
-
-my %pkgInstances;
-
-
-my $pid = open(PATHS, "-|") || exec "nix-store", "-qR", $root;
-while (<PATHS>) {
-    chomp;
-    /^.*\/[0-9a-z]*-(.*)$/;
-    my $nameVersion = $1;
-    $nameVersion =~ /^($nameRE)(-($versionRE))?$/;
-    $name = $1;
-    $version = $3;
-    $version = "(unnumbered)" unless defined $version;
-#    print "$nameVersion $name $version\n";
-    push @{$pkgInstances{$name}}, {version => $version, path => $_};
-}
-close PATHS or exit 1;
-
-
-sub pathSize {
-    my $path = shift;
-    my @st = lstat $path or die;
-
-    my $size = $st[7];
-
-    if (-d $path) {
-        opendir DIR, $path or die;
-        foreach my $name (readdir DIR) {
-            next if $name eq "." || $name eq "..";
-            $size += pathSize("$path/$name");
-        }
-    }
-    
-    return $size;
-}
-
-
-my $totalPaths = 0;
-my $totalSize = 0, $totalWaste = 0;
-
-foreach my $name (sort {scalar @{$pkgInstances{$b}} <=> scalar @{$pkgInstances{$a}}} (keys %pkgInstances)) {
-    print "$name ", scalar @{$pkgInstances{$name}}, "\n";
-    my $allSize = 0;
-    foreach my $x (sort {$a->{version} cmp $b->{version}} @{$pkgInstances{$name}}) {
-        $totalPaths++;
-        my $size = pathSize $x->{path};
-        $allSize += $size;
-        print "    $x->{version} $size\n";
-    }
-    my $avgSize = int($allSize / scalar @{$pkgInstances{$name}});
-    my $waste = $allSize - $avgSize;
-    $totalSize += $allSize;
-    $totalWaste += $waste;
-    print "    average $avgSize, waste $waste\n";
-}
-
-
-my $avgDupl = $totalPaths / scalar (keys %pkgInstances);
-my $wasteFactor = ($totalWaste / $totalSize) * 100;
-print "average package duplication $avgDupl, total size $totalSize, total waste $totalWaste, $wasteFactor% wasted\n";
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 515d80091de3..5af7c46e86da 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -252,7 +252,6 @@ void printVersion(const string & programName)
         std::cout << "Configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
         std::cout << "Store directory: " << settings.nixStore << "\n";
         std::cout << "State directory: " << settings.nixStateDir << "\n";
-        std::cout << "Database directory: " << settings.nixDBPath << "\n";
     }
     throw Exit();
 }
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 801ecd368a6b..e71ea6a57a34 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -254,7 +254,7 @@ struct BinaryCacheStoreAccessor : public FSAccessor
         std::string restPath = std::string(path, storePath.size());
 
         if (!store->isValidPath(storePath))
-            throw Error(format("path ‘%1%’ is not a valid store path") % storePath);
+            throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath);
 
         auto i = nars.find(storePath);
         if (i != nars.end()) return {i->second, restPath};
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 10ae574f9e49..cfab0b0dc32c 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2910,7 +2910,7 @@ Path DerivationGoal::openLogFile()
     string baseName = baseNameOf(drvPath);
 
     /* Create a log file. */
-    Path dir = (format("%1%/%2%/%3%/") % settings.nixLogDir % drvsLogDir % string(baseName, 0, 2)).str();
+    Path dir = (format("%1%/%2%/%3%/") % worker.store.logDir % drvsLogDir % string(baseName, 0, 2)).str();
     createDirs(dir);
 
     Path logFileName = (format("%1%/%2%%3%")
@@ -3213,7 +3213,7 @@ void SubstitutionGoal::tryNext()
     /* Bail out early if this substituter lacks a valid
        signature. LocalStore::addToStore() also checks for this, but
        only after we've downloaded the path. */
-    if (worker.store.requireSigs && !info->checkSignatures(worker.store.publicKeys)) {
+    if (worker.store.requireSigs && !info->checkSignatures(worker.store, worker.store.publicKeys)) {
         printMsg(lvlInfo, format("warning: substituter ‘%s’ does not have a valid signature for path ‘%s’")
             % sub->getUri() % storePath);
         tryNext();
diff --git a/src/libstore/download.cc b/src/libstore/download.cc
index cf3929cadd65..95c7d2255afc 100644
--- a/src/libstore/download.cc
+++ b/src/libstore/download.cc
@@ -8,6 +8,7 @@
 #include <curl/curl.h>
 
 #include <iostream>
+#include <thread>
 
 
 namespace nix {
@@ -194,9 +195,17 @@ struct CurlDownloader : public Downloader
         if (res != CURLE_OK) {
             Error err =
                 httpStatus == 404 ? NotFound :
-                httpStatus == 403 ? Forbidden : Misc;
-            throw DownloadError(err, format("unable to download ‘%1%’: %2% (%3%)")
-                % url % curl_easy_strerror(res) % res);
+                httpStatus == 403 ? Forbidden :
+                (httpStatus == 408 || httpStatus == 500 || httpStatus == 503
+                 || httpStatus == 504  || httpStatus == 522 || httpStatus == 524
+                 || res == CURLE_COULDNT_RESOLVE_HOST) ? Transient :
+                Misc;
+            if (res == CURLE_HTTP_RETURNED_ERROR && httpStatus != -1)
+                throw DownloadError(err, format("unable to download ‘%s’: HTTP error %d")
+                    % url % httpStatus);
+            else
+                throw DownloadError(err, format("unable to download ‘%s’: %s (%d)")
+                    % url % curl_easy_strerror(res) % res);
         }
 
         if (httpStatus == 304) return false;
@@ -206,14 +215,26 @@ struct CurlDownloader : public Downloader
 
     DownloadResult download(string url, const DownloadOptions & options) override
     {
-        DownloadResult res;
-        if (fetch(resolveUri(url), options)) {
-            res.cached = false;
-            res.data = data;
-        } else
-            res.cached = true;
-        res.etag = etag;
-        return res;
+        size_t attempt = 0;
+
+        while (true) {
+            try {
+                DownloadResult res;
+                if (fetch(resolveUri(url), options)) {
+                    res.cached = false;
+                    res.data = data;
+                } else
+                    res.cached = true;
+                res.etag = etag;
+                return res;
+            } catch (DownloadError & e) {
+                attempt++;
+                if (e.error != Transient || attempt >= options.tries) throw;
+                auto ms = 25 * (1 << (attempt - 1));
+                printMsg(lvlError, format("warning: %s; retrying in %d ms") % e.what() % ms);
+                std::this_thread::sleep_for(std::chrono::milliseconds(ms));
+            }
+        }
     }
 };
 
diff --git a/src/libstore/download.hh b/src/libstore/download.hh
index efddc55281fe..1f6098759a2d 100644
--- a/src/libstore/download.hh
+++ b/src/libstore/download.hh
@@ -9,10 +9,11 @@ namespace nix {
 
 struct DownloadOptions
 {
-    string expectedETag;
-    bool verifyTLS{true};
-    enum { yes, no, automatic } showProgress{yes};
-    bool head{false};
+    std::string expectedETag;
+    bool verifyTLS = true;
+    enum { yes, no, automatic } showProgress = yes;
+    bool head = false;
+    size_t tries = 1;
 };
 
 struct DownloadResult
@@ -31,7 +32,7 @@ struct Downloader
     Path downloadCached(ref<Store> store, const string & url, bool unpack,
         const Hash & expectedHash = Hash());
 
-    enum Error { NotFound, Forbidden, Misc };
+    enum Error { NotFound, Forbidden, Misc, Transient };
 };
 
 ref<Downloader> makeDownloader();
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index c12178e4028a..7bf48be378f8 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -69,7 +69,6 @@ void Settings::processEnvironment()
     nixDataDir = canonPath(getEnv("NIX_DATA_DIR", NIX_DATA_DIR));
     nixLogDir = canonPath(getEnv("NIX_LOG_DIR", NIX_LOG_DIR));
     nixStateDir = canonPath(getEnv("NIX_STATE_DIR", NIX_STATE_DIR));
-    nixDBPath = getEnv("NIX_DB_DIR", nixStateDir + "/db");
     nixConfDir = canonPath(getEnv("NIX_CONF_DIR", NIX_CONF_DIR));
     nixLibexecDir = canonPath(getEnv("NIX_LIBEXEC_DIR", NIX_LIBEXEC_DIR));
     nixBinDir = canonPath(getEnv("NIX_BIN_DIR", NIX_BIN_DIR));
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 65f763ace3c7..3194193bc842 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -51,9 +51,6 @@ struct Settings {
     /* The directory where state is stored. */
     Path nixStateDir;
 
-    /* The directory where we keep the SQLite database. */
-    Path nixDBPath;
-
     /* The directory where configuration files are stored. */
     Path nixConfDir;
 
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index da80b636c76c..42e9099b8e20 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -58,6 +58,7 @@ protected:
             DownloadOptions options;
             options.showProgress = DownloadOptions::no;
             options.head = true;
+            options.tries = 5;
             downloader->download(cacheUri + "/" + path, options);
             return true;
         } catch (DownloadError & e) {
@@ -79,6 +80,7 @@ protected:
         auto downloader(downloaders.get());
         DownloadOptions options;
         options.showProgress = DownloadOptions::no;
+        options.tries = 3;
         try {
             return downloader->download(cacheUri + "/" + path, options).data;
         } catch (DownloadError & e) {
diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc
index b1b9dc29e40d..4571a2211cd2 100644
--- a/src/libstore/local-fs-store.cc
+++ b/src/libstore/local-fs-store.cc
@@ -7,7 +7,9 @@ namespace nix {
 
 LocalFSStore::LocalFSStore(const Params & params)
     : Store(params)
-    , stateDir(get(params, "state", settings.nixStateDir))
+    , rootDir(get(params, "root"))
+    , stateDir(canonPath(get(params, "state", rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir)))
+    , logDir(canonPath(get(params, "log", rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir)))
 {
 }
 
@@ -21,7 +23,7 @@ struct LocalStoreAccessor : public FSAccessor
     {
         Path storePath = store->toStorePath(path);
         if (!store->isValidPath(storePath))
-            throw Error(format("path ‘%1%’ is not a valid store path") % storePath);
+            throw InvalidPath(format("path ‘%1%’ is not a valid store path") % storePath);
         return store->getRealStoreDir() + std::string(path, store->storeDir.size());
     }
 
@@ -79,7 +81,7 @@ void LocalFSStore::narFromPath(const Path & path, Sink & sink)
 {
     if (!isValidPath(path))
         throw Error(format("path ‘%s’ is not valid") % path);
-    dumpPath(path, sink);
+    dumpPath(getRealStoreDir() + std::string(path, storeDir.size()), sink);
 }
 
 }
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 96ce6a0d893b..d3f0c4787e17 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -38,8 +38,8 @@ namespace nix {
 
 LocalStore::LocalStore(const Params & params)
     : LocalFSStore(params)
-    , realStoreDir(get(params, "real", storeDir))
-    , dbDir(get(params, "state", "") != "" ? get(params, "state", "") + "/db" : settings.nixDBPath)
+    , realStoreDir(get(params, "real", rootDir != "" ? rootDir + "/nix/store" : storeDir))
+    , dbDir(stateDir + "/db")
     , linksDir(realStoreDir + "/.links")
     , reservedPath(dbDir + "/reserved")
     , schemaPath(dbDir + "/schema")
@@ -181,17 +181,20 @@ LocalStore::LocalStore(const Params & params)
 
         if (curSchema < 8) {
             SQLiteTxn txn(state->db);
-            if (sqlite3_exec(state->db, "alter table ValidPaths add column ultimate integer", 0, 0, 0) != SQLITE_OK)
-                throwSQLiteError(state->db, "upgrading database schema");
-            if (sqlite3_exec(state->db, "alter table ValidPaths add column sigs text", 0, 0, 0) != SQLITE_OK)
-                throwSQLiteError(state->db, "upgrading database schema");
+            state->db.exec("alter table ValidPaths add column ultimate integer");
+            state->db.exec("alter table ValidPaths add column sigs text");
             txn.commit();
         }
 
         if (curSchema < 9) {
             SQLiteTxn txn(state->db);
-            if (sqlite3_exec(state->db, "drop table FailedPaths", 0, 0, 0) != SQLITE_OK)
-                throwSQLiteError(state->db, "upgrading database schema");
+            state->db.exec("drop table FailedPaths");
+            txn.commit();
+        }
+
+        if (curSchema < 10) {
+            SQLiteTxn txn(state->db);
+            state->db.exec("alter table ValidPaths add column ca text");
             txn.commit();
         }
 
@@ -204,13 +207,13 @@ LocalStore::LocalStore(const Params & params)
 
     /* Prepare SQL statements. */
     state->stmtRegisterValidPath.create(state->db,
-        "insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate, sigs) values (?, ?, ?, ?, ?, ?, ?);");
+        "insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate, sigs, ca) values (?, ?, ?, ?, ?, ?, ?, ?);");
     state->stmtUpdatePathInfo.create(state->db,
-        "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ? where path = ?;");
+        "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ?, ca = ? where path = ?;");
     state->stmtAddReference.create(state->db,
         "insert or replace into Refs (referrer, reference) values (?, ?);");
     state->stmtQueryPathInfo.create(state->db,
-        "select id, hash, registrationTime, deriver, narSize, ultimate, sigs from ValidPaths where path = ?;");
+        "select id, hash, registrationTime, deriver, narSize, ultimate, sigs, ca from ValidPaths where path = ?;");
     state->stmtQueryReferences.create(state->db,
         "select path from Refs join ValidPaths on reference = id where referrer = ?;");
     state->stmtQueryReferrers.create(state->db,
@@ -279,8 +282,7 @@ void LocalStore::openDB(State & state, bool create)
     if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK)
         throwSQLiteError(db, "setting timeout");
 
-    if (sqlite3_exec(db, "pragma foreign_keys = 1;", 0, 0, 0) != SQLITE_OK)
-        throwSQLiteError(db, "enabling foreign keys");
+    db.exec("pragma foreign_keys = 1");
 
     /* !!! check whether sqlite has been built with foreign key
        support */
@@ -290,8 +292,7 @@ void LocalStore::openDB(State & state, bool create)
        all.  This can cause database corruption if the system
        crashes. */
     string syncMode = settings.fsyncMetadata ? "normal" : "off";
-    if (sqlite3_exec(db, ("pragma synchronous = " + syncMode + ";").c_str(), 0, 0, 0) != SQLITE_OK)
-        throwSQLiteError(db, "setting synchronous mode");
+    db.exec("pragma synchronous = " + syncMode);
 
     /* Set the SQLite journal mode.  WAL mode is fastest, so it's the
        default. */
@@ -319,8 +320,7 @@ void LocalStore::openDB(State & state, bool create)
         const char * schema =
 #include "schema.sql.hh"
             ;
-        if (sqlite3_exec(db, (const char *) schema, 0, 0, 0) != SQLITE_OK)
-            throwSQLiteError(db, "initialising database schema");
+        db.exec(schema);
     }
 }
 
@@ -527,6 +527,7 @@ uint64_t LocalStore::addValidPath(State & state,
         (info.narSize, info.narSize != 0)
         (info.ultimate ? 1 : 0, info.ultimate)
         (concatStringsSep(" ", info.sigs), !info.sigs.empty())
+        (info.ca, !info.ca.empty())
         .exec();
     uint64_t id = sqlite3_last_insert_rowid(state.db);
 
@@ -609,6 +610,9 @@ std::shared_ptr<ValidPathInfo> LocalStore::queryPathInfoUncached(const Path & pa
         s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 6);
         if (s) info->sigs = tokenizeString<StringSet>(s, " ");
 
+        s = (const char *) sqlite3_column_text(state->stmtQueryPathInfo, 7);
+        if (s) info->ca = s;
+
         /* Get the references. */
         auto useQueryReferences(state->stmtQueryReferences.use()(info->id));
 
@@ -628,6 +632,7 @@ void LocalStore::updatePathInfo(State & state, const ValidPathInfo & info)
         ("sha256:" + printHash(info.narHash))
         (info.ultimate ? 1 : 0, info.ultimate)
         (concatStringsSep(" ", info.sigs), !info.sigs.empty())
+        (info.ca, !info.ca.empty())
         (info.path)
         .exec();
 }
@@ -898,7 +903,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, const std::string & nar,
         throw Error(format("hash mismatch importing path ‘%s’; expected hash ‘%s’, got ‘%s’") %
             info.path % info.narHash.to_string() % h.to_string());
 
-    if (requireSigs && !dontCheckSigs && !info.checkSignatures(publicKeys))
+    if (requireSigs && !dontCheckSigs && !info.checkSignatures(*this, publicKeys))
         throw Error(format("cannot import path ‘%s’ because it lacks a valid signature") % info.path);
 
     addTempRoot(info.path);
@@ -983,6 +988,7 @@ Path LocalStore::addToStoreFromDump(const string & dump, const string & name,
             info.narHash = hash.first;
             info.narSize = hash.second;
             info.ultimate = true;
+            info.ca = "fixed:" + (recursive ? (std::string) "r:" : "") + h.to_string();
             registerValidPath(info);
         }
 
@@ -1014,7 +1020,8 @@ Path LocalStore::addToStore(const string & name, const Path & _srcPath,
 Path LocalStore::addTextToStore(const string & name, const string & s,
     const PathSet & references, bool repair)
 {
-    Path dstPath = computeStorePathForText(name, s, references);
+    auto hash = hashString(htSHA256, s);
+    auto dstPath = makeTextPath(name, hash, references);
 
     addTempRoot(dstPath);
 
@@ -1034,16 +1041,17 @@ Path LocalStore::addTextToStore(const string & name, const string & s,
 
             StringSink sink;
             dumpString(s, sink);
-            auto hash = hashString(htSHA256, *sink.s);
+            auto narHash = hashString(htSHA256, *sink.s);
 
             optimisePath(realPath);
 
             ValidPathInfo info;
             info.path = dstPath;
-            info.narHash = hash;
+            info.narHash = narHash;
             info.narSize = sink.s->size();
             info.references = references;
             info.ultimate = true;
+            info.ca = "text:" + hash.to_string();
             registerValidPath(info);
         }
 
@@ -1282,9 +1290,7 @@ void LocalStore::upgradeStore7()
 void LocalStore::vacuumDB()
 {
     auto state(_state.lock());
-
-    if (sqlite3_exec(state->db, "vacuum;", 0, 0, 0) != SQLITE_OK)
-        throwSQLiteError(state->db, "vacuuming SQLite database");
+    state->db.exec("vacuum");
 }
 
 
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 7bfc4ad34c3f..5b5960cf245f 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -17,8 +17,8 @@ namespace nix {
 /* Nix store and database schema version.  Version 1 (or 0) was Nix <=
    0.7.  Version 2 was Nix 0.8 and 0.9.  Version 3 is Nix 0.10.
    Version 4 is Nix 0.11.  Version 5 is Nix 0.12-0.16.  Version 6 is
-   Nix 1.0.  Version 7 is Nix 1.3. Version 9 is 1.12. */
-const int nixSchemaVersion = 9;
+   Nix 1.0.  Version 7 is Nix 1.3. Version 10 is 1.12. */
+const int nixSchemaVersion = 10;
 
 
 extern string drvsLogDir;
diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc
index 8896862be149..ded19c05d2cd 100644
--- a/src/libstore/nar-accessor.cc
+++ b/src/libstore/nar-accessor.cc
@@ -27,7 +27,7 @@ struct NarIndexer : ParseSink, StringSource
 
     Path currentPath;
     std::string currentStart;
-    bool isExec;
+    bool isExec = false;
 
     NarIndexer(const std::string & nar) : StringSource(nar)
     {
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index 172a918ff453..d28ff42c7f23 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -78,21 +78,16 @@ public:
         Path dbPath = getCacheDir() + "/nix/binary-cache-v5.sqlite";
         createDirs(dirOf(dbPath));
 
-        if (sqlite3_open_v2(dbPath.c_str(), &state->db.db,
-                SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0) != SQLITE_OK)
-            throw Error(format("cannot open store cache ‘%s’") % dbPath);
+        state->db = SQLite(dbPath);
 
         if (sqlite3_busy_timeout(state->db, 60 * 60 * 1000) != SQLITE_OK)
             throwSQLiteError(state->db, "setting timeout");
 
         // We can always reproduce the cache.
-        if (sqlite3_exec(state->db, "pragma synchronous = off", 0, 0, 0) != SQLITE_OK)
-            throwSQLiteError(state->db, "making database asynchronous");
-        if (sqlite3_exec(state->db, "pragma main.journal_mode = truncate", 0, 0, 0) != SQLITE_OK)
-            throwSQLiteError(state->db, "setting journal mode");
+        state->db.exec("pragma synchronous = off");
+        state->db.exec("pragma main.journal_mode = truncate");
 
-        if (sqlite3_exec(state->db, schema, 0, 0, 0) != SQLITE_OK)
-            throwSQLiteError(state->db, "initialising database schema");
+        state->db.exec(schema);
 
         state->insertCache.create(state->db,
             "insert or replace into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)");
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index b0a8d77c2fba..201cac671a55 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -67,6 +67,10 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
             system = value;
         else if (name == "Sig")
             sigs.insert(value);
+        else if (name == "CA") {
+            if (!ca.empty()) corrupt();
+            ca = value;
+        }
 
         pos = eol + 1;
     }
@@ -101,6 +105,9 @@ std::string NarInfo::to_string() const
     for (auto sig : sigs)
         res += "Sig: " + sig + "\n";
 
+    if (!ca.empty())
+        res += "CA: " + ca + "\n";
+
     return res;
 }
 
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index ab05c3844289..94075f3b9b39 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -94,6 +94,8 @@ ref<RemoteStore::Connection> RemoteStore::openConnection()
         conn->daemonVersion = readInt(conn->from);
         if (GET_PROTOCOL_MAJOR(conn->daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
             throw Error("Nix daemon protocol version not supported");
+        if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 10)
+            throw Error("the Nix daemon version is too old");
         conn->to << PROTOCOL_VERSION;
 
         if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 14) {
@@ -127,17 +129,13 @@ void RemoteStore::setOptions(ref<Connection> conn)
        << settings.tryFallback
        << verbosity
        << settings.maxBuildJobs
-       << settings.maxSilentTime;
-    if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 2)
-        conn->to << settings.useBuildHook;
-    if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 4)
-        conn->to << (settings.verboseBuild ? lvlError : lvlVomit)
-                 << 0 // obsolete log type
-                 << 0 /* obsolete print build trace */;
-    if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 6)
-        conn->to << settings.buildCores;
-    if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 10)
-        conn->to << settings.useSubstitutes;
+       << settings.maxSilentTime
+       << settings.useBuildHook
+       << (settings.verboseBuild ? lvlError : lvlVomit)
+       << 0 // obsolete log type
+       << 0 /* obsolete print build trace */
+       << settings.buildCores
+       << settings.useSubstitutes;
 
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 12) {
         Settings::SettingsMap overrides = settings.getOverrides();
@@ -213,8 +211,6 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
 
     auto conn(connections->get());
 
-    if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 3) return;
-
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) {
 
         for (auto & i : paths) {
@@ -227,7 +223,7 @@ void RemoteStore::querySubstitutablePathInfos(const PathSet & paths,
             if (info.deriver != "") assertStorePath(info.deriver);
             info.references = readStorePaths<PathSet>(*this, conn->from);
             info.downloadSize = readLongLong(conn->from);
-            info.narSize = GET_PROTOCOL_MINOR(conn->daemonVersion) >= 7 ? readLongLong(conn->from) : 0;
+            info.narSize = readLongLong(conn->from);
             infos[i] = info;
         }
 
@@ -277,6 +273,7 @@ std::shared_ptr<ValidPathInfo> RemoteStore::queryPathInfoUncached(const Path & p
     if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 16) {
         info->ultimate = readInt(conn->from) != 0;
         info->sigs = readStrings<StringSet>(conn->from);
+        info->ca = readString(conn->from);
     }
     return info;
 }
@@ -481,11 +478,11 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
 {
     auto conn(connections->get());
 
-    conn->to << wopCollectGarbage << options.action << options.pathsToDelete << options.ignoreLiveness
-       << options.maxFreed << 0;
-    if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 5)
+    conn->to
+        << wopCollectGarbage << options.action << options.pathsToDelete << options.ignoreLiveness
+        << options.maxFreed
         /* removed options */
-        conn->to << 0 << 0;
+        << 0 << 0 << 0;
 
     conn->processStderr();
 
@@ -562,7 +559,7 @@ void RemoteStore::Connection::processStderr(Sink * sink, Source * source)
     }
     if (msg == STDERR_ERROR) {
         string error = readString(from);
-        unsigned int status = GET_PROTOCOL_MINOR(daemonVersion) >= 8 ? readInt(from) : 1;
+        unsigned int status = readInt(from);
         throw Error(format("%1%") % error, status);
     }
     else if (msg != STDERR_LAST)
diff --git a/src/libstore/schema.sql b/src/libstore/schema.sql
index 91878af1580d..09c71a2b8dd7 100644
--- a/src/libstore/schema.sql
+++ b/src/libstore/schema.sql
@@ -6,7 +6,8 @@ create table if not exists ValidPaths (
     deriver          text,
     narSize          integer,
     ultimate         integer, -- null implies "false"
-    sigs             text -- space-separated
+    sigs             text, -- space-separated
+    ca               text -- if not null, an assertion that the path is content-addressed; see ValidPathInfo
 );
 
 create table if not exists Refs (
diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc
index 816f9984d6eb..ea0b843f5752 100644
--- a/src/libstore/sqlite.cc
+++ b/src/libstore/sqlite.cc
@@ -35,6 +35,13 @@ namespace nix {
         throw SQLiteError(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
 }
 
+SQLite::SQLite(const Path & path)
+{
+    if (sqlite3_open_v2(path.c_str(), &db,
+            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0) != SQLITE_OK)
+        throw Error(format("cannot open SQLite database ‘%s’") % path);
+}
+
 SQLite::~SQLite()
 {
     try {
@@ -45,6 +52,12 @@ SQLite::~SQLite()
     }
 }
 
+void SQLite::exec(const std::string & stmt)
+{
+    if (sqlite3_exec(db, stmt.c_str(), 0, 0, 0) != SQLITE_OK)
+        throwSQLiteError(db, format("executing SQLite statement ‘%s’") % stmt);
+}
+
 void SQLiteStmt::create(sqlite3 * db, const string & s)
 {
     checkInterrupt();
diff --git a/src/libstore/sqlite.hh b/src/libstore/sqlite.hh
index d6b4a8d9117b..7c1ed538215c 100644
--- a/src/libstore/sqlite.hh
+++ b/src/libstore/sqlite.hh
@@ -13,10 +13,16 @@ namespace nix {
 /* RAII wrapper to close a SQLite database automatically. */
 struct SQLite
 {
-    sqlite3 * db;
-    SQLite() { db = 0; }
+    sqlite3 * db = 0;
+    SQLite() { }
+    SQLite(const Path & path);
+    SQLite(const SQLite & from) = delete;
+    SQLite& operator = (const SQLite & from) = delete;
+    SQLite& operator = (SQLite && from) { db = from.db; from.db = 0; return *this; }
     ~SQLite();
     operator sqlite3 * () { return db; }
+
+    void exec(const std::string & stmt);
 };
 
 /* RAII wrapper to create and destroy SQLite prepared statements. */
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index af002dcc8c33..5dd56f905d57 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -202,6 +202,22 @@ Path Store::makeFixedOutputPath(bool recursive,
 }
 
 
+Path Store::makeTextPath(const string & name, const Hash & hash,
+    const PathSet & references) const
+{
+    assert(hash.type == htSHA256);
+    /* Stuff the references (if any) into the type.  This is a bit
+       hacky, but we can't put them in `s' since that would be
+       ambiguous. */
+    string type = "text";
+    for (auto & i : references) {
+        type += ":";
+        type += i;
+    }
+    return makeStorePath(type, hash, name);
+}
+
+
 std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath,
     bool recursive, HashType hashAlgo, PathFilter & filter) const
 {
@@ -215,16 +231,7 @@ std::pair<Path, Hash> Store::computeStorePathForPath(const Path & srcPath,
 Path Store::computeStorePathForText(const string & name, const string & s,
     const PathSet & references) const
 {
-    Hash hash = hashString(htSHA256, s);
-    /* Stuff the references (if any) into the type.  This is a bit
-       hacky, but we can't put them in `s' since that would be
-       ambiguous. */
-    string type = "text";
-    for (auto & i : references) {
-        type += ":";
-        type += i;
-    }
-    return makeStorePath(type, hash, name);
+    return makeTextPath(name, hashString(htSHA256, s), references);
 }
 
 
@@ -432,9 +439,38 @@ void ValidPathInfo::sign(const SecretKey & secretKey)
 }
 
 
-unsigned int ValidPathInfo::checkSignatures(const PublicKeys & publicKeys) const
+bool ValidPathInfo::isContentAddressed(const Store & store) const
+{
+    auto warn = [&]() {
+        printMsg(lvlError, format("warning: path ‘%s’ claims to be content-addressed but isn't") % path);
+    };
+
+    if (hasPrefix(ca, "text:")) {
+        auto hash = parseHash(std::string(ca, 5));
+        if (store.makeTextPath(storePathToName(path), hash, references) == path)
+            return true;
+        else
+            warn();
+    }
+
+    else if (hasPrefix(ca, "fixed:")) {
+        bool recursive = ca.compare(6, 2, "r:") == 0;
+        auto hash = parseHash(std::string(ca, recursive ? 8 : 6));
+        if (store.makeFixedOutputPath(recursive, hash, storePathToName(path)) == path)
+            return true;
+        else
+            warn();
+    }
+
+    return false;
+}
+
+
+size_t ValidPathInfo::checkSignatures(const Store & store, const PublicKeys & publicKeys) const
 {
-    unsigned int good = 0;
+    if (isContentAddressed(store)) return maxSigs;
+
+    size_t good = 0;
     for (auto & sig : sigs)
         if (checkSignature(publicKeys, sig))
             good++;
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 0b80312d6307..41fc58fc48e2 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -16,6 +16,13 @@
 namespace nix {
 
 
+struct BasicDerivation;
+struct Derivation;
+class FSAccessor;
+class NarInfoDiskCache;
+class Store;
+
+
 /* Size of the hash part of store paths, in base-32 characters. */
 const size_t storePathHashLen = 32; // i.e. 160 bits
 
@@ -109,6 +116,34 @@ struct ValidPathInfo
 
     StringSet sigs; // note: not necessarily verified
 
+    /* If non-empty, an assertion that the path is content-addressed,
+       i.e., that the store path is computed from a cryptographic hash
+       of the contents of the path, plus some other bits of data like
+       the "name" part of the path. Such a path doesn't need
+       signatures, since we don't have to trust anybody's claim that
+       the path is the output of a particular derivation. (In the
+       extensional store model, we have to trust that the *contents*
+       of an output path of a derivation were actually produced by
+       that derivation. In the intensional model, we have to trust
+       that a particular output path was produced by a derivation; the
+       path name then implies the contents.)
+
+       Ideally, the content-addressability assertion would just be a
+       Boolean, and the store path would be computed from
+       ‘storePathToName(path)’, ‘narHash’ and ‘references’. However,
+       1) we've accumulated several types of content-addressed paths
+       over the years; and 2) fixed-output derivations support
+       multiple hash algorithms and serialisation methods (flat file
+       vs NAR). Thus, ‘ca’ has one of the following forms:
+
+       * ‘text:sha256:<sha256 hash of file contents>’: For paths
+         computed by makeTextPath() / addTextToStore().
+
+       * ‘fixed:<r?>:<ht>:<h>’: For paths computed by
+         makeFixedOutputPath() / addToStore().
+    */
+    std::string ca;
+
     bool operator == (const ValidPathInfo & i) const
     {
         return
@@ -117,19 +152,25 @@ struct ValidPathInfo
             && references == i.references;
     }
 
-    /*  Return a fingerprint of the store path to be used in binary
-        cache signatures. It contains the store path, the base-32
-        SHA-256 hash of the NAR serialisation of the path, the size of
-        the NAR, and the sorted references. The size field is strictly
-        speaking superfluous, but might prevent endless/excessive data
-        attacks. */
+    /* Return a fingerprint of the store path to be used in binary
+       cache signatures. It contains the store path, the base-32
+       SHA-256 hash of the NAR serialisation of the path, the size of
+       the NAR, and the sorted references. The size field is strictly
+       speaking superfluous, but might prevent endless/excessive data
+       attacks. */
     std::string fingerprint() const;
 
     void sign(const SecretKey & secretKey);
 
+    /* Return true iff the path is verifiably content-addressed. */
+    bool isContentAddressed(const Store & store) const;
+
+    static const size_t maxSigs = std::numeric_limits<size_t>::max();
+
     /* Return the number of signatures on this .narinfo that were
-       produced by one of the specified keys. */
-    unsigned int checkSignatures(const PublicKeys & publicKeys) const;
+       produced by one of the specified keys, or maxSigs if the path
+       is content-addressed. */
+    size_t checkSignatures(const Store & store, const PublicKeys & publicKeys) const;
 
     /* Verify a single signature. */
     bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
@@ -169,12 +210,6 @@ struct BuildResult
 };
 
 
-struct BasicDerivation;
-struct Derivation;
-class FSAccessor;
-class NarInfoDiskCache;
-
-
 class Store : public std::enable_shared_from_this<Store>
 {
 public:
@@ -234,10 +269,12 @@ public:
     Path makeFixedOutputPath(bool recursive,
         const Hash & hash, const string & name) const;
 
-    /* This is the preparatory part of addToStore() and
-       addToStoreFixed(); it computes the store path to which srcPath
-       is to be copied.  Returns the store path and the cryptographic
-       hash of the contents of srcPath. */
+    Path makeTextPath(const string & name, const Hash & hash,
+        const PathSet & references) const;
+
+    /* This is the preparatory part of addToStore(); it computes the
+       store path to which srcPath is to be copied.  Returns the store
+       path and the cryptographic hash of the contents of srcPath. */
     std::pair<Path, Hash> computeStorePathForPath(const Path & srcPath,
         bool recursive = true, HashType hashAlgo = htSHA256,
         PathFilter & filter = defaultPathFilter) const;
@@ -491,7 +528,9 @@ protected:
 class LocalFSStore : public Store
 {
 public:
+    const Path rootDir;
     const Path stateDir;
+    const Path logDir;
 
     LocalFSStore(const Params & params);
 
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index 6e0d869f4c87..f2b59c84a858 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -413,12 +413,10 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
         options.pathsToDelete = readStorePaths<PathSet>(*store, from);
         options.ignoreLiveness = readInt(from);
         options.maxFreed = readLongLong(from);
-        readInt(from); // obsolete field
-        if (GET_PROTOCOL_MINOR(clientVersion) >= 5) {
-            /* removed options */
-            readInt(from);
-            readInt(from);
-        }
+        // obsolete fields
+        readInt(from);
+        readInt(from);
+        readInt(from);
 
         GCResults results;
 
@@ -440,17 +438,12 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
         verbosity = (Verbosity) readInt(from);
         settings.set("build-max-jobs", std::to_string(readInt(from)));
         settings.set("build-max-silent-time", std::to_string(readInt(from)));
-        if (GET_PROTOCOL_MINOR(clientVersion) >= 2)
-            settings.useBuildHook = readInt(from) != 0;
-        if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
-            settings.verboseBuild = lvlError == (Verbosity) readInt(from);
-            readInt(from); // obsolete logType
-            readInt(from); // obsolete printBuildTrace
-        }
-        if (GET_PROTOCOL_MINOR(clientVersion) >= 6)
-            settings.set("build-cores", std::to_string(readInt(from)));
-        if (GET_PROTOCOL_MINOR(clientVersion) >= 10)
-            settings.set("build-use-substitutes", readInt(from) ? "true" : "false");
+        settings.useBuildHook = readInt(from) != 0;
+        settings.verboseBuild = lvlError == (Verbosity) readInt(from);
+        readInt(from); // obsolete logType
+        readInt(from); // obsolete printBuildTrace
+        settings.set("build-cores", std::to_string(readInt(from)));
+        settings.set("build-use-substitutes", readInt(from) ? "true" : "false");
         if (GET_PROTOCOL_MINOR(clientVersion) >= 12) {
             unsigned int n = readInt(from);
             for (unsigned int i = 0; i < n; i++) {
@@ -478,9 +471,7 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
         if (i == infos.end())
             to << 0;
         else {
-            to << 1 << i->second.deriver << i->second.references << i->second.downloadSize;
-            if (GET_PROTOCOL_MINOR(clientVersion) >= 7)
-                to << i->second.narSize;
+            to << 1 << i->second.deriver << i->second.references << i->second.downloadSize << i->second.narSize;
         }
         break;
     }
@@ -524,7 +515,8 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
                << info->registrationTime << info->narSize;
             if (GET_PROTOCOL_MINOR(clientVersion) >= 16) {
                 to << info->ultimate
-                   << info->sigs;
+                   << info->sigs
+                   << info->ca;
             }
         } else {
             assert(GET_PROTOCOL_MINOR(clientVersion) >= 17);
@@ -585,11 +577,13 @@ static void processConnection(bool trusted)
     to.flush();
     unsigned int clientVersion = readInt(from);
 
+    if (clientVersion < 0x10a)
+        throw Error("the Nix client version is too old");
+
     if (GET_PROTOCOL_MINOR(clientVersion) >= 14 && readInt(from))
         setAffinityTo(readInt(from));
 
-    if (GET_PROTOCOL_MINOR(clientVersion) >= 11)
-        readInt(from); // obsolete reserveSpace
+    readInt(from); // obsolete reserveSpace
 
     /* Send startup error messages to the client. */
     startWork();
@@ -636,10 +630,10 @@ static void processConnection(bool trusted)
                    during addTextToStore() / importPath().  If that
                    happens, just send the error message and exit. */
                 bool errorAllowed = canSendStderr;
-                stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? e.status : 0);
+                stopWork(false, e.msg(), e.status);
                 if (!errorAllowed) throw;
             } catch (std::bad_alloc & e) {
-                stopWork(false, "Nix daemon out of memory", GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
+                stopWork(false, "Nix daemon out of memory", 1);
                 throw;
             }
 
@@ -653,7 +647,7 @@ static void processConnection(bool trusted)
         printMsg(lvlDebug, format("%1% operations") % opCount);
 
     } catch (Error & e) {
-        stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
+        stopWork(false, e.msg(), 1);
         to.flush();
         return;
     }
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index 8532101a174d..e8b56f929b13 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -483,6 +483,10 @@ static void opReadLog(Strings opFlags, Strings opArgs)
 
     RunPager pager;
 
+    // FIXME: move getting logs into Store.
+    auto store2 = std::dynamic_pointer_cast<LocalFSStore>(store);
+    if (!store2) throw Error(format("store ‘%s’ does not support reading logs") % store->getUri());
+
     for (auto & i : opArgs) {
         Path path = useDeriver(store->followLinksToStorePath(i));
 
@@ -493,8 +497,8 @@ static void opReadLog(Strings opFlags, Strings opArgs)
 
             Path logPath =
                 j == 0
-                ? (format("%1%/%2%/%3%/%4%") % settings.nixLogDir % drvsLogDir % string(baseName, 0, 2) % string(baseName, 2)).str()
-                : (format("%1%/%2%/%3%") % settings.nixLogDir % drvsLogDir % baseName).str();
+                ? (format("%1%/%2%/%3%/%4%") % store2->logDir % drvsLogDir % string(baseName, 0, 2) % string(baseName, 2)).str()
+                : (format("%1%/%2%/%3%") % store2->logDir % drvsLogDir % baseName).str();
             Path logBz2Path = logPath + ".bz2";
 
             if (pathExists(logPath)) {
diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc
index c61fe7ff1e00..dca22240b1cb 100644
--- a/src/nix/path-info.cc
+++ b/src/nix/path-info.cc
@@ -73,6 +73,7 @@ struct CmdPathInfo : StorePathsCommand
                 std::cout << '\t';
                 Strings ss;
                 if (info->ultimate) ss.push_back("ultimate");
+                if (info->ca != "") ss.push_back("ca:" + info->ca);
                 for (auto & sig : info->sigs) ss.push_back(sig);
                 std::cout << concatStringsSep(" ", ss);
             }
diff --git a/src/nix/verify.cc b/src/nix/verify.cc
index fd904f465687..f2b6acdfbf0b 100644
--- a/src/nix/verify.cc
+++ b/src/nix/verify.cc
@@ -116,12 +116,16 @@ struct CmdVerify : StorePathsCommand
                             }
                         };
 
+                        if (info->isContentAddressed(*store)) validSigs = ValidPathInfo::maxSigs;
+
                         doSigs(info->sigs);
 
                         for (auto & store2 : substituters) {
                             if (validSigs >= actualSigsNeeded) break;
                             try {
-                                doSigs(store2->queryPathInfo(info->path)->sigs);
+                                auto info2 = store2->queryPathInfo(info->path);
+                                if (info2->isContentAddressed(*store)) validSigs = ValidPathInfo::maxSigs;
+                                doSigs(info2->sigs);
                             } catch (InvalidPath &) {
                             } catch (Error & e) {
                                 printMsg(lvlError, format(ANSI_RED "error:" ANSI_NORMAL " %s") % e.what());
diff --git a/tests/binary-cache.sh b/tests/binary-cache.sh
index 96cab6ad4269..4ce428f643e5 100644
--- a/tests/binary-cache.sh
+++ b/tests/binary-cache.sh
@@ -6,7 +6,7 @@ clearCache
 # Create the binary cache.
 outPath=$(nix-build dependencies.nix --no-out-link)
 
-nix-push --dest $cacheDir $outPath
+nix copy --recursive --to file://$cacheDir $outPath
 
 
 basicTests() {
@@ -58,7 +58,7 @@ unset _NIX_FORCE_HTTP_BINARY_CACHE_STORE
 # Test whether Nix notices if the NAR doesn't match the hash in the NAR info.
 clearStore
 
-nar=$(ls $cacheDir/*.nar.xz | head -n1)
+nar=$(ls $cacheDir/nar/*.nar.xz | head -n1)
 mv $nar $nar.good
 mkdir -p $TEST_ROOT/empty
 nix-store --dump $TEST_ROOT/empty | xz > $nar
@@ -117,7 +117,7 @@ badKey="$(cat $TEST_ROOT/pk2)"
 res=($(nix-store --generate-binary-cache-key foo.nixos.org-1 $TEST_ROOT/sk3 $TEST_ROOT/pk3))
 otherKey="$(cat $TEST_ROOT/pk3)"
 
-nix-push --dest $cacheDir --key-file $TEST_ROOT/sk1 $outPath
+nix copy --recursive --to file://$cacheDir?secret-key=$TEST_ROOT/sk1 $outPath
 
 
 # Downloading should fail if we don't provide a key.
diff --git a/tests/common.sh.in b/tests/common.sh.in
index 097d94bb1eea..316d5f6896bb 100644
--- a/tests/common.sh.in
+++ b/tests/common.sh.in
@@ -12,7 +12,6 @@ fi
 export NIX_LOCALSTATE_DIR=$TEST_ROOT/var
 export NIX_LOG_DIR=$TEST_ROOT/var/log/nix
 export NIX_STATE_DIR=$TEST_ROOT/var/nix
-export NIX_DB_DIR=$TEST_ROOT/db
 export NIX_CONF_DIR=$TEST_ROOT/etc
 export NIX_MANIFESTS_DIR=$TEST_ROOT/var/nix/manifests
 export _NIX_TEST_SHARED=$TEST_ROOT/shared
@@ -51,12 +50,10 @@ clearStore() {
     chmod -R +w "$NIX_STORE_DIR"
     rm -rf "$NIX_STORE_DIR"
     mkdir "$NIX_STORE_DIR"
-    rm -rf "$NIX_DB_DIR"
-    mkdir "$NIX_DB_DIR"
+    rm -rf "$NIX_STATE_DIR"
+    mkdir "$NIX_STATE_DIR"
     nix-store --init
     clearProfiles
-    rm -f "$NIX_STATE_DIR"/gcroots/auto/*
-    rm -f "$NIX_STATE_DIR"/gcroots/ref
 }
 
 clearCache() {
diff --git a/tests/dump-db.sh b/tests/dump-db.sh
index 57c8c401600d..d6eea42aa04e 100644
--- a/tests/dump-db.sh
+++ b/tests/dump-db.sh
@@ -8,8 +8,7 @@ deps="$(nix-store -qR $TEST_ROOT/result)"
 
 nix-store --dump-db > $TEST_ROOT/dump
 
-rm -rf $NIX_DB_DIR
-mkdir $NIX_DB_DIR
+rm -rf $NIX_STATE_DIR/db
 
 nix-store --load-db < $TEST_ROOT/dump
 
diff --git a/tests/init.sh b/tests/init.sh
index 5be999e4b1be..4571b75b859e 100644
--- a/tests/init.sh
+++ b/tests/init.sh
@@ -1,7 +1,5 @@
 source common.sh
 
-echo "NIX_STORE_DIR=$NIX_STORE_DIR NIX_DB_DIR=$NIX_DB_DIR"
-
 test -n "$TEST_ROOT"
 if test -d "$TEST_ROOT"; then
     chmod -R u+w "$TEST_ROOT"
@@ -13,7 +11,6 @@ mkdir "$NIX_STORE_DIR"
 mkdir "$NIX_LOCALSTATE_DIR"
 mkdir -p "$NIX_LOG_DIR"/drvs
 mkdir "$NIX_STATE_DIR"
-mkdir "$NIX_DB_DIR"
 mkdir "$NIX_CONF_DIR"
 
 cat > "$NIX_CONF_DIR"/nix.conf <<EOF
@@ -28,6 +25,6 @@ EOF
 nix-store --init
 
 # Did anything happen?
-test -e "$NIX_DB_DIR"/db.sqlite
+test -e "$NIX_STATE_DIR"/db/db.sqlite
 
 echo 'Hello World' > ./dummy
diff --git a/tests/install-package.sh b/tests/install-package.sh
deleted file mode 100644
index 1916f72713e2..000000000000
--- a/tests/install-package.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-source common.sh
-
-drvPath=$(nix-instantiate ./dependencies.nix)
-outPath=$(nix-store -r $drvPath)
-nix-push --dest $cacheDir $outPath
-
-clearStore
-clearProfiles
-
-cat > $TEST_ROOT/foo.nixpkg <<EOF
-NIXPKG1 - simple $system $drvPath $outPath file://$cacheDir
-EOF
-
-nix-install-package --non-interactive -p $profiles/test $TEST_ROOT/foo.nixpkg
-test "$(nix-env -p $profiles/test -q '*' | wc -l)" -eq 1
-
-clearProfiles
-
-nix-install-package --non-interactive -p $profiles/test --url file://$TEST_ROOT/foo.nixpkg
-test "$(nix-env -p $profiles/test -q '*' | wc -l)" -eq 1
diff --git a/tests/local.mk b/tests/local.mk
index 7c5a553d39e0..1e5439f061e2 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -3,9 +3,9 @@ check:
 
 nix_tests = \
   init.sh hash.sh lang.sh add.sh simple.sh dependencies.sh \
-  build-hook.sh nix-push.sh gc.sh gc-concurrent.sh \
+  build-hook.sh gc.sh gc-concurrent.sh \
   referrers.sh user-envs.sh logging.sh nix-build.sh misc.sh fixed.sh \
-  gc-runtime.sh install-package.sh check-refs.sh filter-source.sh \
+  gc-runtime.sh check-refs.sh filter-source.sh \
   remote-store.sh export.sh export-graph.sh \
   timeout.sh secure-drv-outputs.sh nix-channel.sh \
   multiple-outputs.sh import-derivation.sh fetchurl.sh optimise-store.sh \
diff --git a/tests/nix-channel.sh b/tests/nix-channel.sh
index 2ec986dd415b..553ada51d9f7 100644
--- a/tests/nix-channel.sh
+++ b/tests/nix-channel.sh
@@ -15,7 +15,7 @@ nix-channel --remove xyzzy
 # Create a channel.
 rm -rf $TEST_ROOT/foo
 mkdir -p $TEST_ROOT/foo
-nix-push --dest $TEST_ROOT/foo --manifest --bzip2 $(nix-store -r $(nix-instantiate dependencies.nix))
+nix copy --recursive --to file://$TEST_ROOT/foo?compression="bzip2" $(nix-store -r $(nix-instantiate dependencies.nix))
 rm -rf $TEST_ROOT/nixexprs
 mkdir -p $TEST_ROOT/nixexprs
 cp config.nix dependencies.nix dependencies.builder*.sh $TEST_ROOT/nixexprs/
diff --git a/tests/nix-push.sh b/tests/nix-push.sh
deleted file mode 100644
index 8ea59516c62c..000000000000
--- a/tests/nix-push.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-source common.sh
-
-clearStore
-
-drvPath=$(nix-instantiate dependencies.nix)
-outPath=$(nix-store -r $drvPath)
-
-echo "pushing $drvPath"
-
-mkdir -p $TEST_ROOT/cache
-
-nix-push --dest $TEST_ROOT/cache --manifest $drvPath --bzip2
diff --git a/tests/referrers.sh b/tests/referrers.sh
index 5c1ef20cfeb4..8ab8e5ddfe87 100644
--- a/tests/referrers.sh
+++ b/tests/referrers.sh
@@ -30,7 +30,7 @@ echo "collecting garbage..."
 ln -sfn $reference "$NIX_STATE_DIR"/gcroots/ref
 nix-store --gc
 
-if [ -n "$(type -p sqlite3)" -a "$(sqlite3 $NIX_DB_DIR/db.sqlite 'select count(*) from Refs')" -ne 0 ]; then
+if [ -n "$(type -p sqlite3)" -a "$(sqlite3 $NIX_STATE_DIR/db/db.sqlite 'select count(*) from Refs')" -ne 0 ]; then
     echo "referrers not cleaned up"
     exit 1
 fi
diff --git a/tests/remote-store.sh b/tests/remote-store.sh
index b3908717a40e..f2f2806d022d 100644
--- a/tests/remote-store.sh
+++ b/tests/remote-store.sh
@@ -4,7 +4,7 @@ clearStore
 
 startDaemon
 
-$SHELL ./user-envs.sh
+storeCleared=1 $SHELL ./user-envs.sh
 
 nix-store --dump-db > $TEST_ROOT/d1
 NIX_REMOTE= nix-store --dump-db > $TEST_ROOT/d2
diff --git a/tests/repair.sh b/tests/repair.sh
index 92f2f8fe60a5..782838704da7 100644
--- a/tests/repair.sh
+++ b/tests/repair.sh
@@ -46,7 +46,7 @@ fi
 # --verify can fix it.
 clearCache
 
-nix-push --dest $cacheDir $path
+nix copy --recursive --to file://$cacheDir $path
 
 chmod u+w $path2
 rm -rf $path2
diff --git a/tests/user-envs.sh b/tests/user-envs.sh
index 526c1267cefe..c4192fdc59b2 100644
--- a/tests/user-envs.sh
+++ b/tests/user-envs.sh
@@ -1,6 +1,9 @@
 source common.sh
 
-clearStore
+if [ -z "$storeCleared" ]; then
+    clearStore
+fi
+
 clearProfiles
 
 # Query installed: should be empty.