about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/administration/container-networking.xml8
-rw-r--r--nixos/doc/manual/development/development.xml1
-rw-r--r--nixos/doc/manual/development/reviewing-contributions.xml393
-rw-r--r--nixos/doc/manual/release-notes/rl-1703.xml9
-rw-r--r--nixos/lib/make-squashfs.nix2
-rwxr-xr-xnixos/maintainers/scripts/ec2/create-amis.sh10
-rw-r--r--nixos/modules/config/fonts/fontconfig.nix12
-rw-r--r--nixos/modules/config/i18n.nix1
-rw-r--r--nixos/modules/hardware/video/bumblebee.nix93
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix96
-rw-r--r--nixos/modules/misc/ids.nix6
-rw-r--r--nixos/modules/module-list.nix4
-rw-r--r--nixos/modules/profiles/base.nix4
-rw-r--r--nixos/modules/profiles/minimal.nix2
-rw-r--r--nixos/modules/programs/java.nix1
-rw-r--r--nixos/modules/programs/ssh.nix2
-rw-r--r--nixos/modules/rename.nix8
-rw-r--r--nixos/modules/security/duosec.nix12
-rw-r--r--nixos/modules/security/grsecurity.nix33
-rw-r--r--nixos/modules/security/grsecurity.xml8
-rw-r--r--nixos/modules/services/backup/crashplan.nix2
-rw-r--r--nixos/modules/services/backup/tarsnap.nix156
-rw-r--r--nixos/modules/services/computing/boinc/client.nix88
-rw-r--r--nixos/modules/services/continuous-integration/gocd-agent/default.nix1
-rw-r--r--nixos/modules/services/continuous-integration/gocd-server/default.nix1
-rw-r--r--nixos/modules/services/databases/riak-cs.nix202
-rw-r--r--nixos/modules/services/databases/riak.nix14
-rw-r--r--nixos/modules/services/databases/stanchion.nix212
-rw-r--r--nixos/modules/services/hardware/sane.nix111
-rw-r--r--nixos/modules/services/misc/dictd.nix3
-rw-r--r--nixos/modules/services/misc/disnix.nix1
-rw-r--r--nixos/modules/services/misc/gitlab.nix3
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix4
-rw-r--r--nixos/modules/services/misc/parsoid.nix37
-rw-r--r--nixos/modules/services/monitoring/collectd.nix2
-rw-r--r--nixos/modules/services/network-filesystems/tahoe.nix52
-rw-r--r--nixos/modules/services/networking/cjdns.nix51
-rw-r--r--nixos/modules/services/networking/dante.nix61
-rw-r--r--nixos/modules/services/networking/flannel.nix1
-rw-r--r--nixos/modules/services/networking/hostapd.nix5
-rw-r--r--nixos/modules/services/networking/nntp-proxy.nix4
-rw-r--r--nixos/modules/services/networking/nsd.nix4
-rw-r--r--nixos/modules/services/networking/quassel.nix3
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix2
-rw-r--r--nixos/modules/services/search/hound.nix2
-rw-r--r--nixos/modules/services/security/clamav.nix95
-rw-r--r--nixos/modules/services/torrent/opentracker.nix1
-rw-r--r--nixos/modules/services/web-apps/quassel-webserver.nix2
-rw-r--r--nixos/modules/services/x11/compton.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix24
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix8
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm-unstable.nix48
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm.nix83
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix1
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix50
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix2
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix12
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl17
-rw-r--r--nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix7
-rw-r--r--nixos/modules/system/boot/plymouth.nix4
-rw-r--r--nixos/modules/tasks/network-interfaces.nix17
-rw-r--r--nixos/modules/virtualisation/containers.nix18
-rw-r--r--nixos/modules/virtualisation/grow-partition.nix2
-rw-r--r--nixos/modules/virtualisation/vmware-guest.nix10
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/cjdns.nix2
-rw-r--r--nixos/tests/containers-tmpfs.nix79
67 files changed, 1319 insertions, 892 deletions
diff --git a/nixos/doc/manual/administration/container-networking.xml b/nixos/doc/manual/administration/container-networking.xml
index 1b1576d3babe..d89d262eff4e 100644
--- a/nixos/doc/manual/administration/container-networking.xml
+++ b/nixos/doc/manual/administration/container-networking.xml
@@ -47,4 +47,12 @@ where <literal>eth0</literal> should be replaced with the desired
 external interface. Note that <literal>ve-+</literal> is a wildcard
 that matches all container interfaces.</para>
 
+<para>If you are using Network Manager, you need to explicitly prevent
+it from managing container interfaces:
+
+<programlisting>
+networking.networkmanager.unmanaged = [ "interface-name:ve-*" ];
+</programlisting>
+</para>
+
 </section>
diff --git a/nixos/doc/manual/development/development.xml b/nixos/doc/manual/development/development.xml
index b0364b346577..47343d93cde9 100644
--- a/nixos/doc/manual/development/development.xml
+++ b/nixos/doc/manual/development/development.xml
@@ -18,7 +18,6 @@ NixOS.</para>
 <xi:include href="building-nixos.xml" />
 <xi:include href="nixos-tests.xml" />
 <xi:include href="testing-installer.xml" />
-<xi:include href="reviewing-contributions.xml" />
 <xi:include href="releases.xml" />
 
 </part>
diff --git a/nixos/doc/manual/development/reviewing-contributions.xml b/nixos/doc/manual/development/reviewing-contributions.xml
deleted file mode 100644
index f86928bcd5d0..000000000000
--- a/nixos/doc/manual/development/reviewing-contributions.xml
+++ /dev/null
@@ -1,393 +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-reviewing-contributions">
-
-<title>Reviewing contributions</title>
-
-<warning>
-  <para>The following section is a draft and reviewing policy is still being 
-    discussed.</para>
-</warning>
-
-<para>The nixpkgs projects receives a fairly high number of contributions via 
-  GitHub pull-requests. Reviewing and approving these is an important task and a 
-  way to contribute to the project.</para>
-
-<para>The high change rate of nixpkgs make any pull request that is open for 
-  long enough subject to conflicts that will require extra work from the 
-  submitter or the merger. Reviewing pull requests in a timely manner and being 
-  responsive to the comments is the key to avoid these. Github provides sort 
-  filters that can be used to see the <link 
-    xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc">most 
-    recently</link> and the <link 
-    xlink:href="https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-asc">least 
-    recently</link> updated pull-requests.</para>
-
-<para>When reviewing a pull request, please always be nice and polite. 
-  Controversial changes can lead to controversial opinions, but it is important 
-  to respect every community members and their work.</para>
-
-<para>GitHub provides reactions, they are a simple and quick way to provide 
-  feedback to pull-requests or any comments. The thumb-down reaction should be 
-  used with care and if possible accompanied with some explanations so the 
-  submitter has directions to improve his contribution.</para>
-
-<para>Pull-requests reviews should include a list of what has been reviewed in a 
-  comment, so other reviewers and mergers can know the state of the 
-  review.</para>
-
-<para>All the review template samples provided in this section are generic and 
-  meant as examples. Their usage is optional and the reviewer is free to adapt 
-  them to his liking.</para>
-
-<section><title>Package updates</title>
-
-<para>A package update is the most trivial and common type of pull-request. 
-  These pull-requests mainly consist in updating the version part of the package 
-  name and the source hash.</para>
-<para>It can happen that non trivial updates include patches or more complex 
-  changes.</para>
-
-<para>Reviewing process:</para>
-
-<itemizedlist>
-  <listitem><para>Add labels to the pull-request. (Requires commit 
-      rights)</para>
-    <itemizedlist>
-      <listitem><para><literal>8.has: package (update)</literal> and any topic 
-          label that fit the updated package.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the package versioning is fitting the 
-      guidelines.</para></listitem>
-  <listitem><para>Ensure that the commit text is fitting the 
-      guidelines.</para></listitem>
-  <listitem><para>Ensure that the package maintainers are notified.</para>
-    <itemizedlist>
-      <listitem><para>mention-bot usually notify GitHub users based on the 
-          submitted changes, but it can happen that it misses some of the 
-          package maintainers.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the meta field contains correct 
-      information.</para>
-    <itemizedlist>
-      <listitem><para>License can change with version updates, so it should be 
-          checked to be fitting upstream license.</para></listitem>
-      <listitem><para>If the package has no maintainer, a maintainer must be 
-          set. This can be the update submitter or a community member that 
-          accepts to take maintainership of the package.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the code contains no typos.</para></listitem>
-  <listitem><para>Building the package locally.</para>
-    <itemizedlist>
-      <listitem><para>Pull-requests are often targeted to the master or staging 
-          branch so building the pull-request locally as it is submitted can 
-          trigger a large amount of source builds.</para>
-        <para>It is possible to rebase the changes on nixos-unstable or 
-          nixpkgs-unstable for easier review by running the following commands 
-          from a nixpkgs clone.
-<screen>
-$ git remote add channels https://github.com/NixOS/nixpkgs-channels.git <co 
-  xml:id='reviewing-rebase-1' />
-$ git fetch channels nixos-unstable <co xml:id='reviewing-rebase-2' />
-$ git fetch origin pull/PRNUMBER/head <co xml:id='reviewing-rebase-3' />
-$ git rebase --onto nixos-unstable BASEBRANCH FETCH_HEAD <co 
-  xml:id='reviewing-rebase-4' />
-</screen>
-        <calloutlist>
-          <callout arearefs='reviewing-rebase-1'>
-            <para>This should be done only once to be able to fetch channel 
-              branches from the nixpkgs-channels repository.</para>
-          </callout>
-          <callout arearefs='reviewing-rebase-2'>
-            <para>Fetching the nixos-unstable branch.</para>
-          </callout>
-          <callout arearefs='reviewing-rebase-3'>
-            <para>Fetching the pull-request changes, <varname>PRNUMBER</varname> 
-              is the number at the end of the pull-request title and 
-              <varname>BASEBRANCH</varname> the base branch of the 
-              pull-request.</para>
-          </callout>
-          <callout arearefs='reviewing-rebase-3'>
-            <para>Rebasing the pull-request changes to the nixos-unstable 
-              branch.</para>
-          </callout>
-        </calloutlist>
-        </para>
-      </listitem>
-      <listitem>
-        <para>The <link xlink:href="https://github.com/madjar/nox">nox</link> 
-          tool can be used to review a pull-request content in a single command. 
-          It doesn't rebase on a channel branch so it might trigger multiple 
-          source builds. <varname>PRNUMBER</varname> should be replaced by the 
-          number at the end of the pull-request title.</para>
-<screen>
-$ nix-shell -p nox --run "nox-review -k pr PRNUMBER"
-</screen>
-      </listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Running every binary.</para></listitem>
-</itemizedlist>
-
-<example><title>Sample template for a package update review</title>
-<screen>
-##### Reviewed points
-
-- [ ] package name fits guidelines
-- [ ] package version fits guidelines
-- [ ] package build on ARCHITECTURE
-- [ ] executables tested on ARCHITECTURE
-- [ ] all depending packages build
-
-##### Possible improvements
-
-##### Comments
-
-</screen></example>
-</section>
-
-<section><title>New packages</title>
-
-<para>New packages are a common type of pull-requests. These pull requests 
-  consists in adding a new nix-expression for a package.</para>
-
-<para>Reviewing process:</para>
-
-<itemizedlist>
-  <listitem><para>Add labels to the pull-request. (Requires commit 
-      rights)</para>
-    <itemizedlist>
-      <listitem><para><literal>8.has: package (new)</literal> and any topic 
-          label that fit the new package.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the package versioning is fitting the 
-      guidelines.</para></listitem>
-  <listitem><para>Ensure that the commit name is fitting the 
-      guidelines.</para></listitem>
-  <listitem><para>Ensure that the meta field contains correct 
-      information.</para>
-    <itemizedlist>
-      <listitem><para>License must be checked to be fitting upstream 
-          license.</para></listitem>
-      <listitem><para>Platforms should be set or the package will not get binary 
-          substitutes.</para></listitem>
-      <listitem><para>A maintainer must be set, this can be the package 
-          submitter or a community member that accepts to take maintainership of 
-          the package.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the code contains no typos.</para></listitem>
-  <listitem><para>Ensure the package source.</para>
-    <itemizedlist>
-      <listitem><para>Mirrors urls should be used when 
-          available.</para></listitem>
-      <listitem><para>The most appropriate function should be used (e.g. 
-          packages from GitHub should use 
-          <literal>fetchFromGitHub</literal>).</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Building the package locally.</para></listitem>
-  <listitem><para>Running every binary.</para></listitem>
-</itemizedlist>
-
-<example><title>Sample template for a new package review</title>
-<screen>
-##### Reviewed points
-
-- [ ] package path fits guidelines
-- [ ] package name fits guidelines
-- [ ] package version fits guidelines
-- [ ] package build on ARCHITECTURE
-- [ ] executables tested on ARCHITECTURE
-- [ ] `meta.description` is set and fits guidelines
-- [ ] `meta.license` fits upstream license
-- [ ] `meta.platforms` is set
-- [ ] `meta.maintainers` is set
-- [ ] build time only dependencies are declared in `nativeBuildInputs`
-- [ ] source is fetched using the appropriate function
-- [ ] phases are respected
-- [ ] patches that are remotely available are fetched with `fetchpatch`
-
-##### Possible improvements
-
-##### Comments
-
-</screen></example>
-</section>
-
-<section><title>Module updates</title>
-
-<para>Module updates are submissions changing modules in some ways. These often 
-  contains changes to the options or introduce new options.</para>
-
-<para>Reviewing process</para>
-
-<itemizedlist>
-  <listitem><para>Add labels to the pull-request. (Requires commit 
-      rights)</para>
-    <itemizedlist>
-      <listitem><para><literal>8.has: module (update)</literal> and any topic 
-          label that fit the module.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the module maintainers are notified.</para>
-    <itemizedlist>
-      <listitem><para>Mention-bot notify GitHub users based on the submitted 
-          changes, but it can happen that it miss some of the package 
-          maintainers.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the module tests, if any, are 
-      succeeding.</para></listitem>
-  <listitem><para>Ensure that the introduced options are correct.</para>
-    <itemizedlist>
-      <listitem><para>Type should be appropriate (string related types differs 
-          in their merging capabilities, <literal>optionSet</literal> and 
-          <literal>string</literal> types are deprecated).</para></listitem>
-      <listitem><para>Description, default and example should be 
-          provided.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that option changes are backward compatible.</para>
-    <itemizedlist>
-      <listitem><para><literal>mkRenamedOptionModule</literal> and 
-          <literal>mkAliasOptionModule</literal> functions provide way to make 
-          option changes backward compatible.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that removed options are declared with 
-      <literal>mkRemovedOptionModule</literal></para></listitem>
-  <listitem><para>Ensure that changes that are not backward compatible are 
-      mentioned in release notes.</para></listitem>
-  <listitem><para>Ensure that documentations affected by the change is 
-      updated.</para></listitem>
-</itemizedlist>
-
-<example><title>Sample template for a module update review</title>
-<screen>
-##### Reviewed points
-
-- [ ] changes are backward compatible
-- [ ] removed options are declared with `mkRemovedOptionModule`
-- [ ] changes that are not backward compatible are documented in release notes
-- [ ] module tests succeed on ARCHITECTURE
-- [ ] options types are appropriate
-- [ ] options description is set
-- [ ] options example is provided
-- [ ] documentation affected by the changes is updated
-
-##### Possible improvements
-
-##### Comments
-
-</screen></example>
-</section>
-
-<section><title>New modules</title>
-
-<para>New modules submissions introduce a new module to NixOS.</para>
-
-<itemizedlist>
-  <listitem><para>Add labels to the pull-request. (Requires commit 
-      rights)</para>
-    <itemizedlist>
-      <listitem><para><literal>8.has: module (new)</literal> and any topic label 
-          that fit the module.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the module tests, if any, are 
-      succeeding.</para></listitem>
-  <listitem><para>Ensure that the introduced options are correct.</para>
-    <itemizedlist>
-      <listitem><para>Type should be appropriate (string related types differs 
-          in their merging capabilities, <literal>optionSet</literal> and 
-          <literal>string</literal> types are deprecated).</para></listitem>
-      <listitem><para>Description, default and example should be 
-          provided.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that module <literal>meta</literal> field is 
-      present</para>
-    <itemizedlist>
-      <listitem><para>Maintainers should be declared in 
-          <literal>meta.maintainers</literal>.</para></listitem>
-      <listitem><para>Module documentation should be declared with 
-          <literal>meta.doc</literal>.</para></listitem>
-    </itemizedlist>
-  </listitem>
-  <listitem><para>Ensure that the module respect other modules 
-      functionality.</para>
-    <itemizedlist>
-      <listitem><para>For example, enabling a module should not open firewall 
-          ports by default.</para></listitem>
-    </itemizedlist>
-  </listitem>
-</itemizedlist>
-
-<example><title>Sample template for a new module review</title>
-<screen>
-##### Reviewed points
-
-- [ ] module path fits the guidelines
-- [ ] module tests succeed on ARCHITECTURE
-- [ ] options have appropriate types
-- [ ] options have default
-- [ ] options have example
-- [ ] options have descriptions
-- [ ] No unneeded package is added to system.environmentPackages
-- [ ] meta.maintainers is set
-- [ ] module documentation is declared in meta.doc
-
-##### Possible improvements
-
-##### Comments
-
-</screen></example>
-</section>
-
-<section><title>Other submissions</title>
-
-<para>Other type of submissions requires different reviewing steps.</para>
-
-<para>If you consider having enough knowledge and experience in a topic and 
-  would like to be a long-term reviewer for related submissions, please contact 
-  the current reviewers for that topic. They will give you information about the 
-  reviewing process.
-The main reviewers for a topic can be hard to find as there is no list, but 
-checking past pull-requests to see who reviewed or git-blaming the code to see 
-who committed to that topic can give some hints.</para>
-
-<para>Container system, boot system and library changes are some examples of the 
-  pull requests fitting this category.</para>
-
-</section>
-
-<section><title>Merging pull-requests</title>
-
-<para>It is possible for community members that have enough knowledge and 
-  experience on a special topic to contribute by merging pull requests.</para>
-
-<para>TODO: add the procedure to request merging rights.</para>
-
-<!--
-The following paragraph about how to deal with unactive contributors is just a
-proposition and should be modified to what the community agrees to be the right
-policy.
-
-<para>Please note that contributors with commit rights unactive for more than 
-  three months will have their commit rights revoked.</para>
--->
-
-<para>In a case a contributor leaves definitively the Nix community, he should 
-  create an issue or notify the mailing list with references of packages and 
-  modules he maintains so the maintainership can be taken over by other 
-  contributors.</para>
-
-</section>
-</chapter>
diff --git a/nixos/doc/manual/release-notes/rl-1703.xml b/nixos/doc/manual/release-notes/rl-1703.xml
index 743f3dce2302..a133630e1464 100644
--- a/nixos/doc/manual/release-notes/rl-1703.xml
+++ b/nixos/doc/manual/release-notes/rl-1703.xml
@@ -68,6 +68,15 @@ following incompatible changes:</para>
     that may be in /etc.
     </para>
   </listitem>
+
+  <listitem>
+    <para>
+      Parsoid service now uses YAML configuration format.
+     <literal>service.parsoid.interwikis</literal> is now called
+     <literal>service.parsoid.wikis</literal> and is a list of either API URLs
+     or attribute sets as specified in parsoid's documentation.
+    </para>
+  </listitem>
 </itemizedlist>
 
 
diff --git a/nixos/lib/make-squashfs.nix b/nixos/lib/make-squashfs.nix
index 3b640334e17a..2baa4f667607 100644
--- a/nixos/lib/make-squashfs.nix
+++ b/nixos/lib/make-squashfs.nix
@@ -25,6 +25,6 @@ stdenv.mkDerivation {
 
       # Generate the squashfs image.
       mksquashfs nix-path-registration $storePaths $out \
-        -keep-as-directory -all-root
+        -keep-as-directory -all-root -comp xz
     '';
 }
diff --git a/nixos/maintainers/scripts/ec2/create-amis.sh b/nixos/maintainers/scripts/ec2/create-amis.sh
index e26caa191643..0750a1b18c99 100755
--- a/nixos/maintainers/scripts/ec2/create-amis.sh
+++ b/nixos/maintainers/scripts/ec2/create-amis.sh
@@ -1,4 +1,8 @@
-#! /bin/sh -e
+#!/usr/bin/env nix-shell
+#! nix-shell -i bash -p qemu ec2_ami_tools jq ec2_api_tools awscli
+
+# To start with do: nix-shell -p awscli --run "aws configure"
+
 
 set -o pipefail
 #set -x
@@ -15,7 +19,7 @@ rm -f ec2-amis.nix
 
 types="hvm pv"
 stores="ebs s3"
-regions="eu-west-1 eu-central-1 us-east-1 us-west-1 us-west-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ap-northeast-2 sa-east-1 ap-south-1"
+regions="eu-west-1 eu-central-1 us-east-1 us-east-2 us-west-1 us-west-2 ap-southeast-1 ap-southeast-2 ap-northeast-1 ap-northeast-2 sa-east-1 ap-south-1"
 
 for type in $types; do
     link=$stateDir/$type
@@ -57,7 +61,7 @@ for type in $types; do
                     ami=$(aws ec2 copy-image \
                         --region "$region" \
                         --source-region "$prevRegion" --source-image-id "$prevAmi" \
-                        --name "$name" --description "$description" | json -q .ImageId)
+                        --name "$name" --description "$description" | jq -r '.ImageId')
                     if [ "$ami" = null ]; then break; fi
                 else
 
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
index 770c3a03f9d8..52ad1e714fb9 100644
--- a/nixos/modules/config/fonts/fontconfig.nix
+++ b/nixos/modules/config/fonts/fontconfig.nix
@@ -301,9 +301,7 @@ in
           };
 
           style = mkOption {
-            type = types.str // {
-              check = flip elem ["none" "slight" "medium" "full"];
-            };
+            type = types.enum ["none" "slight" "medium" "full"];
             default = "full";
             description = ''
               TrueType hinting style, one of <literal>none</literal>,
@@ -329,9 +327,7 @@ in
             default = "rgb";
             type = types.enum ["rgb" "bgr" "vrgb" "vbgr" "none"];
             description = ''
-              Subpixel order, one of <literal>none</literal>,
-              <literal>rgb</literal>, <literal>bgr</literal>,
-              <literal>vrgb</literal>, or <literal>vbgr</literal>.
+              Subpixel order.
             '';
           };
 
@@ -339,9 +335,7 @@ in
             default = "default";
             type = types.enum ["none" "default" "light" "legacy"];
             description = ''
-              FreeType LCD filter, one of <literal>none</literal>,
-              <literal>default</literal>, <literal>light</literal>, or
-              <literal>legacy</literal>.
+              FreeType LCD filter.
             '';
           };
 
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix
index e341931aacce..d7fd38ebed9a 100644
--- a/nixos/modules/config/i18n.nix
+++ b/nixos/modules/config/i18n.nix
@@ -44,6 +44,7 @@ in
       consolePackages = mkOption {
         type = types.listOf types.package;
         default = with pkgs.kbdKeymaps; [ dvp neo ];
+        defaultText = ''with pkgs.kbdKeymaps; [ dvp neo ]'';
         description = ''
 	  List of additional packages that provide console fonts, keymaps and
           other resources.
diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix
index 69db518ab21c..3ce97ad31c22 100644
--- a/nixos/modules/hardware/video/bumblebee.nix
+++ b/nixos/modules/hardware/video/bumblebee.nix
@@ -13,6 +13,8 @@ let
     useDisplayDevice = cfg.connectDisplay;
   };
 
+  useBbswitch = cfg.pmMethod == "bbswitch";
+
   primus = pkgs.primus.override {
     inherit useNvidia;
   };
@@ -22,58 +24,69 @@ in
 {
 
   options = {
-    hardware.bumblebee.enable = mkOption {
-      default = false;
-      type = types.bool;
-      description = ''
-        Enable the bumblebee daemon to manage Optimus hybrid video cards.
-        This should power off secondary GPU until its use is requested
-        by running an application with optirun.
-
-        Only nvidia driver is supported so far.
-      '';
-    };
-    hardware.bumblebee.group = mkOption {
-      default = "wheel";
-      example = "video";
-      type = types.str;
-      description = ''Group for bumblebee socket'';
-    };
+    hardware.bumblebee = {
 
-    hardware.bumblebee.connectDisplay = mkOption {
-      default = false;
-      type = types.bool;
-      description = ''
-        Set to true if you intend to connect your discrete card to a
-        monitor. This option will set up your Nvidia card for EDID
-        discovery and to turn on the monitor signal.
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable the bumblebee daemon to manage Optimus hybrid video cards.
+          This should power off secondary GPU until its use is requested
+          by running an application with optirun.
+        '';
+      };
 
-        Only nvidia driver is supported so far.
-      '';
-    };
+      group = mkOption {
+        default = "wheel";
+        example = "video";
+        type = types.str;
+        description = ''Group for bumblebee socket'';
+      };
+
+      connectDisplay = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Set to true if you intend to connect your discrete card to a
+          monitor. This option will set up your Nvidia card for EDID
+          discovery and to turn on the monitor signal.
+
+          Only nvidia driver is supported so far.
+        '';
+      };
+
+      driver = mkOption {
+        default = "nvidia";
+        type = types.enum [ "nvidia" "nouveau" ];
+        description = ''
+          Set driver used by bumblebeed. Supported are nouveau and nvidia.
+        '';
+      };
+
+      pmMethod = mkOption {
+        default = "auto";
+        type = types.enum [ "auto" "bbswitch" "nouveau" "switcheroo" "none" ];
+        description = ''
+          Set preferred power management method for unused card.
+        '';
+      };
 
-    hardware.bumblebee.driver = mkOption {
-      default = "nvidia";
-      type = types.enum [ "nvidia" "nouveau" ];
-      description = ''
-        Set driver used by bumblebeed. Supported are nouveau and nvidia.
-      '';
     };
   };
 
-  config = mkIf config.hardware.bumblebee.enable {
-    boot.blacklistedKernelModules = [ "nouveau" "nvidia" ];
-    boot.kernelModules = [ "bbswitch" ];
-    boot.extraModulePackages = [ kernel.bbswitch ] ++ optional useNvidia kernel.nvidia_x11;
+  config = mkIf cfg.enable {
+    boot.blacklistedKernelModules = [ "nvidia-drm" "nvidia" "nouveau" ];
+    boot.kernelModules = optional useBbswitch [ "bbswitch" ];
+    boot.extraModulePackages = optional useBbswitch kernel.bbswitch ++ optional useNvidia kernel.nvidia_x11;
 
     environment.systemPackages = [ bumblebee primus ];
 
     systemd.services.bumblebeed = {
       description = "Bumblebee Hybrid Graphics Switcher";
-      wantedBy = [ "display-manager.service" ];
-      path = [ kernel.bbswitch bumblebee ];
+      wantedBy = [ "multi-user.target" ];
+      before = [ "display-manager.service" ];
       serviceConfig = {
-        ExecStart = "${bumblebee}/bin/bumblebeed --use-syslog -g ${cfg.group} --driver ${cfg.driver}";
+        ExecStart = "${bumblebee}/bin/bumblebeed --use-syslog -g ${cfg.group} --driver ${cfg.driver} --pm-method ${cfg.pmMethod}";
       };
     };
   };
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
index b5ee57d9e22e..c44dff3bb60d 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix
@@ -1,20 +1,41 @@
 # This module defines a NixOS installation CD that contains X11 and
-# KDE 4.
+# KDE 5.
 
 { config, lib, pkgs, ... }:
 
 with lib;
 
 {
-  imports = [ ./installation-cd-base.nix ../../profiles/graphical.nix ];
+  imports = [ ./installation-cd-base.nix ];
 
-  # Provide wicd for easy wireless configuration.
-  #networking.wicd.enable = true;
+  services.xserver = {
+    enable = true;
+
+    # Automatically login as root.
+    displayManager.slim = {
+      enable = true;
+      defaultUser = "root";
+      autoLogin = true;
+    };
+
+    desktopManager.kde5 = {
+      enable = true;
+      enableQt4Support = false;
+    };
+
+    # Enable touchpad support for many laptops.
+    synaptics.enable = true;
+  };
 
   environment.systemPackages =
-    [ # Include gparted for partitioning disks.
+    [ pkgs.glxinfo
+
+      # Include gparted for partitioning disks.
       pkgs.gparted
 
+      # Firefox for reading the manual.
+      pkgs.firefox
+
       # Include some editors.
       pkgs.vim
       pkgs.bvi # binary editor
@@ -32,80 +53,21 @@ with lib;
   # Don't start the X server by default.
   services.xserver.autorun = mkForce false;
 
-  # Auto-login as root.
-  services.xserver.displayManager.kdm.extraConfig =
-    ''
-      [X-*-Core]
-      AllowRootLogin=true
-      AutoLoginEnable=true
-      AutoLoginUser=root
-      AutoLoginPass=""
-    '';
-
-  # Custom kde-workspace adding some icons on the desktop
-
   system.activationScripts.installerDesktop = let
-    openManual = pkgs.writeScript "nixos-manual.sh" ''
-      #!${pkgs.stdenv.shell}
-      cd ${config.system.build.manual.manual}/share/doc/nixos/
-      konqueror ./index.html
-    '';
-
     desktopFile = pkgs.writeText "nixos-manual.desktop" ''
       [Desktop Entry]
       Version=1.0
       Type=Application
       Name=NixOS Manual
-      Exec=${openManual}
-      Icon=konqueror
+      Exec=firefox ${config.system.build.manual.manual}/share/doc/nixos/index.html
+      Icon=text-html
     '';
 
   in ''
     mkdir -p /root/Desktop
     ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop
-    ln -sfT ${pkgs.kde4.konsole}/share/applications/kde4/konsole.desktop /root/Desktop/konsole.desktop
+    ln -sfT ${pkgs.kde5.konsole}/share/applications/org.kde.konsole.desktop /root/Desktop/org.kde.konsole.desktop
     ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop
   '';
 
-  services.xserver.desktopManager.kde4.kdeWorkspacePackage = let
-    pkg = pkgs.kde4.kde_workspace;
-
-    plasmaInit = pkgs.writeText "00-defaultLayout.js" ''
-      loadTemplate("org.kde.plasma-desktop.defaultPanel")
-
-      for (var i = 0; i < screenCount; ++i) {
-        var desktop = new Activity
-        desktop.name = i18n("Desktop")
-        desktop.screen = i
-        desktop.wallpaperPlugin = 'image'
-        desktop.wallpaperMode = 'SingleImage'
-
-        var folderview = desktop.addWidget("folderview");
-        folderview.writeConfig("url", "desktop:/");
-
-        //Create more panels for other screens
-        if (i > 0){
-          var panel = new Panel
-          panel.screen = i
-          panel.location = 'bottom'
-          panel.height = screenGeometry(i).height > 1024 ? 35 : 27
-          var tasks = panel.addWidget("tasks")
-          tasks.writeConfig("showOnlyCurrentScreen", true);
-        }
-      }
-    '';
-
-  in
-    pkgs.runCommand pkg.name
-      { inherit (pkg) meta; }
-      ''
-        mkdir -p $out
-        cp -prf ${pkg}/* $out/
-        chmod a+w $out/share/apps/plasma-desktop/init
-        cp -f ${plasmaInit} $out/share/apps/plasma-desktop/init/00-defaultLayout.js
-      '';
-
-  # Disable large stuff that's not very useful on the installation CD.
-  services.xserver.desktopManager.kde4.enablePIM = false;
-
 }
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 80a9a520e24e..b61c1f4799ec 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -84,7 +84,7 @@
       spamd = 56;
       #networkmanager = 57; # unused
       nslcd = 58;
-      #scanner = 59; # unused
+      scanner = 59;
       nginx = 60;
       chrony = 61;
       #systemd-journal = 62; # unused
@@ -279,6 +279,8 @@
       hound = 259;
       leaps = 260;
       ipfs  = 261;
+      stanchion = 262;
+      riak-cs = 263;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -528,6 +530,8 @@
       hound = 259;
       leaps = 260;
       ipfs = 261;
+      stanchion = 262;
+      riak-cs = 263;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 8254ada3ddf7..4589f47e7c19 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -159,6 +159,8 @@
   ./services/databases/postgresql.nix
   ./services/databases/redis.nix
   ./services/databases/riak.nix
+  ./services/databases/riak-cs.nix
+  ./services/databases/stanchion.nix
   ./services/databases/virtuoso.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/geoclue2.nix
@@ -346,6 +348,7 @@
   ./services/networking/connman.nix
   ./services/networking/consul.nix
   ./services/networking/coturn.nix
+  ./services/networking/dante.nix
   ./services/networking/ddclient.nix
   ./services/networking/dhcpcd.nix
   ./services/networking/dhcpd.nix
@@ -539,7 +542,6 @@
   ./services/x11/window-managers/fluxbox.nix
   ./services/x11/window-managers/icewm.nix
   ./services/x11/window-managers/bspwm.nix
-  ./services/x11/window-managers/bspwm-unstable.nix
   ./services/x11/window-managers/metacity.nix
   ./services/x11/window-managers/none.nix
   ./services/x11/window-managers/twm.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 32bea97823ce..f90d0d992ec8 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -7,7 +7,7 @@
   # Include some utilities that are useful for installing or repairing
   # the system.
   environment.systemPackages = [
-    pkgs.w3m # needed for the manual anyway
+    pkgs.w3m-nox # needed for the manual anyway
     pkgs.testdisk # useful for repairing boot problems
     pkgs.mssys # for writing Microsoft boot sectors / MBRs
     pkgs.efibootmgr
@@ -42,8 +42,6 @@
     # Some compression/archiver tools.
     pkgs.unzip
     pkgs.zip
-    pkgs.dar # disk archiver
-    pkgs.cabextract
   ];
 
   # Include support for various filesystems.
diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix
index b047b7063653..e2497d04252e 100644
--- a/nixos/modules/profiles/minimal.nix
+++ b/nixos/modules/profiles/minimal.nix
@@ -14,4 +14,6 @@ with lib;
 
   programs.man.enable = mkDefault false;
   programs.info.enable = mkDefault false;
+
+  sound.enable = mkDefault false;
 }
diff --git a/nixos/modules/programs/java.nix b/nixos/modules/programs/java.nix
index 3292aa369d28..d31698c3b392 100644
--- a/nixos/modules/programs/java.nix
+++ b/nixos/modules/programs/java.nix
@@ -34,6 +34,7 @@ in
 
       package = mkOption {
         default = pkgs.jdk;
+        defaultText = "pkgs.jdk";
         description = ''
           Java package to install. Typical values are pkgs.jdk or pkgs.jre.
         '';
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index b6fd9868f98f..5f4d4dc9475e 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -165,7 +165,7 @@ in
   config = {
 
     programs.ssh.setXAuthLocation =
-      mkDefault (config.services.xserver.enable || config.programs.ssh.forwardX11);
+      mkDefault (config.services.xserver.enable || config.programs.ssh.forwardX11 || config.services.openssh.forwardX11);
 
     assertions =
       [ { assertion = cfg.forwardX11 -> cfg.setXAuthLocation;
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 44e07f4618de..a89ce2c743d4 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -30,6 +30,8 @@ with lib;
     (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ])
     (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ] "")
 
+    (mkRenamedOptionModule [ "services" "clamav" "updater" "config" ] [ "services" "clamav" "updater" "extraConfig" ])
+
     # Old Grub-related options.
     (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ])
     (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ])
@@ -142,6 +144,12 @@ with lib;
     # murmur
     (mkRenamedOptionModule [ "services" "murmur" "welcome" ] [ "services" "murmur" "welcometext" ])
 
+    # parsoid
+    (mkRemovedOptionModule [ "services" "parsoid" "interwikis" ] [ "services" "parsoid" "wikis" ])
+
+    # tarsnap
+    (mkRemovedOptionModule [ "services" "tarsnap" "cachedir" ] "Use services.tarsnap.archives.<name>.cachedir")
+
     # Options that are obsolete and have no replacement.
     (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "")
     (mkRemovedOptionModule [ "programs" "bash" "enable" ] "")
diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix
index 0e3a54325cad..97e2d39dc076 100644
--- a/nixos/modules/security/duosec.nix
+++ b/nixos/modules/security/duosec.nix
@@ -73,7 +73,7 @@ in
       };
 
       failmode = mkOption {
-        type = types.str;
+        type = types.enum [ "safe" "enum" ];
         default = "safe";
         description = ''
           On service or configuration errors that prevent Duo
@@ -115,7 +115,7 @@ in
       };
 
       prompts = mkOption {
-        type = types.int;
+        type = types.enum [ 1 2 3 ];
         default = 3;
         description = ''
           If a user fails to authenticate with a second factor, Duo
@@ -181,13 +181,7 @@ in
 
   config = mkIf (cfg.ssh.enable || cfg.pam.enable) {
     assertions =
-      [ { assertion = cfg.failmode == "safe" || cfg.failmode == "secure";
-          message   = "Invalid value for failmode (must be safe or secure).";
-        }
-        { assertion = cfg.prompts == 1 || cfg.prompts == 2 || cfg.prompts == 3;
-          message   = "Invalid value for prompts (must be 1, 2, or 3).";
-        }
-        { assertion = !cfg.pam.enable;
+      [ { assertion = !cfg.pam.enable;
           message   = "PAM support is currently not implemented.";
         }
       ];
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 53c2ace784ef..ea245ecc5b6a 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -6,14 +6,6 @@ let
   cfg = config.security.grsecurity;
   grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock";
 
-  # Ascertain whether ZFS is required for booting the system; grsecurity is
-  # currently incompatible with ZFS, rendering the system unbootable.
-  zfsNeededForBoot = filter
-    (fs: (fs.neededForBoot
-          || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ])
-          && fs.fsType == "zfs")
-    config.system.build.fileSystems != [];
-
   # Ascertain whether NixOS container support is required
   containerSupportRequired =
     config.boot.enableContainers && config.containers != {};
@@ -27,7 +19,14 @@ in
 
   options.security.grsecurity = {
 
-    enable = mkEnableOption "grsecurity/PaX";
+    enable = mkOption {
+      type = types.bool;
+      example = true;
+      default = false;
+      description = ''
+        Enable grsecurity/PaX.
+      '';
+    };
 
     lockTunables = mkOption {
       type = types.bool;
@@ -58,20 +57,10 @@ in
 
   config = mkIf cfg.enable {
 
-    # Allow the user to select a different package set, subject to the stated
-    # required kernel config
     boot.kernelPackages = mkDefault pkgs.linuxPackages_grsec_nixos;
 
     boot.kernelParams = optional cfg.disableEfiRuntimeServices "noefi";
 
-    system.requiredKernelConfig = with config.lib.kernelConfig;
-      [ (isEnabled "GRKERNSEC")
-        (isEnabled "PAX")
-        (isYes "GRKERNSEC_SYSCTL")
-        (isYes "GRKERNSEC_SYSCTL_DISTRO")
-        (isNo "GRKERNSEC_NO_RBAC")
-      ];
-
     nixpkgs.config.grsecurity = true;
 
     # Install PaX related utillities into the system profile.
@@ -135,11 +124,5 @@ in
       "kernel.grsecurity.chroot_caps" = mkForce 0;
     };
 
-    assertions = [
-      { assertion = !zfsNeededForBoot;
-        message = "grsecurity is currently incompatible with ZFS";
-      }
-    ];
-
   };
 }
diff --git a/nixos/modules/security/grsecurity.xml b/nixos/modules/security/grsecurity.xml
index 37314bdba8a5..6f9884336b1e 100644
--- a/nixos/modules/security/grsecurity.xml
+++ b/nixos/modules/security/grsecurity.xml
@@ -225,11 +225,9 @@
   </para>
 
   <para>
-    The NixOS module makes several assumptions about the kernel and so may be
-    incompatible with your customised kernel.  Most of these assumptions are
-    encoded as assertions &#x2014; mismatches should ideally result in a build
-    failure.  Currently, the only way to work around incompatibilities is to
-    eschew the NixOS module and do all configuration yourself.
+    The NixOS module makes several assumptions about the kernel and so
+    may be incompatible with your customised kernel. Currently, the only way
+    to work around incompatibilities is to eschew the NixOS module.
   </para>
 
   </sect1>
diff --git a/nixos/modules/services/backup/crashplan.nix b/nixos/modules/services/backup/crashplan.nix
index 38cf8eb72fb8..d0af2e416b63 100644
--- a/nixos/modules/services/backup/crashplan.nix
+++ b/nixos/modules/services/backup/crashplan.nix
@@ -49,7 +49,7 @@ with lib;
         ensureDir ${crashplan.vardir}/backupArchives 700
         ensureDir ${crashplan.vardir}/log 777
         cp -avn ${crashplan}/conf.template/* ${crashplan.vardir}/conf
-        for x in app.asar bin EULA.txt install.vars lang lib libjniwrap64.so libjniwrap.so libjtux64.so libjtux.so libmd564.so libmd5.so share skin upgrade; do
+        for x in app.asar bin install.vars lang lib libc42archive64.so libc52archive.so libjniwrap64.so libjniwrap.so libjtux64.so libjtux.so libleveldb64.so libleveldb.so libmd564.so libmd5.so share skin upgrade; do
           rm -f ${crashplan.vardir}/$x;
           ln -sf ${crashplan}/$x ${crashplan.vardir}/$x;
         done
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index 24892a2a59a1..67112343c335 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -1,25 +1,25 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
 with lib;
 
 let
-  cfg = config.services.tarsnap;
+  gcfg = config.services.tarsnap;
 
   configFile = name: cfg: ''
-    cachedir ${config.services.tarsnap.cachedir}/${name}
-    keyfile  ${cfg.keyfile}
+    keyfile ${cfg.keyfile}
+    ${optionalString (cfg.cachedir != null) "cachedir ${cfg.cachedir}"}
     ${optionalString cfg.nodump "nodump"}
     ${optionalString cfg.printStats "print-stats"}
     ${optionalString cfg.printStats "humanize-numbers"}
     ${optionalString (cfg.checkpointBytes != null) ("checkpoint-bytes "+cfg.checkpointBytes)}
     ${optionalString cfg.aggressiveNetworking "aggressive-networking"}
-    ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)}
-    ${concatStringsSep "\n" (map (v: "include "+v) cfg.includes)}
+    ${concatStringsSep "\n" (map (v: "exclude ${v}") cfg.excludes)}
+    ${concatStringsSep "\n" (map (v: "include ${v}") cfg.includes)}
     ${optionalString cfg.lowmem "lowmem"}
     ${optionalString cfg.verylowmem "verylowmem"}
-    ${optionalString (cfg.maxbw != null) ("maxbw "+toString cfg.maxbw)}
-    ${optionalString (cfg.maxbwRateUp != null) ("maxbw-rate-up "+toString cfg.maxbwRateUp)}
-    ${optionalString (cfg.maxbwRateDown != null) ("maxbw-rate-down "+toString cfg.maxbwRateDown)}
+    ${optionalString (cfg.maxbw != null) "maxbw ${toString cfg.maxbw}"}
+    ${optionalString (cfg.maxbwRateUp != null) "maxbw-rate-up ${toString cfg.maxbwRateUp}"}
+    ${optionalString (cfg.maxbwRateDown != null) "maxbw-rate-down ${toString cfg.maxbwRateDown}"}
   '';
 in
 {
@@ -60,34 +60,13 @@ in
         '';
       };
 
-      cachedir = mkOption {
-        type    = types.nullOr types.path;
-        default = "/var/cache/tarsnap";
-        description = ''
-          The cache allows tarsnap to identify previously stored data
-          blocks, reducing archival time and bandwidth usage.
-
-          Should the cache become desynchronized or corrupted, tarsnap
-          will refuse to run until you manually rebuild the cache with
-          <command>tarsnap --fsck</command>.
-
-          Note that each individual archive (specified below) has its own cache
-          directory specified under <literal>cachedir</literal>; this is because
-          tarsnap locks the cache during backups, meaning multiple services
-          archives cannot be backed up concurrently or overlap with a shared
-          cache.
-
-          Set to <literal>null</literal> to disable caching.
-        '';
-      };
-
       archives = mkOption {
-        type = types.attrsOf (types.submodule (
+        type = types.attrsOf (types.submodule ({ config, ... }:
           {
             options = {
               keyfile = mkOption {
                 type = types.str;
-                default = config.services.tarsnap.keyfile;
+                default = gcfg.keyfile;
                 description = ''
                   Set a specific keyfile for this archive. This defaults to
                   <literal>"/root/tarsnap.key"</literal> if left unspecified.
@@ -107,6 +86,21 @@ in
                 '';
               };
 
+              cachedir = mkOption {
+                type = types.nullOr types.path;
+                default = "/var/cache/tarsnap/${utils.escapeSystemdPath config.keyfile}";
+                description = ''
+                  The cache allows tarsnap to identify previously stored data
+                  blocks, reducing archival time and bandwidth usage.
+
+                  Should the cache become desynchronized or corrupted, tarsnap
+                  will refuse to run until you manually rebuild the cache with
+                  <command>tarsnap --fsck</command>.
+
+                  Set to <literal>null</literal> to disable caching.
+                '';
+              };
+
               nodump = mkOption {
                 type = types.bool;
                 default = true;
@@ -249,7 +243,7 @@ in
               };
 
             gamedata =
-              { directories = [ "/var/lib/minecraft "];
+              { directories = [ "/var/lib/minecraft" ];
                 period      = "*:30";
               };
           }
@@ -262,8 +256,8 @@ in
           archive names are suffixed by a 1 second resolution timestamp.
 
           For each member of the set is created a timer which triggers the
-          instanced <literal>tarsnap@</literal> service unit. You may use
-          <command>systemctl start tarsnap@archive-name</command> to
+          instanced <literal>tarsnap-archive-name</literal> service unit. You may use
+          <command>systemctl start tarsnap-archive-name</command> to
           manually trigger creation of <literal>archive-name</literal> at
           any time.
         '';
@@ -271,63 +265,73 @@ in
     };
   };
 
-  config = mkIf cfg.enable {
+  config = mkIf gcfg.enable {
     assertions =
       (mapAttrsToList (name: cfg:
         { assertion = cfg.directories != [];
           message = "Must specify paths for tarsnap to back up";
-        }) cfg.archives) ++
+        }) gcfg.archives) ++
       (mapAttrsToList (name: cfg:
         { assertion = !(cfg.lowmem && cfg.verylowmem);
           message = "You cannot set both lowmem and verylowmem";
-        }) cfg.archives);
-
-    systemd.services."tarsnap@" = {
-      description = "Tarsnap archive '%i'";
-      requires    = [ "network-online.target" ];
-      after       = [ "network-online.target" ];
-
-      path = [ pkgs.iputils pkgs.tarsnap pkgs.coreutils ];
-
-      # In order for the persistent tarsnap timer to work reliably, we have to
-      # make sure that the tarsnap server is reachable after systemd starts up
-      # the service - therefore we sleep in a loop until we can ping the
-      # endpoint.
-      preStart = "while ! ping -q -c 1 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done";
-      scriptArgs = "%i";
-      script = ''
-        mkdir -p -m 0755 ${dirOf cfg.cachedir}
-        mkdir -p -m 0700 ${cfg.cachedir}
-        chown root:root ${cfg.cachedir}
-        chmod 0700 ${cfg.cachedir}
-        mkdir -p -m 0700 ${cfg.cachedir}/$1
-        DIRS=`cat /etc/tarsnap/$1.dirs`
-        exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
-      '';
-
-      serviceConfig = {
-        IOSchedulingClass = "idle";
-        NoNewPrivileges = "true";
-        CapabilityBoundingSet = "CAP_DAC_READ_SEARCH";
-        PermissionsStartOnly = "true";
-      };
-    };
+        }) gcfg.archives);
+
+    systemd.services =
+      mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" {
+        description = "Tarsnap archive '${name}'";
+        requires    = [ "network-online.target" ];
+        after       = [ "network-online.target" ];
+
+        path = [ pkgs.iputils pkgs.tarsnap pkgs.utillinux ];
+
+        # In order for the persistent tarsnap timer to work reliably, we have to
+        # make sure that the tarsnap server is reachable after systemd starts up
+        # the service - therefore we sleep in a loop until we can ping the
+        # endpoint.
+        preStart = ''
+          while ! ping -q -c 1 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done
+        '';
+
+        script =
+          let run = ''tarsnap --configfile "/etc/tarsnap/${name}.conf" -c -f "${name}-$(date +"%Y%m%d%H%M%S")" ${concatStringsSep " " cfg.directories}'';
+          in if (cfg.cachedir != null) then ''
+            mkdir -p ${cfg.cachedir}
+            chmod 0700 ${cfg.cachedir}
+
+            ( flock 9
+              if [ ! -e ${cfg.cachedir}/firstrun ]; then
+                ( flock 10
+                  flock -u 9
+                  tarsnap --configfile "/etc/tarsnap/${name}.conf" --fsck
+                  flock 9
+                ) 10>${cfg.cachedir}/firstrun
+              fi
+            ) 9>${cfg.cachedir}/lockf
+
+             exec flock ${cfg.cachedir}/firstrun ${run}
+          '' else "exec ${run}";
+
+        serviceConfig = {
+          Type = "oneshot";
+          IOSchedulingClass = "idle";
+          NoNewPrivileges = "true";
+          CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ];
+          PermissionsStartOnly = "true";
+        };
+      }) gcfg.archives;
 
     # Note: the timer must be Persistent=true, so that systemd will start it even
     # if e.g. your laptop was asleep while the latest interval occurred.
-    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}"
+    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}"
       { timerConfig.OnCalendar = cfg.period;
         timerConfig.Persistent = "true";
         wantedBy = [ "timers.target" ];
-      }) cfg.archives;
+      }) gcfg.archives;
 
     environment.etc =
-      (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
+      mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
         { text = configFile name cfg;
-        }) cfg.archives) //
-      (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs"
-        { text = concatStringsSep " " cfg.directories;
-        }) cfg.archives);
+        }) gcfg.archives;
 
     environment.systemPackages = [ pkgs.tarsnap ];
   };
diff --git a/nixos/modules/services/computing/boinc/client.nix b/nixos/modules/services/computing/boinc/client.nix
new file mode 100644
index 000000000000..5e73638913de
--- /dev/null
+++ b/nixos/modules/services/computing/boinc/client.nix
@@ -0,0 +1,88 @@
+{config, lib, pkgs, ...}:
+
+with lib;
+
+let
+  cfg = config.services.boinc;
+  allowRemoteGuiRpcFlag = optionalString cfg.allowRemoteGuiRpc "--allow_remote_gui_rpc";
+
+in
+  {
+    options.services.boinc = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = ''
+          Whether to enable the BOINC distributed computing client. If this
+          option is set to true, the boinc_client daemon will be run as a
+          background service. The boinccmd command can be used to control the
+          daemon.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.boinc;
+        defaultText = "pkgs.boinc";
+        description = ''
+          Which BOINC package to use.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/boinc";
+        description = ''
+          The directory in which to store BOINC's configuration and data files.
+        '';
+      };
+
+      allowRemoteGuiRpc = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = ''
+          If set to true, any remote host can connect to and control this BOINC
+          client (subject to password authentication). If instead set to false,
+          only the hosts listed in <varname>dataDir</varname>/remote_hosts.cfg will be allowed to
+          connect.
+
+          See also: <ulink url="http://boinc.berkeley.edu/wiki/Controlling_BOINC_remotely#Remote_access"/>
+        '';
+      };
+    };
+
+    config = mkIf cfg.enable {
+      environment.systemPackages = [cfg.package];
+
+      users.users.boinc = {
+        createHome = false;
+        description = "BOINC Client";
+        home = cfg.dataDir;
+        isSystemUser = true;
+      };
+
+      systemd.services.boinc = {
+        description = "BOINC Client";
+        after = ["network.target" "local-fs.target"];
+        wantedBy = ["multi-user.target"];
+        preStart = ''
+          mkdir -p ${cfg.dataDir}
+          chown boinc ${cfg.dataDir}
+        '';
+        script = ''
+          ${cfg.package}/bin/boinc_client --dir ${cfg.dataDir} --redirectio ${allowRemoteGuiRpcFlag}
+        '';
+        serviceConfig = {
+          PermissionsStartOnly = true; # preStart must be run as root
+          User = "boinc";
+          Nice = 10;
+        };
+      };
+    };
+
+    meta = {
+      maintainers = with lib.maintainers; [kierdavis];
+    };
+  }
diff --git a/nixos/modules/services/continuous-integration/gocd-agent/default.nix b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
index d60b55e83d11..05adb18fbe91 100644
--- a/nixos/modules/services/continuous-integration/gocd-agent/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
@@ -37,6 +37,7 @@ in {
 
       packages = mkOption {
         default = [ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ];
+        defaultText = "[ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ]";
         type = types.listOf types.package;
         description = ''
           Packages to add to PATH for the Go.CD agent process.
diff --git a/nixos/modules/services/continuous-integration/gocd-server/default.nix b/nixos/modules/services/continuous-integration/gocd-server/default.nix
index 4bb792055d25..07e00f17f1e8 100644
--- a/nixos/modules/services/continuous-integration/gocd-server/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-server/default.nix
@@ -68,6 +68,7 @@ in {
 
       packages = mkOption {
         default = [ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ];
+        defaultText = "[ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ]";
         type = types.listOf types.package;
         description = ''
           Packages to add to PATH for the Go.CD server's process.
diff --git a/nixos/modules/services/databases/riak-cs.nix b/nixos/modules/services/databases/riak-cs.nix
new file mode 100644
index 000000000000..198efc29222a
--- /dev/null
+++ b/nixos/modules/services/databases/riak-cs.nix
@@ -0,0 +1,202 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.riak-cs;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.riak-cs = {
+
+      enable = mkEnableOption "riak-cs";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.riak-cs;
+        defaultText = "pkgs.riak-cs";
+        example = literalExample "pkgs.riak-cs";
+        description = ''
+          Riak package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.str;
+        default = "riak-cs@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+      
+      anonymousUserCreation = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Anonymous user creation.
+        '';
+      };
+
+      riakHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8087";
+        description = ''
+          Name of riak hosting service.
+        '';
+      };
+
+      listener = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8080";
+        description = ''
+          Name of Riak CS listening service.
+        '';
+      };
+
+      stanchionHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of stanchion hosting service.
+        '';
+      };
+
+      stanchionSsl = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Tell stanchion to use SSL.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.str;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/riak-cs";
+        description = ''
+          Data directory for Riak CS.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/riak-cs";
+        description = ''
+          Log directory for Riak CS.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>riak-cs.conf</filename>.
+        '';
+      };
+
+      extraAdvancedConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>advanced.config</filename>.
+        '';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+    environment.etc."riak-cs/riak-cs.conf".text = ''
+      nodename = ${cfg.nodeName}
+      distributed_cookie = ${cfg.distributedCookie}
+
+      platform_log_dir = ${cfg.logDir}
+
+      riak_host = ${cfg.riakHost}
+      listener = ${cfg.listener}
+      stanchion_host = ${cfg.stanchionHost}
+
+      anonymous_user_creation = ${if cfg.anonymousUserCreation then "on" else "off"}
+
+      ${cfg.extraConfig}
+    '';
+
+    environment.etc."riak-cs/advanced.config".text = ''
+      ${cfg.extraAdvancedConfig}
+    '';
+
+    users.extraUsers.riak-cs = {
+      name = "riak-cs";
+      uid = config.ids.uids.riak-cs;
+      group = "riak";
+      description = "Riak CS server user";
+    };
+
+  systemd.services.riak-cs = {
+      description = "Riak CS Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.HOME = "${cfg.dataDir}";
+      environment.RIAK_CS_DATA_DIR = "${cfg.dataDir}";
+      environment.RIAK_CS_LOG_DIR = "${cfg.logDir}";
+      environment.RIAK_CS_ETC_DIR = "/etc/riak";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R riak-cs ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R riak-cs ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/riak-cs console";
+        ExecStop = "${cfg.package}/bin/riak-cs stop";
+        StandardInput = "tty";
+        User = "riak-cs";
+        Group = "riak-cs";
+        PermissionsStartOnly = true;
+        # Give Riak a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/riak"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix
index 4477904f78c6..e0ebf164aef0 100644
--- a/nixos/modules/services/databases/riak.nix
+++ b/nixos/modules/services/databases/riak.nix
@@ -20,6 +20,8 @@ in
 
       package = mkOption {
         type = types.package;
+        default = pkgs.riak;
+        defaultText = "pkgs.riak";
         example = literalExample "pkgs.riak";
         description = ''
           Riak package to use.
@@ -68,6 +70,14 @@ in
         '';
       };
 
+      extraAdvancedConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>advanced.config</filename>.
+        '';
+      };
+
     };
 
   };
@@ -88,6 +98,10 @@ in
       ${cfg.extraConfig}
     '';
 
+    environment.etc."riak/advanced.config".text = ''
+      ${cfg.extraAdvancedConfig}
+    '';
+
     users.extraUsers.riak = {
       name = "riak";
       uid = config.ids.uids.riak;
diff --git a/nixos/modules/services/databases/stanchion.nix b/nixos/modules/services/databases/stanchion.nix
new file mode 100644
index 000000000000..f2dbb78b5c4b
--- /dev/null
+++ b/nixos/modules/services/databases/stanchion.nix
@@ -0,0 +1,212 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.stanchion;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.stanchion = {
+
+      enable = mkEnableOption "stanchion";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.stanchion;
+        defaultText = "pkgs.stanchion";
+        example = literalExample "pkgs.stanchion";
+        description = ''
+          Stanchion package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.str;
+        default = "stanchion@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+
+      adminKey = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Name of admin user.
+        '';
+      };
+
+      adminSecret = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Name of admin secret
+        '';
+      };
+
+      riakHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8087";
+        description = ''
+          Name of riak hosting service.
+        '';
+      };
+
+      listener = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of Riak CS listening service.
+        '';
+      };
+
+      stanchionHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of stanchion hosting service.
+        '';
+      };
+
+      stanchionSsl = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Tell stanchion to use SSL.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.str;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/stanchion";
+        description = ''
+          Data directory for Stanchion.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/stanchion";
+        description = ''
+          Log directory for Stanchino.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>stanchion.conf</filename>.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+
+    environment.etc."stanchion/advanced.config".text = ''
+      [{stanchion, []}].
+    '';
+
+    environment.etc."stanchion/stanchion.conf".text = ''
+      listener = ${cfg.listener}
+
+      riak_host = ${cfg.riakHost}
+
+      ${optionalString (cfg.adminKey == "") "#"} admin.key=${optionalString (cfg.adminKey != "") cfg.adminKey}
+      ${optionalString (cfg.adminSecret == "") "#"} admin.secret=${optionalString (cfg.adminSecret != "") cfg.adminSecret}
+
+      platform_bin_dir = ${pkgs.stanchion}/bin
+      platform_data_dir = ${cfg.dataDir}
+      platform_etc_dir = /etc/stanchion
+      platform_lib_dir = ${pkgs.stanchion}/lib
+      platform_log_dir = ${cfg.logDir}
+
+      nodename = ${cfg.nodeName}
+
+      distributed_cookie = ${cfg.distributedCookie}
+
+      stanchion_ssl=${if cfg.stanchionSsl then "on" else "off"}
+
+      ${cfg.extraConfig}
+    '';
+
+    users.extraUsers.stanchion = {
+      name = "stanchion";
+      uid = config.ids.uids.stanchion;
+      group = "stanchion";
+      description = "Stanchion server user";
+    };
+
+    users.extraGroups.stanchion.gid = config.ids.gids.stanchion;
+
+    systemd.services.stanchion = {
+      description = "Stanchion Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.HOME = "${cfg.dataDir}";
+      environment.STANCHION_DATA_DIR = "${cfg.dataDir}";
+      environment.STANCHION_LOG_DIR = "${cfg.logDir}";
+      environment.STANCHION_ETC_DIR = "/etc/stanchion";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R stanchion:stanchion ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R stanchion:stanchion ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/stanchion console";
+        ExecStop = "${cfg.package}/bin/stanchion stop";
+        StandardInput = "tty";
+        User = "stanchion";
+        Group = "stanchion";
+        PermissionsStartOnly = true;
+        # Give Stanchion a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/stanchion"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index a34037403123..8ddb9ef9c53b 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -7,9 +7,35 @@ let
   pkg = if config.hardware.sane.snapshot
     then pkgs.sane-backends-git
     else pkgs.sane-backends;
-  backends = [ pkg ] ++ config.hardware.sane.extraBackends;
+
+  sanedConf = pkgs.writeTextFile {
+    name = "saned.conf";
+    destination = "/etc/sane.d/saned.conf";
+    text = ''
+      localhost
+      ${config.services.saned.extraConfig}
+    '';
+  };
+
+  netConf = pkgs.writeTextFile {
+    name = "net.conf";
+    destination = "/etc/sane.d/net.conf";
+    text = ''
+      ${lib.optionalString config.services.saned.enable "localhost"}
+      ${config.hardware.sane.netConf}
+    '';
+  };
+
+  env = {
+    SANE_CONFIG_DIR = config.hardware.sane.configDir;
+    LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
+  };
+
+  backends = [ pkg netConf ] ++ optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends;
   saneConfig = pkgs.mkSaneConfig { paths = backends; };
 
+  enabled = config.hardware.sane.enable || config.services.saned.enable;
+
 in
 
 {
@@ -51,27 +77,86 @@ in
 
     hardware.sane.configDir = mkOption {
       type = types.string;
+      internal = true;
       description = "The value of SANE_CONFIG_DIR.";
     };
 
-  };
+    hardware.sane.netConf = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.16";
+      description = ''
+        Network hosts that should be probed for remote scanners.
+      '';
+    };
 
+    services.saned.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable saned network daemon for remote connection to scanners.
 
-  ###### implementation
+        saned would be runned from <literal>scanner</literal> user; to allow
+        access to hardware that doesn't have <literal>scanner</literal> group
+        you should add needed groups to this user.
+      '';
+    };
 
-  config = mkIf config.hardware.sane.enable {
+    services.saned.extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.0/24";
+      description = ''
+        Extra saned configuration lines.
+      '';
+    };
 
-    hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+  };
 
-    environment.systemPackages = backends;
-    environment.sessionVariables = {
-      SANE_CONFIG_DIR = config.hardware.sane.configDir;
-      LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
-    };
-    services.udev.packages = backends;
 
-    users.extraGroups."scanner".gid = config.ids.gids.scanner;
+  ###### implementation
 
-  };
+  config = mkMerge [
+    (mkIf enabled {
+      hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+
+      environment.systemPackages = backends;
+      environment.sessionVariables = env;
+      services.udev.packages = backends;
+
+      users.extraGroups."scanner".gid = config.ids.gids.scanner;
+    })
+
+    (mkIf config.services.saned.enable {
+      networking.firewall.connectionTrackingModules = [ "sane" ];
+
+      systemd.services."saned@" = {
+        description = "Scanner Service";
+        environment = mapAttrs (name: val: toString val) env;
+        serviceConfig = {
+          User = "scanner";
+          Group = "scanner";
+          ExecStart = "${pkg}/bin/saned";
+        };
+      };
+
+      systemd.sockets.saned = {
+        description = "saned incoming socket";
+        wantedBy = [ "sockets.target" ];
+        listenStreams = [ "0.0.0.0:6566" "[::]:6566" ];
+        socketConfig = {
+          # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
+          BindIPv6Only = "ipv6-only";
+          Accept = true;
+          MaxConnections = 1;
+        };
+      };
+
+      users.extraUsers."scanner" = {
+        uid = config.ids.uids.scanner;
+        group = "scanner";
+      };
+    })
+  ];
 
 }
diff --git a/nixos/modules/services/misc/dictd.nix b/nixos/modules/services/misc/dictd.nix
index 24dca15dd913..7e3b6431a133 100644
--- a/nixos/modules/services/misc/dictd.nix
+++ b/nixos/modules/services/misc/dictd.nix
@@ -25,7 +25,8 @@ in
       DBs = mkOption {
         type = types.listOf types.package;
         default = with pkgs.dictdDBs; [ wiktionary wordnet ];
-        example = [ pkgs.dictdDBs.nld2eng ];
+        defaultText = "with pkgs.dictdDBs; [ wiktionary wordnet ]";
+        example = literalExample "[ pkgs.dictdDBs.nld2eng ]";
         description = ''List of databases to make available.'';
       };
 
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index e5a125ad3245..e96645c79c77 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -41,6 +41,7 @@ in
         type = types.path;
         description = "The Disnix package";
         default = pkgs.disnix;
+        defaultText = "pkgs.disnix";
       };
 
     };
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index 3e4584c7a512..cb8fa901bbd2 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -164,18 +164,21 @@ in {
       packages.gitlab = mkOption {
         type = types.package;
         default = pkgs.gitlab;
+        defaultText = "pkgs.gitlab";
         description = "Reference to the gitlab package";
       };
 
       packages.gitlab-shell = mkOption {
         type = types.package;
         default = pkgs.gitlab-shell;
+        defaultText = "pkgs.gitlab-shell";
         description = "Reference to the gitlab-shell package";
       };
 
       packages.gitlab-workhorse = mkOption {
         type = types.package;
         default = pkgs.gitlab-workhorse;
+        defaultText = "pkgs.gitlab-workhorse";
         description = "Reference to the gitlab-workhorse package";
       };
 
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 333782d15bcb..e2bbd4b01aa1 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -172,8 +172,8 @@ in
             sshKey = "/root/.ssh/id_buildfarm";
             system = "x86_64-linux";
             maxJobs = 2;
-            supportedFeatures = "kvm";
-            mandatoryFeatures = "perf";
+            supportedFeatures = [ "kvm" ];
+            mandatoryFeatures = [ "perf" ];
           }
         ];
         description = ''
diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix
index ab1b54068772..ae3f84333d2d 100644
--- a/nixos/modules/services/misc/parsoid.nix
+++ b/nixos/modules/services/misc/parsoid.nix
@@ -6,20 +6,21 @@ let
 
   cfg = config.services.parsoid;
 
-  conf = ''
-    exports.setup = function( parsoidConfig ) {
-      ${toString (mapAttrsToList (name: str: "parsoidConfig.setInterwiki('${name}', '${str}');") cfg.interwikis)}
-
-      parsoidConfig.serverInterface = "${cfg.interface}";
-      parsoidConfig.serverPort = ${toString cfg.port};
-
-      parsoidConfig.useSelser = true;
-
-      ${cfg.extraConfig}
-    };
-  '';
+  confTree = {
+    worker_heartbeat_timeout = 300000;
+    logging = { level = "info"; };
+    services = [{
+      module = "lib/index.js";
+      entrypoint = "apiServiceWorker";
+      conf = {
+        mwApis = map (x: if isAttrs x then x else { uri = x; }) cfg.wikis;
+        serverInterface = cfg.interface;
+        serverPort = cfg.port;
+      };
+    }];
+  };
 
-  confFile = builtins.toFile "localsettings.js" conf;
+  confFile = pkgs.writeText "config.yml" (builtins.toJSON (recursiveUpdate confTree cfg.extraConfig));
 
 in
 {
@@ -38,9 +39,9 @@ in
         '';
       };
 
-      interwikis = mkOption {
-        type = types.attrsOf types.str;
-        example = { localhost = "http://localhost/api.php"; };
+      wikis = mkOption {
+        type = types.listOf (types.either types.str types.attrs);
+        example = [ "http://localhost/api.php" ];
         description = ''
           Used MediaWiki API endpoints.
         '';
@@ -71,8 +72,8 @@ in
       };
 
       extraConfig = mkOption {
-        type = types.lines;
-        default = "";
+        type = types.attrs;
+        default = {};
         description = ''
           Extra configuration to add to parsoid configuration.
         '';
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 3c3d83c66ed0..01c6fb817669 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -9,7 +9,7 @@ let
     BaseDir "${cfg.dataDir}"
     PIDFile "${cfg.pidFile}"
     AutoLoadPlugin ${if cfg.autoLoadPlugin then "true" else "false"}
-    Hostname ${config.networking.hostName}
+    Hostname "${config.networking.hostName}"
 
     LoadPlugin syslog
     <Plugin "syslog">
diff --git a/nixos/modules/services/network-filesystems/tahoe.nix b/nixos/modules/services/network-filesystems/tahoe.nix
index f1846b963252..f91827c379de 100644
--- a/nixos/modules/services/network-filesystems/tahoe.nix
+++ b/nixos/modules/services/network-filesystems/tahoe.nix
@@ -138,6 +138,45 @@ in
               '';
             };
             helper.enable = mkEnableOption "helper service";
+            sftpd.enable = mkEnableOption "SFTP service";
+            sftpd.port = mkOption {
+              default = null;
+              type = types.nullOr types.int;
+              description = ''
+                The port on which the SFTP server will listen.
+
+                This is the correct setting to tweak if you want Tahoe's SFTP
+                daemon to listen on a different port.
+              '';
+            };
+            sftpd.hostPublicKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the SSH host public key.
+              '';
+            };
+            sftpd.hostPrivateKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the SSH host private key.
+              '';
+            };
+            sftpd.accounts.file = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the accounts file.
+              '';
+            };
+            sftpd.accounts.url = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                URL of the accounts server.
+              '';
+            };
             package = mkOption {
               default = pkgs.tahoelafs;
               defaultText = "pkgs.tahoelafs";
@@ -256,6 +295,19 @@ in
 
                 [helper]
                 enabled = ${if settings.helper.enable then "true" else "false"}
+
+                [sftpd]
+                enabled = ${if settings.sftpd.enable then "true" else "false"}
+                ${optionalString (settings.sftpd.port != null)
+                  "port = ${toString settings.sftpd.port}"}
+                ${optionalString (settings.sftpd.hostPublicKeyFile != null)
+                  "host_pubkey_file = ${settings.sftpd.hostPublicKeyFile}"}
+                ${optionalString (settings.sftpd.hostPrivateKeyFile != null)
+                  "host_privkey_file = ${settings.sftpd.hostPrivateKeyFile}"}
+                ${optionalString (settings.sftpd.accounts.file != null)
+                  "accounts.file = ${settings.sftpd.accounts.file}"}
+                ${optionalString (settings.sftpd.accounts.url != null)
+                  "accounts.url = ${settings.sftpd.accounts.url}"}
               '';
             });
           # Actually require Tahoe, so that we will have it installed.
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index 7e981183353d..f50dae2ab7be 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -19,30 +19,21 @@ let
         type = types.str;
         description = "Public key at the opposite end of the tunnel.";
       };
-      hostname = mkOption {
-        default = "";
-        example = "foobar.hype";
-        type = types.str;
-        description = "Optional hostname to add to /etc/hosts; prevents reverse lookup failures.";
-      };
     };
   };
 
-  # Additional /etc/hosts entries for peers with an associated hostname
-  cjdnsExtraHosts = import (pkgs.runCommand "cjdns-hosts" {}
-    # Generate a builder that produces an output usable as a Nix string value
-    ''
-      exec >$out
-      echo \'\'
-      ${concatStringsSep "\n" (mapAttrsToList (k: v:
-          optionalString (v.hostname != "")
-            "echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}")
-          (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
-      echo \'\'
-    '');
-
-  parseModules = x:
-    x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; };
+  # check for the required attributes, otherwise
+  # permit attributes not undefined here
+  checkPeers = x:
+    x // {
+      connectTo = mapAttrs
+        (name: value:
+          if !hasAttr "publicKey" value then abort "cjdns peer ${name} missing a publicKey" else
+          if !hasAttr "password"  value then abort "cjdns peer ${name} missing a password"  else
+          value
+        )
+      x.connectTo;
+    };
 
   # would be nice to  merge 'cfg' with a //,
   # but the json nesting is wacky.
@@ -53,8 +44,8 @@ let
     };
     authorizedPasswords = map (p: { password = p; }) cfg.authorizedPasswords;
     interfaces = {
-      ETHInterface = if (cfg.ETHInterface.bind != "") then [ (parseModules cfg.ETHInterface) ] else [ ];
-      UDPInterface = if (cfg.UDPInterface.bind != "") then [ (parseModules cfg.UDPInterface) ] else [ ];
+      ETHInterface = if (cfg.ETHInterface.bind != "") then [ (checkPeers cfg.ETHInterface) ] else [ ];
+      UDPInterface = if (cfg.UDPInterface.bind != "") then [ (checkPeers cfg.UDPInterface) ] else [ ];
     };
 
     privateKey = "@CJDNS_PRIVATE_KEY@";
@@ -134,12 +125,12 @@ in
           '';
          };
         connectTo = mkOption {
-          type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
+          type = types.attrsOf (types.attrsOf types.str);
           default = { };
           example = {
             "192.168.1.1:27313" = {
-              hostname = "homer.hype";
-              password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+              user      = "foobar";
+              password  = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
               publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
             };
           };
@@ -179,12 +170,12 @@ in
         };
 
         connectTo = mkOption {
-          type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
+          type = types.attrsOf (types.attrsOf types.str);
           default = { };
           example = {
             "01:02:03:04:05:06" = {
-              hostname = "homer.hype";
-              password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+              user      = "foobar";
+              password  = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
               publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
             };
           };
@@ -254,8 +245,6 @@ in
       };
     };
 
-    networking.extraHosts = cjdnsExtraHosts;
-
     assertions = [
       { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null );
         message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
diff --git a/nixos/modules/services/networking/dante.nix b/nixos/modules/services/networking/dante.nix
new file mode 100644
index 000000000000..8f4e15223ab0
--- /dev/null
+++ b/nixos/modules/services/networking/dante.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+with lib;
+
+let
+  cfg = config.services.dante;
+  confFile = pkgs.writeText "dante-sockd.conf" ''
+    user.privileged: root
+    user.unprivileged: dante
+
+    ${cfg.config}
+  '';
+in
+
+{
+  meta = {
+    maintainers = with maintainers; [ arobyn ];
+  };
+
+  options = {
+    services.dante = {
+      enable = mkEnableOption "Dante SOCKS proxy";
+
+      config = mkOption {
+        default     = null;
+        type        = types.str;
+        description = ''
+          Contents of Dante's configuration file
+          NOTE: user.privileged/user.unprivileged are set by the service
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [
+      { assertion   = cfg.config != null;
+        message     = "please provide Dante configuration file contents";
+      }
+    ];
+
+    users.users.dante = {
+      description   = "Dante SOCKS proxy daemon user";
+      isSystemUser  = true;
+      group         = "dante";
+    };
+    users.groups.dante = {};
+
+    systemd.services.dante = {
+      description   = "Dante SOCKS v4 and v5 compatible proxy server";
+      after         = [ "network.target" ];
+      wantedBy      = [ "multi-user.target" ];
+
+      serviceConfig = {
+        Type        = "simple";
+        ExecStart   = "${pkgs.dante}/bin/sockd -f ${confFile}";
+        ExecReload  = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        Restart     = "always";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/flannel.nix b/nixos/modules/services/networking/flannel.nix
index 28b6c4f657dd..ca47a18bc1f6 100644
--- a/nixos/modules/services/networking/flannel.nix
+++ b/nixos/modules/services/networking/flannel.nix
@@ -20,6 +20,7 @@ in {
       description = "Package to use for flannel";
       type = types.package;
       default = pkgs.flannel.bin;
+      defaultText = "pkgs.flannel.bin";
     };
 
     publicIp = mkOption {
diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix
index 51f95af48029..fd4545e88e2d 100644
--- a/nixos/modules/services/networking/hostapd.nix
+++ b/nixos/modules/services/networking/hostapd.nix
@@ -86,7 +86,7 @@ in
 
       hwMode = mkOption {
         default = "g";
-        type = types.string;
+        type = types.enum [ "a" "b" "g" ];
         description = ''
           Operation mode.
           (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g).
@@ -152,9 +152,6 @@ in
   config = mkIf cfg.enable {
 
     assertions = [
-      { assertion = (cfg.hwMode == "a" || cfg.hwMode == "b" || cfg.hwMode == "g");
-        message = "hwMode must be a/b/g";
-      }
       { assertion = (cfg.channel >= 1 && cfg.channel <= 13);
         message = "channel must be between 1 and 13";
       }];
diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
index dca8ccac7627..7eebecb23b00 100644
--- a/nixos/modules/services/networking/nntp-proxy.nix
+++ b/nixos/modules/services/networking/nntp-proxy.nix
@@ -148,11 +148,11 @@ in
       };
 
       verbosity = mkOption {
-        type = types.str;
+        type = types.enum [ "error" "warning" "notice" "info" "debug" ];
         default = "info";
         example = "error";
         description = ''
-          Verbosity level (error, warning, notice, info, debug)
+          Verbosity level
         '';
       };
 
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index ccfd219620cf..481e267f6c38 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -345,12 +345,10 @@ let
       };
 
       rrlWhitelist = mkOption {
-        type = types.listOf types.str;
+        type = with types; listOf (enum [ "nxdomain" "error" "referral" "any" "rrsig" "wildcard" "nodata" "dnskey" "positive" "all" ]);
         default = [];
         description = ''
           Whitelists the given rrl-types.
-          The RRL classification types are:  nxdomain,  error, referral, any,
-          rrsig, wildcard, nodata, dnskey, positive, all
         '';
       };
 
diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix
index 3f0906fdb80d..edcc12170b20 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -26,10 +26,11 @@ in
       package = mkOption {
         type = types.package;
         default = pkgs.kde4.quasselDaemon;
+        defaultText = "pkgs.kde4.quasselDaemon";
         description = ''
           The package of the quassel daemon.
         '';
-        example = pkgs.quasselDaemon;
+        example = literalExample "pkgs.quasselDaemon";
       };
 
       interfaces = mkOption {
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index 81941ce1cfb6..073391ffdbbc 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -228,8 +228,6 @@ in
 
   config = mkIf cfg.enable {
 
-    programs.ssh.setXAuthLocation = mkForce cfg.forwardX11;
-
     users.extraUsers.sshd =
       { isSystemUser = true;
         description = "SSH privilege separation user";
diff --git a/nixos/modules/services/search/hound.nix b/nixos/modules/services/search/hound.nix
index 1226cba682ec..a94a851e80ec 100644
--- a/nixos/modules/services/search/hound.nix
+++ b/nixos/modules/services/search/hound.nix
@@ -50,6 +50,8 @@ in {
 
       package = mkOption {
         default = pkgs.hound;
+        defaultText = "pkgs.hound";
+        type = types.package;
         description = ''
           Package for running hound.
         '';
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index e4e5c1253b77..b045e140546d 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -3,26 +3,37 @@ with lib;
 let
   clamavUser = "clamav";
   stateDir = "/var/lib/clamav";
-  runDir = "/var/run/clamav";
-  logDir = "/var/log/clamav";
+  runDir = "/run/clamav";
   clamavGroup = clamavUser;
   cfg = config.services.clamav;
+  pkg = pkgs.clamav;
+
   clamdConfigFile = pkgs.writeText "clamd.conf" ''
     DatabaseDirectory ${stateDir}
     LocalSocket ${runDir}/clamd.ctl
-    LogFile ${logDir}/clamav.log
     PidFile ${runDir}/clamd.pid
+    TemporaryDirectory /tmp
     User clamav
+    Foreground yes
 
     ${cfg.daemon.extraConfig}
   '';
-  pkg = pkgs.clamav.override { freshclamConf = cfg.updater.config; };
+
+  freshclamConfigFile = pkgs.writeText "freshclam.conf" ''
+    DatabaseDirectory ${stateDir}
+    Foreground yes
+    Checks ${toString cfg.updater.frequency}
+
+    ${cfg.updater.extraConfig}
+
+    DatabaseMirror database.clamav.net
+  '';
 in
 {
   options = {
     services.clamav = {
       daemon = {
-        enable = mkEnableOption "clamd daemon";
+        enable = mkEnableOption "ClamAV clamd daemon";
 
         extraConfig = mkOption {
           type = types.lines;
@@ -34,16 +45,27 @@ in
         };
       };
       updater = {
-        enable = mkEnableOption "freshclam updater";
+        enable = mkEnableOption "ClamAV freshclam updater";
 
         frequency = mkOption {
+          type = types.int;
           default = 12;
           description = ''
             Number of database checks per day.
           '';
         };
 
-        config = mkOption {
+        interval = mkOption {
+          type = types.str;
+          default = "hourly";
+          description = ''
+            How often freshclam is invoked. See systemd.time(7) for more
+            information about the format.
+          '';
+        };
+
+        extraConfig = mkOption {
+          type = types.lines;
           default = "";
           description = ''
             Extra configuration for freshclam. Contents will be added verbatim to the
@@ -68,50 +90,53 @@ in
       gid = config.ids.gids.clamav;
     };
 
-    services.clamav.updater.config = mkIf cfg.updater.enable ''
-      DatabaseDirectory ${stateDir}
-      Foreground yes
-      Checks ${toString cfg.updater.frequency}
-      DatabaseMirror database.clamav.net
-    '';
+    environment.etc."clamav/freshclam.conf".source = freshclamConfigFile;
+    environment.etc."clamav/clamd.conf".source = clamdConfigFile;
 
-    systemd.services.clamd = mkIf cfg.daemon.enable {
+    systemd.services.clamav-daemon = mkIf cfg.daemon.enable {
       description = "ClamAV daemon (clamd)";
-      path = [ pkg ];
-      after = [ "network.target" "freshclam.service" ];
-      requires = [ "freshclam.service" ];
+      after = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
+      requires = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
       wantedBy = [ "multi-user.target" ];
+      restartTriggers = [ clamdConfigFile ];
+
       preStart = ''
-        mkdir -m 0755 -p ${logDir}
         mkdir -m 0755 -p ${runDir}
-        chown ${clamavUser}:${clamavGroup} ${logDir}
         chown ${clamavUser}:${clamavGroup} ${runDir}
       '';
+
       serviceConfig = {
-        ExecStart = "${pkg}/bin/clamd --config-file=${clamdConfigFile}";
-        Type = "forking";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        Restart = "on-failure";
-        RestartSec = "10s";
-        StartLimitInterval = "1min";
+        ExecStart = "${pkg}/bin/clamd";
+        ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
+        PrivateNetwork = "yes";
       };
     };
 
-    systemd.services.freshclam = mkIf cfg.updater.enable {
-      description = "ClamAV updater (freshclam)";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      path = [ pkg ];
+    systemd.timers.clamav-freshclam = mkIf cfg.updater.enable {
+      description = "Timer for ClamAV virus database updater (freshclam)";
+      wantedBy = [ "timers.target" ];
+      timerConfig = {
+        OnCalendar = cfg.updater.interval;
+        Unit = "clamav-freshclam.service";
+      };
+    };
+
+    systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
+      description = "ClamAV virus database updater (freshclam)";
+      restartTriggers = [ freshclamConfigFile ];
+
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
         chown ${clamavUser}:${clamavGroup} ${stateDir}
       '';
+
       serviceConfig = {
-        ExecStart = "${pkg}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        Restart = "on-failure";
-        RestartSec = "10s";
-        StartLimitInterval = "1min";
+        Type = "oneshot";
+        ExecStart = "${pkg}/bin/freshclam";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
       };
     };
   };
diff --git a/nixos/modules/services/torrent/opentracker.nix b/nixos/modules/services/torrent/opentracker.nix
index d86b9fea2d79..74f443381d92 100644
--- a/nixos/modules/services/torrent/opentracker.nix
+++ b/nixos/modules/services/torrent/opentracker.nix
@@ -13,6 +13,7 @@ in {
         opentracker package to use
       '';
       default = pkgs.opentracker;
+      defaultText = "pkgs.opentracker";
     };
 
     extraOptions = mkOption {
diff --git a/nixos/modules/services/web-apps/quassel-webserver.nix b/nixos/modules/services/web-apps/quassel-webserver.nix
index 7de9480d4c46..d19e4bc58277 100644
--- a/nixos/modules/services/web-apps/quassel-webserver.nix
+++ b/nixos/modules/services/web-apps/quassel-webserver.nix
@@ -31,6 +31,8 @@ in {
       };
       pkg = mkOption {
         default = pkgs.quassel-webserver;
+        defaultText = "pkgs.quassel-webserver";
+        type = types.package;
         description = "The quassel-webserver package";
       };
       quasselCoreHost = mkOption {
diff --git a/nixos/modules/services/x11/compton.nix b/nixos/modules/services/x11/compton.nix
index bda4eec01026..7cbca1dcddfd 100644
--- a/nixos/modules/services/x11/compton.nix
+++ b/nixos/modules/services/x11/compton.nix
@@ -188,6 +188,7 @@ in {
     package = mkOption {
       type = types.package;
       default = pkgs.compton;
+      defaultText = "pkgs.compton";
       example = literalExample "pkgs.compton";
       description = ''
         Compton derivation to use.
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index bc010d1ce1cf..9b51b92faa4d 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -22,6 +22,15 @@ in
         description = "Enable the Plasma 5 (KDE 5) desktop environment.";
       };
 
+      enableQt4Support = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable support for Qt 4-based applications. Particularly, install the
+          Qt 4 version of the Breeze theme and a default backend for Phonon.
+        '';
+      };
+
     };
 
   };
@@ -105,7 +114,7 @@ in
         kde5.sonnet
         kde5.threadweaver
 
-        kde5.breeze
+        kde5.breeze-qt5
         kde5.kactivitymanagerd
         kde5.kde-cli-tools
         kde5.kdecoration
@@ -141,13 +150,12 @@ in
         kde5.konsole
         kde5.print-manager
 
-        # Oxygen icons moved to KDE Frameworks 5.16 and later.
-        (kde5.oxygen-icons or kde5.oxygen-icons5)
+        # Install Breeze icons if available
+        (kde5.breeze-icons or kde5.oxygen-icons5 or kde5.oxygen-icons)
         pkgs.hicolor_icon_theme
 
-        kde5.kde-gtk-config
+        kde5.kde-gtk-config kde5.breeze-gtk
 
-        pkgs.phonon-backend-gstreamer
         pkgs.qt5.phonon-backend-gstreamer
       ]
 
@@ -155,15 +163,14 @@ in
       # If it is not available, Orion is very similar to Breeze.
       ++ lib.optional (!(lib.hasAttr "breeze-gtk" kde5)) pkgs.orion
 
-      # Install Breeze icons if available
-      ++ lib.optional (lib.hasAttr "breeze-icons" kde5) kde5.breeze-icons
-
       # Install activity manager if available
       ++ lib.optional (lib.hasAttr "kactivitymanagerd" kde5) kde5.kactivitymanagerd
 
       # frameworkintegration was split with plasma-integration in Plasma 5.6
       ++ lib.optional (lib.hasAttr "plasma-integration" kde5) kde5.plasma-integration
 
+      ++ lib.optionals cfg.enableQt4Support [ kde5.breeze-qt4 pkgs.phonon-backend-gstreamer ]
+
       # Optional hardware support features
       ++ lib.optional config.hardware.bluetooth.enable kde5.bluedevil
       ++ lib.optional config.networking.networkmanager.enable kde5.plasma-nm
@@ -217,7 +224,6 @@ in
         kde5.ecm # for the setup-hook
         kde5.plasma-workspace
         kde5.breeze-icons
-        (kde5.oxygen-icons or kde5.oxygen-icons5)
       ];
     };
 
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 36daf55a36a5..dda8d0f7629e 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -27,7 +27,6 @@ let
     ${cfg.stopScript}
   '';
 
-
   cfgFile = pkgs.writeText "sddm.conf" ''
     [General]
     HaltCommand=${pkgs.systemd}/bin/systemctl poweroff
@@ -47,7 +46,7 @@ let
     HideShells=/run/current-system/sw/bin/nologin
 
     [X11]
-    MinimumVT=${toString xcfg.tty}
+    MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)}
     ServerPath=${xserverWrapper}
     XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
     SessionCommand=${dmcfg.session.script}
@@ -254,5 +253,10 @@ in
 
     users.extraGroups.sddm.gid = config.ids.gids.sddm;
 
+    services.dbus.packages = [ sddm.unwrapped ];
+
+    # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
+    services.xserver.tty = null;
+    services.xserver.display = null;
   };
 }
diff --git a/nixos/modules/services/x11/window-managers/bspwm-unstable.nix b/nixos/modules/services/x11/window-managers/bspwm-unstable.nix
deleted file mode 100644
index 3282e0d0851f..000000000000
--- a/nixos/modules/services/x11/window-managers/bspwm-unstable.nix
+++ /dev/null
@@ -1,48 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.xserver.windowManager.bspwm-unstable;
-in
-
-{
-  options = {
-    services.xserver.windowManager.bspwm-unstable = {
-        enable = mkEnableOption "bspwm-unstable";
-        startThroughSession = mkOption {
-            type = with types; bool;
-            default = false;
-            description = "
-                Start the window manager through the script defined in 
-                sessionScript. Defaults to the the bspwm-session script
-                provided by bspwm
-            ";
-        };
-        sessionScript = mkOption {
-            default = "${pkgs.bspwm-unstable}/bin/bspwm-session";
-            defaultText = "(pkgs.bspwm-unstable)/bin/bspwm-session";
-            description = "
-                The start-session script to use. Defaults to the
-                provided bspwm-session script from the bspwm package.
-
-                Does nothing unless `bspwm.startThroughSession` is enabled
-            ";
-        };
-    };
-  };
-
-  config = mkIf cfg.enable {
-    services.xserver.windowManager.session = singleton {
-      name = "bspwm-unstable";
-      start = if cfg.startThroughSession
-        then cfg.sessionScript
-        else ''
-            export _JAVA_AWT_WM_NONREPARENTING=1
-            SXHKD_SHELL=/bin/sh ${pkgs.sxhkd-unstable}/bin/sxhkd -f 100 &
-            ${pkgs.bspwm-unstable}/bin/bspwm
-        '';
-    };
-    environment.systemPackages = [ pkgs.bspwm-unstable ];
-  };
-}
diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
index 03a1b7a72e88..6783ac3479e6 100644
--- a/nixos/modules/services/x11/window-managers/bspwm.nix
+++ b/nixos/modules/services/x11/window-managers/bspwm.nix
@@ -9,40 +9,69 @@ in
 {
   options = {
     services.xserver.windowManager.bspwm = {
-        enable = mkEnableOption "bspwm";
-        startThroughSession = mkOption {
-            type = with types; bool;
-            default = false;
-            description = "
-                Start the window manager through the script defined in 
-                sessionScript. Defaults to the the bspwm-session script
-                provided by bspwm
-            ";
-        };
-        sessionScript = mkOption {
-            default = "${pkgs.bspwm}/bin/bspwm-session";
-            defaultText = "(pkgs.bspwm)/bin/bspwm-session";
-            description = "
-                The start-session script to use. Defaults to the
-                provided bspwm-session script from the bspwm package.
+      enable = mkEnableOption "bspwm";
+
+      package = mkOption {
+        type        = types.package;
+        default     = pkgs.bspwm;
+        defaultText = "pkgs.bspwm";
+        example     = "pkgs.bspwm-unstable";
+        description = ''
+          bspwm package to use.
+        '';
+      };
+      configFile = mkOption {
+        type        = with types; nullOr path;
+        example     = "${pkgs.bspwm}/share/doc/bspwm/examples/bspwmrc";
+        default     = null;
+        description = ''
+          Path to the bspwm configuration file.
+          If null, $HOME/.config/bspwm/bspwmrc will be used.
+        '';
+      };
 
-                Does nothing unless `bspwm.startThroughSession` is enabled
-            ";
+      sxhkd = {
+        package = mkOption {
+          type        = types.package;
+          default     = pkgs.sxhkd;
+          defaultText = "pkgs.sxhkd";
+          example     = "pkgs.sxhkd-unstable";
+          description = ''
+            sxhkd package to use.
+          '';
         };
+        configFile = mkOption {
+          type        = with types; nullOr path;
+          example     = "${pkgs.bspwm}/share/doc/bspwm/examples/sxhkdrc";
+          default     = null;
+          description = ''
+            Path to the sxhkd configuration file.
+            If null, $HOME/.config/sxhkd/sxhkdrc will be used.
+          '';
+        };
+      };
     };
   };
 
   config = mkIf cfg.enable {
     services.xserver.windowManager.session = singleton {
-      name = "bspwm";
-      start = if cfg.startThroughSession
-        then cfg.sessionScript
-        else ''
-            export _JAVA_AWT_WM_NONREPARENTING=1
-            SXHKD_SHELL=/bin/sh ${pkgs.sxhkd}/bin/sxhkd -f 100 &
-            ${pkgs.bspwm}/bin/bspwm
-        '';
+      name  = "bspwm";
+      start = ''
+        export _JAVA_AWT_WM_NONREPARENTING=1
+        SXHKD_SHELL=/bin/sh ${cfg.sxhkd.package}/bin/sxhkd ${optionalString (cfg.sxhkd.configFile != null) "-c \"${cfg.sxhkd.configFile}\""} &
+        ${cfg.package}/bin/bspwm ${optionalString (cfg.configFile != null) "-c \"${cfg.configFile}\""}
+        waitPID=$!
+      '';
     };
-    environment.systemPackages = [ pkgs.bspwm ];
+    environment.systemPackages = [ cfg.package ];
   };
+
+  imports = [
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm-unstable" "enable" ]
+     "Use services.xserver.windowManager.bspwm.enable and set services.xserver.windowManager.bspwm.package to pkgs.bspwm-unstable to use the unstable version of bspwm.")
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm" "startThroughSession" ]
+     "bspwm package does not provide bspwm-session anymore.")
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm" "sessionScript" ]
+     "bspwm package does not provide bspwm-session anymore.")
+  ];
 }
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index dabe2c26a72f..f005decfa33c 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -10,7 +10,6 @@ in
   imports = [
     ./afterstep.nix
     ./bspwm.nix
-    ./bspwm-unstable.nix
     ./compiz.nix
     ./dwm.nix
     ./exwm.nix
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
index cfe9439b688c..f9c75e80db41 100644
--- a/nixos/modules/services/x11/window-managers/i3.nix
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -3,52 +3,58 @@
 with lib;
 
 let
-  wmCfg = config.services.xserver.windowManager;
+  cfg = config.services.xserver.windowManager.i3;
+in
+
+{
+  options.services.xserver.windowManager.i3 = {
+    enable = mkEnableOption "i3 window manager";
 
-  i3option = name: {
-    enable = mkEnableOption name;
     configFile = mkOption {
-      default = null;
-      type = types.nullOr types.path;
+      default     = null;
+      type        = with types; nullOr path;
       description = ''
         Path to the i3 configuration file.
         If left at the default value, $HOME/.i3/config will be used.
       '';
     };
+
     extraSessionCommands = mkOption {
-      default = "";
-      type = types.lines;
+      default     = "";
+      type        = types.lines;
       description = ''
         Shell commands executed just before i3 is started.
       '';
     };
+
+    package = mkOption {
+      type        = types.package;
+      default     = pkgs.i3;
+      defaultText = "pkgs.i3";
+      example     = "pkgs.i3-gaps";
+      description = ''
+        i3 package to use.
+      '';
+    };
   };
 
-  i3config = name: pkg: cfg: {
+  config = mkIf cfg.enable {
     services.xserver.windowManager.session = [{
-      inherit name;
+      name  = "i3";
       start = ''
         ${cfg.extraSessionCommands}
 
-        ${pkg}/bin/i3 ${optionalString (cfg.configFile != null)
+        ${cfg.package}/bin/i3 ${optionalString (cfg.configFile != null)
           "-c \"${cfg.configFile}\""
         } &
         waitPID=$!
       '';
     }];
-    environment.systemPackages = [ pkg ];
-  };
-
-in
-
-{
-  options.services.xserver.windowManager = {
-    i3 = i3option "i3";
-    i3-gaps = i3option "i3-gaps";
+    environment.systemPackages = [ cfg.package ];
   };
 
-  config = mkMerge [
-    (mkIf wmCfg.i3.enable (i3config "i3" pkgs.i3 wmCfg.i3))
-    (mkIf wmCfg.i3-gaps.enable (i3config "i3-gaps" pkgs.i3-gaps wmCfg.i3-gaps))
+  imports = [
+    (mkRemovedOptionModule [ "services" "xserver" "windowManager" "i3-gaps" "enable" ]
+      "Use services.xserver.windowManager.i3.enable and set services.xserver.windowManager.i3.package to pkgs.i3-gaps to use i3-gaps.")
   ];
 }
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index a8c7d4b3ee5e..59ecaf8d5a6d 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -122,7 +122,7 @@ in
 
       mkdir -p /root/.ssh
       ${concatStrings (map (key: ''
-        echo -n ${escapeShellArg key} >> /root/.ssh/authorized_keys
+        echo ${escapeShellArg key} >> /root/.ssh/authorized_keys
       '') cfg.authorizedKeys)}
 
       dropbear -s -j -k -E -m -p ${toString cfg.port}
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index 17c842ddc533..294fc1988e9f 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -53,7 +53,7 @@ let
       inherit (args) devices;
       inherit (efi) canTouchEfiVariables;
       inherit (cfg)
-        version extraConfig extraPerEntryConfig extraEntries
+        version extraConfig extraPerEntryConfig extraEntries forceInstall 
         extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels
         default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios;
       path = (makeBinPath ([
@@ -403,6 +403,16 @@ in
         '';
       };
 
+      forceInstall = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to try and forcibly install GRUB even if problems are
+          detected. It is not recommended to enable this unless you know what
+          you are doing.
+        '';
+      };
+
       trustedBoot = {
 
         enable = mkOption {
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index b93395300b72..24442ca12a30 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -65,6 +65,7 @@ my $efiSysMountPoint = get("efiSysMountPoint");
 my $gfxmodeEfi = get("gfxmodeEfi");
 my $gfxmodeBios = get("gfxmodeBios");
 my $bootloaderId = get("bootloaderId");
+my $forceInstall = get("forceInstall");
 $ENV{'PATH'} = get("path");
 
 die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2;
@@ -531,13 +532,14 @@ if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) {
     foreach my $dev (@deviceTargets) {
         next if $dev eq "nodev";
         print STDERR "installing the GRUB $grubVersion boot loader on $dev...\n";
-        if ($grubTarget eq "") {
-            system("$grub/sbin/grub-install", "--recheck", "--root-directory=$tmpDir", Cwd::abs_path($dev)) == 0
-                or die "$0: installation of GRUB on $dev failed\n";
-        } else {
-            system("$grub/sbin/grub-install", "--recheck", "--root-directory=$tmpDir", "--target=$grubTarget", Cwd::abs_path($dev)) == 0
-                or die "$0: installation of GRUB on $dev failed\n";
+        my @command = ("$grub/sbin/grub-install", "--recheck", "--root-directory=$tmpDir", Cwd::abs_path($dev));
+        if ($forceInstall eq "true") {
+            push @command, "--force";
+        }
+        if ($grubTarget ne "") {
+            push @command, "--target=$grubTarget";
         }
+        (system @command) == 0 or die "$0: installation of GRUB on $dev failed\n";
     }
 }
 
@@ -546,6 +548,9 @@ if (($requireNewInstall != 0) && ($efiTarget eq "no" || $efiTarget eq "both")) {
 if (($requireNewInstall != 0) && ($efiTarget eq "only" || $efiTarget eq "both")) {
     print STDERR "installing the GRUB $grubVersion EFI boot loader into $efiSysMountPoint...\n";
     my @command = ("$grubEfi/sbin/grub-install", "--recheck", "--target=$grubTargetEfi", "--boot-directory=$bootPath", "--efi-directory=$efiSysMountPoint");
+    if ($forceInstall eq "true") {
+        push @command, "--force";
+    }
     if ($canTouchEfiVariables eq "true") {
         push @command, "--bootloader-id=$bootloaderId";
     } else {
diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
index b7400e333e21..eb8ea6130972 100644
--- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
+++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix
@@ -33,7 +33,7 @@ in
 
     boot.loader.raspberryPi.version = mkOption {
       default = 2;
-      type = types.int;
+      type = types.enum [ 1 2 ];
       description = ''
       '';
     };
@@ -44,10 +44,5 @@ in
     system.build.installBootLoader = builder;
     system.boot.loader.id = "raspberrypi";
     system.boot.loader.kernelFile = platform.kernelTarget;
-    assertions = [
-      { assertion = (cfg.version == 1 || cfg.version == 2);
-        message = "loader.raspberryPi.version should be 1 or 2";
-      }
-    ];
   };
 }
diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix
index 60a587af8e9f..d45b1686c1ea 100644
--- a/nixos/modules/system/boot/plymouth.nix
+++ b/nixos/modules/system/boot/plymouth.nix
@@ -51,6 +51,10 @@ in
           url = "https://nixos.org/logo/nixos-hires.png";
           sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si";
         };
+        defaultText = ''pkgs.fetchurl {
+          url = "https://nixos.org/logo/nixos-hires.png";
+          sha256 = "1ivzgd7iz0i06y36p8m5w48fd8pjqwxhdaavc0pxs7w1g7mcy5si";
+        }'';
         description = ''
           Logo which is displayed on the splash screen.
         '';
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 1faa8abd5f7f..aaa78daeb3a3 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -782,13 +782,12 @@ in
           };
 
           type = mkOption {
-            type = types.string;
+            type = types.enum [ "managed" "ibss" "monitor" "mesh" "wds" ];
             default = "managed";
             example = "ibss";
             description = ''
-              The type of the WLAN interface. The type has to be either <literal>managed</literal>,
-              <literal>ibss</literal>, <literal>monitor</literal>, <literal>mesh</literal> or <literal>wds</literal>.
-              Also, the type has to be supported by the underlying hardware of the device.
+              The type of the WLAN interface.
+              The type has to be supported by the underlying hardware of the device.
             '';
           };
 
@@ -799,17 +798,11 @@ in
           };
 
           flags = mkOption {
-            type = types.nullOr types.string;
+            type = with types; nullOr (enum [ "none" "fcsfail" "control" "otherbss" "cook" "active" ]);
             default = null;
             example = "control";
             description = ''
-              Flags for interface of type <literal>monitor</literal>. The valid flags are:
-              none:     no special flags
-              fcsfail:  show frames with FCS errors
-              control:  show control frames
-              otherbss: show frames from other BSSes
-              cook:     use cooked mode
-              active:   use active mode (ACK incoming unicast packets)
+              Flags for interface of type <literal>monitor</literal>.
             '';
           };
 
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index aa28a25be7ac..cfc1065b7294 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -129,9 +129,12 @@ let
         --setenv HOST_ADDRESS6="$HOST_ADDRESS6" \
         --setenv LOCAL_ADDRESS6="$LOCAL_ADDRESS6" \
         --setenv PATH="$PATH" \
-        ${if cfg.additionalCapabilities != null then
+        ${if cfg.additionalCapabilities != null && cfg.additionalCapabilities != [] then
           ''--capability="${concatStringsSep " " cfg.additionalCapabilities}"'' else ""
         } \
+        ${if cfg.tmpfs != null && cfg.tmpfs != [] then
+          ''--tmpfs=${concatStringsSep " --tmpfs=" cfg.tmpfs}'' else ""
+        } \
         ${containerInit cfg} "''${SYSTEM_PATH:-/nix/var/nix/profiles/system}/init"
     '';
 
@@ -367,6 +370,7 @@ let
       hostAddress6 = null;
       localAddress = null;
       localAddress6 = null;
+      tmpfs = null;
     };
 
 in
@@ -510,6 +514,18 @@ in
               '';
             };
 
+            tmpfs = mkOption {
+              type = types.listOf types.str;
+              default = [];
+              example = [ "/var" ];
+              description = ''
+                Mounts a set of tmpfs file systems into the container.
+                Multiple paths can be specified.
+                Valid items must conform to the --tmpfs argument
+                of systemd-nspawn. See systemd-nspawn(1) for details.
+              '';
+            };
+
           } // networkOptions;
 
           config = mkMerge
diff --git a/nixos/modules/virtualisation/grow-partition.nix b/nixos/modules/virtualisation/grow-partition.nix
index abc2e766959e..5039118d78ee 100644
--- a/nixos/modules/virtualisation/grow-partition.nix
+++ b/nixos/modules/virtualisation/grow-partition.nix
@@ -24,7 +24,7 @@ with lib;
       copy_bin_and_libs ${pkgs.gnused}/bin/sed
       copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk
       copy_bin_and_libs ${pkgs.utillinux}/sbin/lsblk
-      cp -v ${pkgs.cloud-utils}/bin/growpart $out/bin/growpart
+      cp -v ${pkgs.cloud-utils}/bin/.growpart-wrapped $out/bin/growpart
       ln -s sed $out/bin/gnused
     '';
 
diff --git a/nixos/modules/virtualisation/vmware-guest.nix b/nixos/modules/virtualisation/vmware-guest.nix
index b9a4f3b11dc1..ac5f87817fe9 100644
--- a/nixos/modules/virtualisation/vmware-guest.nix
+++ b/nixos/modules/virtualisation/vmware-guest.nix
@@ -5,6 +5,7 @@ with lib;
 let
   cfg = config.services.vmwareGuest;
   open-vm-tools = pkgs.open-vm-tools;
+  xf86inputvmmouse = pkgs.xorg.xf86inputvmmouse;
 in
 {
   options = {
@@ -29,18 +30,17 @@ in
 
     services.xserver = {
       videoDrivers = mkOverride 50 [ "vmware" ];
+      modules = [ xf86inputvmmouse ];
 
       config = ''
-          Section "InputDevice"
+          Section "InputClass"
             Identifier "VMMouse"
+            MatchDevicePath "/dev/input/event*"
+            MatchProduct "ImPS/2 Generic Wheel Mouse"
             Driver "vmmouse"
           EndSection
         '';
 
-      serverLayoutSection = ''
-          InputDevice "VMMouse"
-        '';
-
       displayManager.sessionCommands = ''
           ${open-vm-tools}/bin/vmware-user-suid-wrapper
         '';
diff --git a/nixos/release.nix b/nixos/release.nix
index 639ee45b38d6..4fd48bc2477f 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -228,6 +228,7 @@ in rec {
   tests.containers-imperative = callTest tests/containers-imperative.nix {};
   tests.containers-extra_veth = callTest tests/containers-extra_veth.nix {};
   tests.containers-physical_interfaces = callTest tests/containers-physical_interfaces.nix {};
+  tests.containers-tmpfs = callTest tests/containers-tmpfs.nix {};
   tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; });
   tests.dnscrypt-proxy = callTest tests/dnscrypt-proxy.nix { system = "x86_64-linux"; };
   tests.ecryptfs = callTest tests/ecryptfs.nix {};
diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix
index f61c82b916ad..f32ec52dfc26 100644
--- a/nixos/tests/cjdns.nix
+++ b/nixos/tests/cjdns.nix
@@ -54,7 +54,7 @@ import ./make-test.nix ({ pkgs, ...} : {
           services.cjdns =
             { UDPInterface =
                 { bind = "0.0.0.0:1024";
-                  connectTo."192.168.0.1:1024}" =
+                  connectTo."192.168.0.1:1024" =
                     { password = carolPassword;
                       publicKey = carolPubKey;
                     };
diff --git a/nixos/tests/containers-tmpfs.nix b/nixos/tests/containers-tmpfs.nix
new file mode 100644
index 000000000000..564831fa2737
--- /dev/null
+++ b/nixos/tests/containers-tmpfs.nix
@@ -0,0 +1,79 @@
+# Test for NixOS' container support.
+
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "containers-bridge";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ ckampka ];
+  };
+
+  machine =
+    { config, pkgs, ... }:
+    { imports = [ ../modules/installer/cd-dvd/channel.nix ];
+      virtualisation.writableStore = true;
+      virtualisation.memorySize = 768;
+
+      containers.tmpfs =
+        {
+          autoStart = true;
+          tmpfs = [
+            # Mount var as a tmpfs
+            "/var"
+
+            # Add a nested mount inside a tmpfs
+            "/var/log"
+
+            # Add a tmpfs on a path that does not exist
+            "/some/random/path"
+          ];
+          config = { };
+        };
+
+      virtualisation.pathsInNixDB = [ pkgs.stdenv ];
+    };
+
+  testScript =
+    ''
+      $machine->waitForUnit("default.target");
+      $machine->succeed("nixos-container list") =~ /tmpfs/ or die;
+
+      # Start the tmpfs container.
+      #$machine->succeed("nixos-container status tmpfs") =~ /up/ or die;
+
+      # Verify that /var is mounted as a tmpfs
+      #$machine->succeed("nixos-container run tmpfs -- systemctl status var.mount --no-pager 2>/dev/null") =~ /What: tmpfs/ or die;
+      $machine->succeed("nixos-container run tmpfs -- mountpoint -q /var 2>/dev/null");
+
+      # Verify that /var/log is mounted as a tmpfs
+      $machine->succeed("nixos-container run tmpfs -- systemctl status var-log.mount --no-pager 2>/dev/null") =~ /What: tmpfs/ or die;
+      $machine->succeed("nixos-container run tmpfs -- mountpoint -q /var/log 2>/dev/null");
+
+      # Verify that /some/random/path is mounted as a tmpfs
+      $machine->succeed("nixos-container run tmpfs -- systemctl status some-random-path.mount --no-pager 2>/dev/null") =~ /What: tmpfs/ or die;
+      $machine->succeed("nixos-container run tmpfs -- mountpoint -q /some/random/path 2>/dev/null");
+
+      # Verify that files created in the container in a non-tmpfs directory are visible on the host.
+      # This establishes legitimacy for the following tests
+      $machine->succeed("nixos-container run tmpfs -- touch /root/test.file 2>/dev/null");
+      $machine->succeed("nixos-container run tmpfs -- ls -l  /root | grep -q test.file 2>/dev/null");
+      $machine->succeed("test -e /var/lib/containers/tmpfs/root/test.file");
+
+
+      # Verify that /some/random/path is writable and that files created there
+      # are not in the hosts container dir but in the tmpfs
+      $machine->succeed("nixos-container run tmpfs -- touch /some/random/path/test.file 2>/dev/null");
+      $machine->succeed("nixos-container run tmpfs -- test -e /some/random/path/test.file 2>/dev/null");
+
+      $machine->fail("test -e /var/lib/containers/tmpfs/some/random/path/test.file");
+
+      # Verify that files created in the hosts container dir in a path where a tmpfs file system has been mounted
+      # are not visible to the container as the do not exist in the tmpfs
+      $machine->succeed("touch /var/lib/containers/tmpfs/var/test.file");
+
+      $machine->succeed("test -e /var/lib/containers/tmpfs/var/test.file");
+      $machine->succeed("ls -l /var/lib/containers/tmpfs/var/ | grep -q test.file 2>/dev/null");
+
+      $machine->fail("nixos-container run tmpfs -- ls -l /var | grep -q test.file 2>/dev/null");
+
+    '';
+
+})