summary refs log tree commit diff
path: root/nixos/modules
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules')
-rw-r--r--nixos/modules/config/ldap.nix4
-rw-r--r--nixos/modules/config/pulseaudio.nix10
-rw-r--r--nixos/modules/config/system-path.nix1
-rw-r--r--nixos/modules/config/users-groups.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/iso-image.nix22
-rw-r--r--nixos/modules/installer/tools/nixos-install.sh2
-rw-r--r--nixos/modules/installer/tools/nixos-rebuild.sh5
-rw-r--r--nixos/modules/misc/ids.nix12
-rw-r--r--nixos/modules/module-list.nix60
-rw-r--r--nixos/modules/profiles/base.nix1
-rw-r--r--nixos/modules/programs/dconf.nix34
-rw-r--r--nixos/modules/programs/nano.nix35
-rw-r--r--nixos/modules/security/ca.nix5
-rw-r--r--nixos/modules/security/grsecurity.nix6
-rw-r--r--nixos/modules/security/rngd.nix3
-rw-r--r--nixos/modules/security/setuid-wrappers.nix3
-rw-r--r--nixos/modules/services/amqp/activemq/default.nix2
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix41
-rw-r--r--nixos/modules/services/audio/mopidy.nix118
-rw-r--r--nixos/modules/services/databases/redis.nix35
-rw-r--r--nixos/modules/services/desktops/gnome3/at-spi2-core.nix7
-rw-r--r--nixos/modules/services/hardware/acpid.nix2
-rw-r--r--nixos/modules/services/hardware/tcsd.nix139
-rw-r--r--nixos/modules/services/logging/logrotate.nix16
-rw-r--r--nixos/modules/services/logging/logstash.nix4
-rw-r--r--nixos/modules/services/logging/syslog-ng.nix83
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix17
-rw-r--r--nixos/modules/services/misc/nix-ssh-serve.nix40
-rw-r--r--nixos/modules/services/misc/siproxd.nix180
-rw-r--r--nixos/modules/services/monitoring/munin.nix15
-rw-r--r--nixos/modules/services/monitoring/nagios.nix2
-rw-r--r--nixos/modules/services/monitoring/systemhealth.nix2
-rw-r--r--nixos/modules/services/network-filesystems/openafs-client/default.nix2
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix5
-rw-r--r--nixos/modules/services/networking/dhcpd.nix35
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/builder.sh4
-rw-r--r--nixos/modules/services/networking/polipo.nix118
-rw-r--r--nixos/modules/services/networking/ssh/lshd.nix3
-rw-r--r--nixos/modules/services/networking/unifi.nix88
-rw-r--r--nixos/modules/services/networking/znc.nix76
-rw-r--r--nixos/modules/services/search/elasticsearch.nix15
-rw-r--r--nixos/modules/services/security/fail2ban.nix17
-rw-r--r--nixos/modules/services/system/dbus.nix2
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix12
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mediawiki.nix4
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mercurial.nix2
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix8
-rw-r--r--nixos/modules/services/web-servers/lighttpd/cgit.nix2
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix12
-rw-r--r--nixos/modules/services/web-servers/lighttpd/gitweb.nix4
-rw-r--r--nixos/modules/services/web-servers/tomcat.nix9
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix5
-rw-r--r--nixos/modules/services/x11/desktop-managers/e18.nix43
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix25
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix151
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix2
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix9
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm.nix29
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix1
-rw-r--r--nixos/modules/system/activation/activation-script.nix5
-rw-r--r--nixos/modules/system/boot/emergency-mode.nix37
-rw-r--r--nixos/modules/system/boot/modprobe.nix23
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh13
-rw-r--r--nixos/modules/system/boot/stage-1.nix40
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh12
-rw-r--r--nixos/modules/system/boot/stage-2.nix14
-rw-r--r--nixos/modules/system/boot/systemd.nix36
-rw-r--r--nixos/modules/system/boot/tmp.nix39
-rw-r--r--nixos/modules/system/etc/etc.nix2
-rw-r--r--nixos/modules/system/etc/setup-etc.pl41
-rw-r--r--nixos/modules/tasks/filesystems.nix20
-rw-r--r--nixos/modules/tasks/filesystems/cifs.nix25
-rw-r--r--nixos/modules/tasks/filesystems/unionfs-fuse.nix13
-rw-r--r--nixos/modules/tasks/network-interfaces.nix89
-rw-r--r--nixos/modules/tasks/trackpoint.nix24
-rw-r--r--nixos/modules/tasks/tty-backgrounds-combine.sh2
-rw-r--r--nixos/modules/testing/test-instrumentation.nix16
-rw-r--r--nixos/modules/virtualisation/amazon-image.nix2
-rw-r--r--nixos/modules/virtualisation/container-config.nix2
-rw-r--r--nixos/modules/virtualisation/containers.nix92
-rw-r--r--nixos/modules/virtualisation/docker.nix109
-rw-r--r--nixos/modules/virtualisation/ec2-data.nix15
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix36
-rw-r--r--nixos/modules/virtualisation/nixos-container.pl54
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix39
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix233
87 files changed, 2134 insertions, 492 deletions
diff --git a/nixos/modules/config/ldap.nix b/nixos/modules/config/ldap.nix
index 7fcb1aaf63dd..1a01533c585b 100644
--- a/nixos/modules/config/ldap.nix
+++ b/nixos/modules/config/ldap.nix
@@ -217,9 +217,7 @@ in
     systemd.services = mkIf cfg.daemon.enable {
 
       nslcd = {
-        wantedBy = [ "nss-user-lookup.target" ];
-        before = [ "nss-user-lookup.target" ];
-        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
 
         preStart = ''
           mkdir -p /run/nslcd
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index 67e536f4fd93..96593885e5b7 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -80,12 +80,12 @@ in {
 
       package = mkOption {
         type = types.package;
-        default = pulseaudio;
-        example = literalExample "pulseaudio.override { jackaudioSupport = true; }";
+        default = pulseaudioFull;
+        example = literalExample "pulseaudioFull";
         description = ''
-          The PulseAudio derivation to use.  This can be used to enable
-          features (such as JACK support) that are not enabled in the
-          default PulseAudio in Nixpkgs.
+          The PulseAudio derivation to use.  This can be used to disable
+          features (such as JACK support, Bluetooth) that are enabled in the
+          pulseaudioFull package in Nixpkgs.
         '';
       };
 
diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix
index 2ea998bbb635..6b4c38172e95 100644
--- a/nixos/modules/config/system-path.nix
+++ b/nixos/modules/config/system-path.nix
@@ -110,6 +110,7 @@ in
         "/man"
         "/sbin"
         "/share/emacs"
+        "/share/vim-plugins"
         "/share/org"
         "/share/info"
         "/share/terminfo"
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 5de81a773424..7783f13b14b1 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -404,7 +404,7 @@ in {
         uid = ids.uids.root;
         description = "System administrator";
         home = "/root";
-        shell = cfg.defaultUserShell;
+        shell = mkDefault cfg.defaultUserShell;
         group = "root";
         extraGroups = [ "grsecurity" ];
         hashedPassword = mkDefault config.security.initialRootPassword;
diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix
index 28c42d64f6fb..d43fa2203818 100644
--- a/nixos/modules/installer/cd-dvd/iso-image.nix
+++ b/nixos/modules/installer/cd-dvd/iso-image.nix
@@ -179,7 +179,6 @@ in
 
     fileSystems."/" =
       { fsType = "tmpfs";
-        device = "none";
         options = "mode=0755";
       };
 
@@ -192,6 +191,8 @@ in
         noCheck = true;
       };
 
+    # In stage 1, mount a tmpfs on top of /nix/store (the squashfs
+    # image) to make this a live CD.
     fileSystems."/nix/.ro-store" =
       { fsType = "squashfs";
         device = "/iso/nix-store.squashfs";
@@ -201,23 +202,20 @@ in
 
     fileSystems."/nix/.rw-store" =
       { fsType = "tmpfs";
-        device = "none";
         options = "mode=0755";
         neededForBoot = true;
       };
 
+    fileSystems."/nix/store" =
+      { fsType = "unionfs-fuse";
+        device = "unionfs";
+        options = "allow_other,cow,nonempty,chroot=/mnt-root,max_files=32768,hide_meta_files,dirs=/nix/.rw-store=rw:/nix/.ro-store=ro";
+      };
+
     boot.initrd.availableKernelModules = [ "squashfs" "iso9660" ];
 
     boot.initrd.kernelModules = [ "loop" ];
 
-    # In stage 1, mount a tmpfs on top of /nix/store (the squashfs
-    # image) to make this a live CD.
-    boot.initrd.postMountCommands =
-      ''
-        mkdir -p $targetRoot/nix/store
-        unionfs -o allow_other,cow,nonempty,chroot=$targetRoot,max_files=32768 /nix/.rw-store=RW:/nix/.ro-store=RO $targetRoot/nix/store
-      '';
-
     # Closures to be copied to the Nix store on the CD, namely the init
     # script and the top-level system configuration directory.
     isoImage.storeContents =
@@ -313,8 +311,8 @@ in
       '';
 
     # Add vfat support to the initrd to enable people to copy the
-    # contents of the CD to a bootable USB stick. Need unionfs-fuse for union mounts
-    boot.initrd.supportedFilesystems = [ "vfat" "unionfs-fuse" ];
+    # contents of the CD to a bootable USB stick.
+    boot.initrd.supportedFilesystems = [ "vfat" ];
 
   };
 
diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh
index 9d62ba131dc7..a55eda1cb8fd 100644
--- a/nixos/modules/installer/tools/nixos-install.sh
+++ b/nixos/modules/installer/tools/nixos-install.sh
@@ -81,7 +81,7 @@ mount -t tmpfs -o "mode=0755" none $mountPoint/var/setuid-wrappers
 rm -rf $mountPoint/var/run
 ln -s /run $mountPoint/var/run
 rm -f $mountPoint/etc/{resolv.conf,hosts}
-cp -f /etc/resolv.conf /etc/hosts $mountPoint/etc/
+cp -Lf /etc/resolv.conf /etc/hosts $mountPoint/etc/
 
 
 if [ -n "$runChroot" ]; then
diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh
index be37e61151aa..52b64c37578e 100644
--- a/nixos/modules/installer/tools/nixos-rebuild.sh
+++ b/nixos/modules/installer/tools/nixos-rebuild.sh
@@ -225,7 +225,10 @@ fi
 # If we're not just building, then make the new configuration the boot
 # default and/or activate it now.
 if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then
-    $pathToConfig/bin/switch-to-configuration "$action"
+    if ! $pathToConfig/bin/switch-to-configuration "$action"; then
+        echo "warning: there were error switching to the new configuration" >&2
+        exit 1
+    fi
 fi
 
 
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 31de680514e6..9f509ba8cb94 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -136,6 +136,12 @@
       nsd = 126;
       gitolite = 127;
       znc = 128;
+      polipo = 129;
+      mopidy = 130;
+      unifi = 131;
+      gdm = 132;
+      dhcpd = 133;
+      siproxd = 134;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -246,6 +252,12 @@
       nsd = 126;
       firebird = 127;
       znc = 128;
+      polipo = 129;
+      mopidy = 130;
+      docker = 131;
+      gdm = 132;
+      tss = 133;
+      siproxd = 134;
 
       # When adding a gid, make sure it doesn't match an existing uid. And don't use gids above 399!
 
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index a9039eea71d4..1fc2959bd8a0 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -14,17 +14,17 @@
   ./config/power-management.nix
   ./config/pulseaudio.nix
   ./config/shells-environment.nix
-  ./config/system-environment.nix
   ./config/swap.nix
   ./config/sysctl.nix
+  ./config/system-environment.nix
   ./config/system-path.nix
   ./config/timezone.nix
   ./config/unix-odbc-drivers.nix
   ./config/users-groups.nix
   ./config/zram.nix
   ./hardware/all-firmware.nix
-  ./hardware/cpu/intel-microcode.nix
   ./hardware/cpu/amd-microcode.nix
+  ./hardware/cpu/intel-microcode.nix
   ./hardware/network/b43.nix
   ./hardware/network/intel-2100bg.nix
   ./hardware/network/intel-2200bg.nix
@@ -50,8 +50,11 @@
   ./programs/bash/bash.nix
   ./programs/bash/command-not-found.nix
   ./programs/blcr.nix
+  ./programs/dconf.nix
   ./programs/environment.nix
   ./programs/info.nix
+  ./programs/nano.nix
+  ./programs/screen.nix
   ./programs/shadow.nix
   ./programs/shell.nix
   ./programs/ssh.nix
@@ -59,7 +62,6 @@
   ./programs/venus.nix
   ./programs/wvdial.nix
   ./programs/zsh/zsh.nix
-  ./programs/screen.nix
   ./rename.nix
   ./security/apparmor.nix
   ./security/apparmor-suid.nix
@@ -79,6 +81,7 @@
   ./services/audio/alsa.nix
   ./services/audio/fuppes.nix
   ./services/audio/mpd.nix
+  ./services/audio/mopidy.nix
   ./services/backup/almir.nix
   ./services/backup/bacula.nix
   ./services/backup/mysql-backup.nix
@@ -92,15 +95,15 @@
   ./services/databases/4store.nix
   ./services/databases/couchdb.nix
   ./services/databases/firebird.nix
+  ./services/databases/influxdb.nix
   ./services/databases/memcached.nix
+  ./services/databases/monetdb.nix
   ./services/databases/mongodb.nix
-  ./services/databases/redis.nix
   ./services/databases/mysql.nix
   ./services/databases/openldap.nix
   ./services/databases/postgresql.nix
+  ./services/databases/redis.nix
   ./services/databases/virtuoso.nix
-  ./services/databases/monetdb.nix
-  ./services/databases/influxdb.nix
   ./services/desktops/accountsservice.nix
   ./services/desktops/geoclue2.nix
   ./services/desktops/gnome3/at-spi2-core.nix
@@ -124,16 +127,18 @@
   ./services/hardware/pcscd.nix
   ./services/hardware/pommed.nix
   ./services/hardware/sane.nix
+  ./services/hardware/tcsd.nix
+  ./services/hardware/thinkfan.nix
   ./services/hardware/udev.nix
   ./services/hardware/udisks2.nix
   ./services/hardware/upower.nix
-  ./services/hardware/thinkfan.nix
   ./services/logging/klogd.nix
   ./services/logging/logcheck.nix
   ./services/logging/logrotate.nix
   ./services/logging/logstash.nix
-  ./services/logging/syslogd.nix
   ./services/logging/rsyslogd.nix
+  ./services/logging/syslogd.nix
+  ./services/logging/syslog-ng.nix
   ./services/mail/dovecot.nix
   ./services/mail/freepops.nix
   ./services/mail/mail.nix
@@ -146,14 +151,15 @@
   ./services/misc/disnix.nix
   ./services/misc/felix.nix
   ./services/misc/folding-at-home.nix
-  ./services/misc/gpsd.nix
   ./services/misc/gitolite.nix
+  ./services/misc/gpsd.nix
   ./services/misc/nix-daemon.nix
   ./services/misc/nix-gc.nix
-  ./services/misc/nix-ssh-serve.nix
   ./services/misc/nixos-manual.nix
+  ./services/misc/nix-ssh-serve.nix
   ./services/misc/rippled.nix
   ./services/misc/rogue.nix
+  ./services/misc/siproxd.nix
   ./services/misc/svnserve.nix
   ./services/misc/synergy.nix
   ./services/monitoring/apcupsd.nix
@@ -179,24 +185,23 @@
   ./services/networking/bind.nix
   ./services/networking/bitlbee.nix
   ./services/networking/btsync.nix
+  ./services/networking/chrony.nix
   ./services/networking/cjdns.nix
-  ./services/networking/connman.nix
   ./services/networking/cntlm.nix
-  ./services/networking/chrony.nix
+  ./services/networking/connman.nix
   ./services/networking/ddclient.nix
   ./services/networking/dhcpcd.nix
   ./services/networking/dhcpd.nix
   ./services/networking/dnsmasq.nix
   ./services/networking/ejabberd.nix
   ./services/networking/firewall.nix
-  ./services/networking/haproxy.nix
-  ./services/networking/tcpcrypt.nix
   ./services/networking/flashpolicyd.nix
   ./services/networking/freenet.nix
   ./services/networking/git-daemon.nix
   ./services/networking/gnunet.nix
   ./services/networking/gogoclient.nix
   ./services/networking/gvpe.nix
+  ./services/networking/haproxy.nix
   ./services/networking/hostapd.nix
   ./services/networking/ifplugd.nix
   ./services/networking/iodined.nix
@@ -214,6 +219,7 @@
   ./services/networking/oidentd.nix
   ./services/networking/openfire.nix
   ./services/networking/openvpn.nix
+  ./services/networking/polipo.nix
   ./services/networking/prayer.nix
   ./services/networking/privoxy.nix
   ./services/networking/quassel.nix
@@ -224,13 +230,15 @@
   ./services/networking/sabnzbd.nix
   ./services/networking/searx.nix
   ./services/networking/spiped.nix
-  ./services/networking/supybot.nix
-  ./services/networking/syncthing.nix
   ./services/networking/ssh/lshd.nix
   ./services/networking/ssh/sshd.nix
+  ./services/networking/supybot.nix
+  ./services/networking/syncthing.nix
+  ./services/networking/tcpcrypt.nix
   ./services/networking/teamspeak3.nix
   ./services/networking/tftpd.nix
   ./services/networking/unbound.nix
+  ./services/networking/unifi.nix
   ./services/networking/vsftpd.nix
   ./services/networking/wakeonlan.nix
   ./services/networking/websockify.nix
@@ -245,11 +253,11 @@
   ./services/search/elasticsearch.nix
   ./services/search/solr.nix
   ./services/security/clamav.nix
-  ./services/security/haveged.nix
   ./services/security/fprot.nix
   ./services/security/frandom.nix
-  ./services/security/tor.nix
+  ./services/security/haveged.nix
   ./services/security/torify.nix
+  ./services/security/tor.nix
   ./services/security/torsocks.nix
   ./services/system/dbus.nix
   ./services/system/kerberos.nix
@@ -257,14 +265,14 @@
   ./services/system/uptimed.nix
   ./services/torrent/deluge.nix
   ./services/torrent/transmission.nix
-  ./services/ttys/gpm.nix
   ./services/ttys/agetty.nix
+  ./services/ttys/gpm.nix
   ./services/ttys/kmscon.nix
   ./services/web-servers/apache-httpd/default.nix
   ./services/web-servers/fcgiwrap.nix
   ./services/web-servers/jboss/default.nix
-  ./services/web-servers/lighttpd/default.nix
   ./services/web-servers/lighttpd/cgit.nix
+  ./services/web-servers/lighttpd/default.nix
   ./services/web-servers/lighttpd/gitweb.nix
   ./services/web-servers/nginx/default.nix
   ./services/web-servers/phpfpm.nix
@@ -275,26 +283,29 @@
   ./services/x11/desktop-managers/default.nix
   ./services/x11/display-managers/auto.nix
   ./services/x11/display-managers/default.nix
+  ./services/x11/display-managers/gdm.nix
   ./services/x11/display-managers/kdm.nix
-  ./services/x11/display-managers/slim.nix
   ./services/x11/display-managers/lightdm.nix
+  ./services/x11/display-managers/slim.nix
   ./services/x11/hardware/multitouch.nix
   ./services/x11/hardware/synaptics.nix
   ./services/x11/hardware/wacom.nix
+  ./services/x11/redshift.nix
   ./services/x11/window-managers/awesome.nix
   #./services/x11/window-managers/compiz.nix
   ./services/x11/window-managers/default.nix
   ./services/x11/window-managers/icewm.nix
+  ./services/x11/window-managers/bspwm.nix
   ./services/x11/window-managers/metacity.nix
   ./services/x11/window-managers/none.nix
   ./services/x11/window-managers/twm.nix
   ./services/x11/window-managers/wmii.nix
   ./services/x11/window-managers/xmonad.nix
-  ./services/x11/redshift.nix
   ./services/x11/xfs.nix
   ./services/x11/xserver.nix
   ./system/activation/activation-script.nix
   ./system/activation/top-level.nix
+  ./system/boot/emergency-mode.nix
   ./system/boot/kernel.nix
   ./system/boot/kexec.nix
   ./system/boot/loader/efi.nix
@@ -310,11 +321,14 @@
   ./system/boot/stage-1.nix
   ./system/boot/stage-2.nix
   ./system/boot/systemd.nix
+  ./system/boot/tmp.nix
   ./system/etc/etc.nix
   ./system/upstart/upstart.nix
   ./tasks/cpu-freq.nix
+  ./tasks/encrypted-devices.nix
   ./tasks/filesystems.nix
   ./tasks/filesystems/btrfs.nix
+  ./tasks/filesystems/cifs.nix
   ./tasks/filesystems/ext.nix
   ./tasks/filesystems/f2fs.nix
   ./tasks/filesystems/nfs.nix
@@ -323,7 +337,6 @@
   ./tasks/filesystems/vfat.nix
   ./tasks/filesystems/xfs.nix
   ./tasks/filesystems/zfs.nix
-  ./tasks/encrypted-devices.nix
   ./tasks/kbd.nix
   ./tasks/lvm.nix
   ./tasks/network-interfaces.nix
@@ -333,6 +346,7 @@
   ./testing/service-runner.nix
   ./virtualisation/container-config.nix
   ./virtualisation/containers.nix
+  ./virtualisation/docker.nix
   ./virtualisation/libvirtd.nix
   #./virtualisation/nova.nix
   ./virtualisation/virtualbox-guest.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 562419b3facb..6f9e3002f299 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -7,7 +7,6 @@
   # Include some utilities that are useful for installing or repairing
   # the system.
   environment.systemPackages = [
-    pkgs.subversion # for nixos-checkout
     pkgs.w3m # needed for the manual anyway
     pkgs.testdisk # useful for repairing boot problems
     pkgs.mssys # for writing Microsoft boot sectors / MBRs
diff --git a/nixos/modules/programs/dconf.nix b/nixos/modules/programs/dconf.nix
new file mode 100644
index 000000000000..1b7e20799819
--- /dev/null
+++ b/nixos/modules/programs/dconf.nix
@@ -0,0 +1,34 @@
+{ config, lib, ... }:
+
+let
+  inherit (lib) mkOption mkIf types mapAttrsToList;
+  cfg = config.programs.dconf;
+
+  mkDconfProfile = name: path:
+    { source = path; target = "dconf/profile/${name}"; };
+
+in
+{
+  ###### interface
+
+  options = {
+    programs.dconf = {
+
+      profiles = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = "Set of dconf profile files.";
+        internal = true;
+      };
+
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf (cfg.profiles != {}) {
+    environment.etc =
+      (mapAttrsToList mkDconfProfile cfg.profiles);
+  };
+
+}
diff --git a/nixos/modules/programs/nano.nix b/nixos/modules/programs/nano.nix
new file mode 100644
index 000000000000..b8803eec7be1
--- /dev/null
+++ b/nixos/modules/programs/nano.nix
@@ -0,0 +1,35 @@
+{ config, lib, ... }:
+
+let
+  cfg = config.programs.nano;
+in
+
+{
+  ###### interface
+
+  options = {
+    programs.nano = {
+
+      nanorc = lib.mkOption {
+        type = lib.types.lines;
+        default = "";
+        description = ''
+          The system-wide nano configuration.
+          See <citerefentry><refentrytitle>nanorc</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        '';
+        example = ''
+          set nowrap
+          set tabstospaces
+          set tabsize 4
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = lib.mkIf (cfg.nanorc != "") {
+    environment.etc."nanorc".text = cfg.nanorc;
+  };
+
+}
diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix
index dd4b0c529e5d..8e653cd42847 100644
--- a/nixos/modules/security/ca.nix
+++ b/nixos/modules/security/ca.nix
@@ -13,8 +13,9 @@ with lib;
       ];
 
     environment.sessionVariables =
-      { OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
-        CURL_CA_BUNDLE         = "/etc/ssl/certs/ca-bundle.crt";
+      { SSL_CERT_FILE          = "/etc/ssl/certs/ca-bundle.crt";
+        # FIXME: unneeded - remove eventually.
+        OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt";
         GIT_SSL_CAINFO         = "/etc/ssl/certs/ca-bundle.crt";
       };
 
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 3bd58218c99d..9e5983691370 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -50,7 +50,7 @@ in
           description = ''
             grsecurity configuration mode. This specifies whether
             grsecurity is auto-configured or otherwise completely
-            manually configured. Can either by
+            manually configured. Can either be
             <literal>custom</literal> or <literal>auto</literal>.
 
             <literal>auto</literal> is recommended.
@@ -64,7 +64,7 @@ in
           description = ''
             grsecurity configuration priority. This specifies whether
             the kernel configuration should emphasize speed or
-            security. Can either by <literal>security</literal> or
+            security. Can either be <literal>security</literal> or
             <literal>performance</literal>.
           '';
         };
@@ -76,7 +76,7 @@ in
           description = ''
             grsecurity system configuration. This specifies whether
             the kernel configuration should be suitable for a Desktop
-            or a Server. Can either by <literal>server</literal> or
+            or a Server. Can either be <literal>server</literal> or
             <literal>desktop</literal>.
           '';
         };
diff --git a/nixos/modules/security/rngd.nix b/nixos/modules/security/rngd.nix
index c31e57e6f6f8..4d8fabc7696e 100644
--- a/nixos/modules/security/rngd.nix
+++ b/nixos/modules/security/rngd.nix
@@ -30,7 +30,8 @@ with lib;
 
       description = "Hardware RNG Entropy Gatherer Daemon";
 
-      serviceConfig.ExecStart = "${pkgs.rng_tools}/sbin/rngd -f";
+      serviceConfig.ExecStart = "${pkgs.rng_tools}/sbin/rngd -f -v" +
+        (if config.services.tcsd.enable then " --no-tpm=1" else "");
 
       restartTriggers = [ pkgs.rng_tools ];
     };
diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix
index 4cdc1023baab..373afffd3fb5 100644
--- a/nixos/modules/security/setuid-wrappers.nix
+++ b/nixos/modules/security/setuid-wrappers.nix
@@ -97,8 +97,7 @@ in
           }:
 
           ''
-            source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}
-            if test -z "$source"; then
+            if ! source=${if source != "" then source else "$(PATH=$SETUID_PATH type -tP ${program})"}; then
                 # If we can't find the program, fall back to the
                 # system profile.
                 source=/nix/var/nix/profiles/default/bin/${program}
diff --git a/nixos/modules/services/amqp/activemq/default.nix b/nixos/modules/services/amqp/activemq/default.nix
index f731900070e4..261f97617664 100644
--- a/nixos/modules/services/amqp/activemq/default.nix
+++ b/nixos/modules/services/amqp/activemq/default.nix
@@ -12,7 +12,7 @@ let
     phases = [ "installPhase" ];
     buildInputs = [ jdk ];
     installPhase = ''
-      ensureDir $out/lib
+      mkdir -p $out/lib
       source ${activemq}/lib/classpath.env
       export CLASSPATH
       ln -s "${./ActiveMQBroker.java}" ActiveMQBroker.java
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
index bef15fb64b7f..a930098bfeec 100644
--- a/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -4,6 +4,8 @@ with lib;
 
 let
   cfg = config.services.rabbitmq;
+  config_file = pkgs.writeText "rabbitmq.config" cfg.config;
+  config_file_wo_suffix = builtins.substring 0 ((builtins.stringLength config_file) - 7) config_file;
 
 in {
   ###### interface
@@ -31,7 +33,6 @@ in {
         '';
       };
 
-
       dataDir = mkOption {
         type = types.path;
         default = "/var/lib/rabbitmq";
@@ -40,6 +41,30 @@ in {
         '';
       };
 
+      cookie = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Erlang cookie is a string of arbitrary length which must
+          be the same for several nodes to be allowed to communicate.
+          Leave empty to generate automatically.
+        '';
+      };
+
+      config = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Verbatim configuration file contents.
+          See http://www.rabbitmq.com/configure.htm
+        '';
+      };
+
+      plugins = mkOption {
+        default = [];
+        type = types.listOf types.str;
+        description = "The names of plugins to enable";
+      };
     };
   };
 
@@ -69,7 +94,10 @@ in {
         RABBITMQ_NODE_IP_ADDRESS = cfg.listenAddress;
         RABBITMQ_SERVER_START_ARGS = "-rabbit error_logger tty -rabbit sasl_error_logger false";
         SYS_PREFIX = "";
-      };
+        RABBITMQ_ENABLED_PLUGINS_FILE = pkgs.writeText "enabled_plugins" ''
+          [ ${concatStringsSep "," cfg.plugins} ].
+        '';
+      } //  optionalAttrs (cfg.config != "") { RABBITMQ_CONFIG_FILE = config_file_wo_suffix; };
 
       serviceConfig = {
         ExecStart = "${pkgs.rabbitmq_server}/sbin/rabbitmq-server";
@@ -81,6 +109,15 @@ in {
       preStart = ''
         mkdir -p ${cfg.dataDir} && chmod 0700 ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown rabbitmq:rabbitmq ${cfg.dataDir}; fi
+        
+        ${optionalString (cfg.cookie != "") ''
+            echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie
+            chmod 400 ${cfg.dataDir}/.erlang.cookie
+            chown rabbitmq:rabbitmq ${cfg.dataDir}/.erlang.cookie
+        ''}
+
+        mkdir -p /var/log/rabbitmq && chmod 0700 /var/log/rabbitmq
+        chown rabbitmq:rabbitmq /var/log/rabbitmq
       '';
     };
 
diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix
new file mode 100644
index 000000000000..5b865cf4c1be
--- /dev/null
+++ b/nixos/modules/services/audio/mopidy.nix
@@ -0,0 +1,118 @@
+{ config, lib, pkgs, ... }:
+
+with pkgs;
+with lib;
+
+let
+
+  uid = config.ids.uids.mopidy;
+  gid = config.ids.gids.mopidy;
+  cfg = config.services.mopidy;
+
+  mopidyConf = writeText "mopidy.conf" cfg.configuration;
+
+  mopidyLauncher = stdenv.mkDerivation {
+    name = "mopidy-launcher";
+    phases = [ "installPhase" ];
+    buildInputs = [ makeWrapper python ];
+    installPhase = ''
+      mkdir -p $out/bin
+      ln -s ${mopidy}/bin/mopidy $out/bin/mopidy
+      wrapProgram $out/bin/mopidy \
+        --prefix PYTHONPATH : \
+        "${concatStringsSep ":" (map (p: "$(toPythonPath ${p})") cfg.extensionPackages)}"
+    '';
+  };
+
+in {
+
+  options = {
+
+    services.mopidy = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to enable Mopidy, a music player daemon.
+        '';
+      };
+
+      dataDir = mkOption {
+        default = "/var/lib/mopidy";
+        type = types.str;
+        description = ''
+          The directory where Mopidy stores its state.
+        '';
+      };
+
+      extensionPackages = mkOption {
+        default = [];
+        type = types.listOf types.package;
+        example = [ mopidy-spotify ];
+        description = ''
+          Mopidy extensions that should be loaded by the service.
+        '';
+      };
+
+      configuration = mkOption {
+        type = types.lines;
+        description = ''
+          The configuration that Mopidy should use.
+        '';
+      };
+
+      extraConfigFiles = mkOption {
+        default = [];
+        type = types.listOf types.str;
+        description = ''
+          Extra config file read by Mopidy when the service starts.
+          Later files in the list overrides earlier configuration.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.mopidy = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "sound.target" ];
+      description = "mopidy music player daemon";
+      preStart = "mkdir -p ${cfg.dataDir} && chown -R mopidy:mopidy  ${cfg.dataDir}";
+      serviceConfig = {
+        ExecStart = "${mopidyLauncher}/bin/mopidy --config ${concatStringsSep ":" ([mopidyConf] ++ cfg.extraConfigFiles)}";
+        User = "mopidy";
+        PermissionsStartOnly = true;
+      };
+    };
+
+    systemd.services.mopidy-scan = {
+      description = "mopidy local files scanner";
+      preStart = "mkdir -p ${cfg.dataDir} && chown -R mopidy:mopidy  ${cfg.dataDir}";
+      serviceConfig = {
+        ExecStart = "${mopidyLauncher}/bin/mopidy --config ${concatStringsSep ":" ([mopidyConf] ++ cfg.extraConfigFiles)} local scan";
+        User = "mopidy";
+        PermissionsStartOnly = true;
+        Type = "oneshot";
+      };
+    };
+
+    users.extraUsers.mopidy = {
+      inherit uid;
+      group = "mopidy";
+      extraGroups = [ "audio" ];
+      description = "Mopidy daemon user";
+      home = "${cfg.dataDir}";
+    };
+
+    users.extraGroups.mopidy.gid = gid;
+
+  };
+
+}
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index 2521e356bf39..b91c389e90a2 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -38,86 +38,92 @@ in
     services.redis = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = "Whether to enable the Redis server.";
       };
 
       package = mkOption {
+        type = types.package;
         default = pkgs.redis;
         description = "Which Redis derivation to use.";
-        type = types.package;
       };
 
       user = mkOption {
+        type = types.str;
         default = "redis";
         description = "User account under which Redis runs.";
       };
 
       pidFile = mkOption {
+        type = types.path;
         default = "/var/lib/redis/redis.pid";
         description = "";
       };
 
       port = mkOption {
+        type = types.int;
         default = 6379;
         description = "The port for Redis to listen to.";
-        type = with types; int;
       };
 
       bind = mkOption {
+        type = with types; nullOr str;
         default = null; # All interfaces
         description = "The IP interface to bind to.";
         example = "127.0.0.1";
       };
 
       unixSocket = mkOption {
+        type = with types; nullOr path;
         default = null;
         description = "The path to the socket to bind to.";
         example = "/var/run/redis.sock";
       };
 
       logLevel = mkOption {
+        type = types.str;
         default = "notice"; # debug, verbose, notice, warning
         example = "debug";
         description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
-        type = with types; string;
       };
 
       logfile = mkOption {
+        type = types.str;
         default = "/dev/null";
         description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
         example = "/var/log/redis.log";
-        type = with types; string;
       };
 
       syslog = mkOption {
+        type = types.bool;
         default = true;
         description = "Enable logging to the system logger.";
-        type = with types; bool;
       };
 
       databases = mkOption {
+        type = types.int;
         default = 16;
         description = "Set the number of databases.";
-        type = with types; int;
       };
 
       save = mkOption {
+        type = with types; listOf (listOf int);
         default = [ [900 1] [300 10] [60 10000] ];
         description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
         example = [ [900 1] [300 10] [60 10000] ];
       };
 
       dbFilename = mkOption {
+        type = types.str;
         default = "dump.rdb";
         description = "The filename where to dump the DB.";
-        type = with types; string;
       };
 
       dbpath = mkOption {
+        type = types.path;
         default = "/var/lib/redis";
         description = "The DB will be written inside this directory, with the filename specified using the 'dbFilename' configuration.";
-        type = with types; string;
       };
 
       slaveOf = mkOption {
@@ -135,46 +141,47 @@ in
       };
 
       requirePass = mkOption {
+        type = with types; nullOr str;
         default = null;
         description = "Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)";
         example = "letmein!";
       };
 
       appendOnly = mkOption {
+        type = types.bool;
         default = false;
         description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
-        type = with types; bool;
       };
 
       appendOnlyFilename = mkOption {
+        type = types.str;
         default = "appendonly.aof";
         description = "Filename for the append-only file (stored inside of dbpath)";
-        type = with types; string;
       };
 
       appendFsync = mkOption {
+        type = types.str;
         default = "everysec"; # no, always, everysec
         description = "How often to fsync the append-only log, options: no, always, everysec.";
-        type = with types; string;
       };
 
       slowLogLogSlowerThan = mkOption {
+        type = types.int;
         default = 10000;
         description = "Log queries whose execution take longer than X in milliseconds.";
         example = 1000;
-        type = with types; int;
       };
 
       slowLogMaxLen = mkOption {
+        type = types.int;
         default = 128;
         description = "Maximum number of items to keep in slow log.";
-        type = with types; int;
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "";
         description = "Extra configuration options for redis.conf.";
-        type = with types; string;
       };
     };
 
diff --git a/nixos/modules/services/desktops/gnome3/at-spi2-core.nix b/nixos/modules/services/desktops/gnome3/at-spi2-core.nix
index 615f272e7b9a..6e4c59f4bb37 100644
--- a/nixos/modules/services/desktops/gnome3/at-spi2-core.nix
+++ b/nixos/modules/services/desktops/gnome3/at-spi2-core.nix
@@ -4,9 +4,6 @@
 
 with lib;
 
-let
-  gnome3 = config.environment.gnome3.packageSet;
-in
 {
 
   ###### interface
@@ -33,9 +30,9 @@ in
 
   config = mkIf config.services.gnome3.at-spi2-core.enable {
 
-    environment.systemPackages = [ gnome3.at_spi2_core ];
+    environment.systemPackages = [ pkgs.at_spi2_core ];
 
-    services.dbus.packages = [ gnome3.at_spi2_core ];
+    services.dbus.packages = [ pkgs.at_spi2_core ];
 
   };
 
diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix
index b87899e45983..a20b1a1ee3ad 100644
--- a/nixos/modules/services/hardware/acpid.nix
+++ b/nixos/modules/services/hardware/acpid.nix
@@ -6,7 +6,7 @@ let
 
   acpiConfDir = pkgs.runCommand "acpi-events" {}
     ''
-      ensureDir $out
+      mkdir -p $out
       ${
         # Generate a configuration file for each event. (You can't have
         # multiple events in one config file...)
diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix
new file mode 100644
index 000000000000..26b2c884b8f1
--- /dev/null
+++ b/nixos/modules/services/hardware/tcsd.nix
@@ -0,0 +1,139 @@
+# tcsd daemon.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+let
+
+  cfg = config.services.tcsd;
+
+  tcsdConf = pkgs.writeText "tcsd.conf" ''
+    port = 30003
+    num_threads = 10
+    system_ps_file = ${cfg.stateDir}/system.data
+    # This is the log of each individual measurement done by the system.
+    # By re-calculating the PCR registers based on this information, even
+    # finer details about the measured environment can be inferred than
+    # what is available directly from the PCR registers.
+    firmware_log_file = /sys/kernel/security/tpm0/binary_bios_measurements
+    kernel_log_file = /sys/kernel/security/ima/binary_runtime_measurements
+    #firmware_pcrs = 0,1,2,3,4,5,6,7
+    #kernel_pcrs = 10,11
+    platform_cred = ${cfg.platformCred}
+    conformance_cred = ${cfg.conformanceCred}
+    endorsement_cred = ${cfg.endorsementCred}
+    #remote_ops = create_key,random
+    #host_platform_class = server_12
+    #all_platform_classes = pc_11,pc_12,mobile_12
+  '';
+
+in
+{
+
+  ###### interface
+
+  options = {
+
+    services.tcsd = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether to enable tcsd, a Trusted Computing management service
+          that provides TCG Software Stack (TSS).  The tcsd daemon is
+          the only portal to the Trusted Platform Module (TPM), a hardware
+          chip on the motherboard.
+        '';
+      };
+
+      user = mkOption {
+        default = "tss";
+        type = types.string;
+        description = "User account under which tcsd runs.";
+      };
+
+      group = mkOption {
+        default = "tss";
+        type = types.string;
+        description = "Group account under which tcsd runs.";
+      };
+
+      stateDir = mkOption {
+	default = "/var/lib/tpm";
+        type = types.path;
+	description = ''
+          The location of the system persistent storage file.
+          The system persistent storage file holds keys and data across
+          restarts of the TCSD and system reboots. 
+	'';
+      };
+
+      platformCred = mkOption {
+        default = "${cfg.stateDir}/platform.cert";
+        type = types.path;
+        description = ''
+	  Path to the platform credential for your TPM. Your TPM
+          manufacturer may have provided you with a set of credentials
+          (certificates) that should be used when creating identities
+          using your TPM. When a user of your TPM makes an identity,
+          this credential will be encrypted as part of that process.
+          See the 1.1b TPM Main specification section 9.3 for information
+          on this process. '';
+      };
+
+      conformanceCred = mkOption {
+        default = "${cfg.stateDir}/conformance.cert";
+        type = types.path;
+        description = ''
+          Path to the conformance credential for your TPM.
+          See also the platformCred option'';
+      };
+
+      endorsementCred = mkOption {
+        default = "${cfg.stateDir}/endorsement.cert";
+        type = types.path;
+        description = ''
+          Path to the endorsement credential for your TPM.
+          See also the platformCred option'';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.trousers ];
+
+#    system.activationScripts.tcsd =
+#      ''
+#        chown ${cfg.user}:${cfg.group} ${tcsdConf}
+#      '';
+
+    systemd.services.tcsd = {
+      description = "TCSD";
+      after = [ "systemd-udev-settle.service" ];
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.trousers ];
+      preStart =
+        ''
+        mkdir -m 0700 -p ${cfg.stateDir}
+        chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir}
+        '';
+      serviceConfig.ExecStart = "${pkgs.trousers}/sbin/tcsd -f -c ${tcsdConf}";
+    };
+
+    users.extraUsers = optionalAttrs (cfg.user == "tss") (singleton
+      { name = "tss";
+        group = "tss";
+        uid = config.ids.uids.nginx;
+      });
+
+    users.extraGroups = optionalAttrs (cfg.group == "tss") (singleton
+      { name = "tss";
+        gid = config.ids.gids.nginx;
+      });
+  };
+}
diff --git a/nixos/modules/services/logging/logrotate.nix b/nixos/modules/services/logging/logrotate.nix
index 804f9a0847ff..6887ab1e8052 100644
--- a/nixos/modules/services/logging/logrotate.nix
+++ b/nixos/modules/services/logging/logrotate.nix
@@ -8,10 +8,6 @@ let
   configFile = pkgs.writeText "logrotate.conf"
     cfg.config;
 
-  cronJob = ''
-    5 * * * * root ${pkgs.logrotate}/sbin/logrotate ${configFile}
-  '';
-
 in
 {
   options = {
@@ -33,6 +29,16 @@ in
   };
 
   config = mkIf cfg.enable {
-    services.cron.systemCronJobs = [ cronJob ];
+    systemd.services.logrotate = {
+      description   = "Logrotate Service";
+      wantedBy      = [ "multi-user.target" ];
+      startAt       = "*-*-* *:05:00";
+
+      serviceConfig.Restart = "no";
+      serviceConfig.User    = "root";
+      script = ''
+        exec ${pkgs.logrotate}/sbin/logrotate ${configFile}
+      '';
+    };
   };
 }
diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix
index c92c81135704..802dd454878b 100644
--- a/nixos/modules/services/logging/logstash.nix
+++ b/nixos/modules/services/logging/logstash.nix
@@ -69,9 +69,9 @@ in
     systemd.services.logstash = with pkgs; {
       description = "Logstash Daemon";
       wantedBy = [ "multi-user.target" ];
-
+      environment = { JAVA_HOME = jre; };
       serviceConfig = {
-        ExecStart = "${jre}/bin/java -jar ${logstash} agent -f ${writeText "logstash.conf" ''
+        ExecStart = "${logstash}/bin/logstash agent -f ${writeText "logstash.conf" ''
           input {
             ${cfg.inputConfig}
           }
diff --git a/nixos/modules/services/logging/syslog-ng.nix b/nixos/modules/services/logging/syslog-ng.nix
new file mode 100644
index 000000000000..8b892a33bb7d
--- /dev/null
+++ b/nixos/modules/services/logging/syslog-ng.nix
@@ -0,0 +1,83 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.syslog-ng;
+
+  syslogngConfig = pkgs.writeText "syslog-ng.conf" ''
+    @version: 3.5
+    @include "scl.conf"
+    ${cfg.extraConfig}
+  '';
+
+  ctrlSocket = "/run/syslog-ng/syslog-ng.ctl";
+  pidFile = "/run/syslog-ng/syslog-ng.pid";
+  persistFile = "/var/syslog-ng/syslog-ng.persist";
+
+  syslogngOptions = [
+    "--foreground"
+    "--module-path=${concatStringsSep ":" (["${pkgs.syslogng}/lib/syslog-ng"] ++ cfg.extraModulePaths)}"
+    "--cfgfile=${syslogngConfig}"
+    "--control=${ctrlSocket}"
+    "--persist-file=${persistFile}"
+    "--pidfile=${pidFile}"
+  ];
+
+in {
+
+  options = {
+
+    services.syslog-ng = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the syslog-ng daemon.
+        '';
+      };
+      serviceName = mkOption {
+        type = types.str;
+        default = "syslog-ng";
+        description = ''
+          The name of the systemd service that runs syslog-ng. Set this to
+          <literal>syslog</literal> if you want journald to automatically
+          forward all logs to syslog-ng.
+        '';
+      };
+      extraModulePaths = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "${pkgs.syslogng_incubator}/lib/syslog-ng" ];
+        description = ''
+          A list of paths that should be included in syslog-ng's
+          <literal>--module-path</literal> option. They should usually
+          end in <literal>/lib/syslog-ng</literal>
+        '';
+      };
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Configuration added to the end of <literal>syslog-ng.conf</literal>.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services."${cfg.serviceName}" = {
+      wantedBy = [ "multi-user.target" ];
+      preStart = "mkdir -p /{var,run}/syslog-ng";
+      serviceConfig = {
+        Type = "notify";
+        Sockets = "syslog.socket";
+        StandardOutput = "null";
+        Restart = "on-failure";
+        ExecStart = "${pkgs.syslogng}/sbin/syslog-ng ${concatStringsSep " " syslogngOptions}";
+      };
+    };
+  };
+
+}
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 1ebd3c3643df..c98c0511b566 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -22,14 +22,11 @@ let
 
   nixConf =
     let
-      # Tricky: if we're using a chroot for builds, then we need
-      # /bin/sh in the chroot (our own compromise to purity).
-      # However, since /bin/sh is a symlink to some path in the
-      # Nix store, which furthermore has runtime dependencies on
-      # other paths in the store, we need the closure of /bin/sh
-      # in `build-chroot-dirs' - otherwise any builder that uses
-      # /bin/sh won't work.
-      binshDeps = pkgs.writeReferencesToFile config.system.build.binsh;
+      # If we're using a chroot for builds, then provide /bin/sh in
+      # the chroot as a bind-mount to bash. This means we also need to
+      # include the entire closure of bash.
+      sh = pkgs.stdenv.shell;
+      binshDeps = pkgs.writeReferencesToFile sh;
     in
       pkgs.runCommand "nix.conf" {extraOptions = cfg.extraOptions; } ''
         extraPaths=$(for i in $(cat ${binshDeps}); do if test -d $i; then echo $i; fi; done)
@@ -40,7 +37,7 @@ let
         build-users-group = nixbld
         build-max-jobs = ${toString (cfg.maxJobs)}
         build-use-chroot = ${if cfg.useChroot then "true" else "false"}
-        build-chroot-dirs = ${toString cfg.chrootDirs} $(echo $extraPaths)
+        build-chroot-dirs = ${toString cfg.chrootDirs} /bin/sh=${sh} $(echo $extraPaths)
         binary-caches = ${toString cfg.binaryCaches}
         trusted-binary-caches = ${toString cfg.trustedBinaryCaches}
         $extraOptions
@@ -253,8 +250,6 @@ in
 
   config = {
 
-    nix.chrootDirs = [ "/bin" ];
-
     environment.etc."nix/nix.conf".source = nixConf;
 
     # List of machines for distributed Nix builds in the format
diff --git a/nixos/modules/services/misc/nix-ssh-serve.nix b/nixos/modules/services/misc/nix-ssh-serve.nix
index 80e7961b1f82..d70bd855c7ff 100644
--- a/nixos/modules/services/misc/nix-ssh-serve.nix
+++ b/nixos/modules/services/misc/nix-ssh-serve.nix
@@ -1,32 +1,35 @@
 { config, lib, pkgs, ... }:
 
-let
-  serveOnly = pkgs.writeScript "nix-store-serve" ''
-    #!${pkgs.stdenv.shell}
-    if [ "$SSH_ORIGINAL_COMMAND" != "nix-store --serve" ]; then
-      echo 'Error: You are only allowed to run `nix-store --serve'\'''!' >&2
-      exit 1
-    fi
-    exec /run/current-system/sw/bin/nix-store --serve
-  '';
-
-  inherit (lib) mkIf mkOption types;
-in {
+with lib;
+
+{
   options = {
+
     nix.sshServe = {
+
       enable = mkOption {
-        description = "Whether to enable serving the nix store over ssh.";
-        default = false;
         type = types.bool;
+        default = false;
+        description = "Whether to enable serving the Nix store as a binary cache via SSH.";
+      };
+
+      keys = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "ssh-dss AAAAB3NzaC1k... alice@example.org" ];
+        description = "A list of SSH public keys allowed to access the binary cache via SSH.";
       };
+
     };
+
   };
 
   config = mkIf config.nix.sshServe.enable {
+
     users.extraUsers.nix-ssh = {
-      description = "User for running nix-store --serve.";
+      description = "Nix SSH substituter user";
       uid = config.ids.uids.nix-ssh;
-      shell = pkgs.stdenv.shell;
+      useDefaultShell = true;
     };
 
     services.openssh.enable = true;
@@ -38,8 +41,11 @@ in {
         PermitTTY no
         PermitTunnel no
         X11Forwarding no
-        ForceCommand ${serveOnly}
+        ForceCommand ${config.nix.package}/bin/nix-store --serve
       Match All
     '';
+
+    users.extraUsers.nix-ssh.openssh.authorizedKeys.keys = config.nix.sshServe.keys;
+
   };
 }
diff --git a/nixos/modules/services/misc/siproxd.nix b/nixos/modules/services/misc/siproxd.nix
new file mode 100644
index 000000000000..9e8fb6c228f2
--- /dev/null
+++ b/nixos/modules/services/misc/siproxd.nix
@@ -0,0 +1,180 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.siproxd;
+
+  conf = ''
+    daemonize = 0
+    rtp_proxy_enable = 1
+    user = siproxd
+    if_inbound  = ${cfg.ifInbound}
+    if_outbound = ${cfg.ifOutbound}
+    sip_listen_port = ${toString cfg.sipListenPort}
+    rtp_port_low    = ${toString cfg.rtpPortLow}
+    rtp_port_high   = ${toString cfg.rtpPortHigh}
+    rtp_dscp        = ${toString cfg.rtpDscp}
+    sip_dscp        = ${toString cfg.sipDscp}
+    ${optionalString (cfg.hostsAllowReg != []) "hosts_allow_reg = ${concatStringsSep "," cfg.hostsAllowReg}"}
+    ${optionalString (cfg.hostsAllowSip != []) "hosts_allow_sip = ${concatStringsSep "," cfg.hostsAllowSip}"}
+    ${optionalString (cfg.hostsDenySip != []) "hosts_deny_sip  = ${concatStringsSep "," cfg.hostsDenySip}"}
+    ${if (cfg.passwordFile != "") then "proxy_auth_pwfile = ${cfg.passwordFile}" else ""}
+    ${cfg.extraConfig}
+  '';
+
+  confFile = builtins.toFile "siproxd.conf" conf;
+
+in
+{
+  ##### interface
+
+  options = {
+
+    services.siproxd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the Siproxd SIP 
+	  proxy/masquerading daemon.
+        '';
+      };
+
+      ifInbound = mkOption {
+        type = types.str;
+        example = "eth0";
+        description = "Local network interface";
+      };
+
+      ifOutbound = mkOption {
+        type = types.str;
+        example = "ppp0";
+        description = "Public network interface";
+      };
+
+      hostsAllowReg = mkOption {
+        type = types.listOf types.str;
+	default = [ ];
+        example = [ "192.168.1.0/24" "192.168.2.0/24" ];
+	description = ''
+          Acess control list for incoming SIP registrations.
+        '';
+      };
+
+      hostsAllowSip = mkOption {
+        type = types.listOf types.str;
+	default = [ ];
+        example = [ "123.45.0.0/16" "123.46.0.0/16" ];
+	description = ''
+          Acess control list for incoming SIP traffic.
+        '';
+      };
+
+      hostsDenySip = mkOption {
+        type = types.listOf types.str;
+	default = [ ];
+        example = [ "10.0.0.0/8" "11.0.0.0/8" ];
+	description = ''
+          Acess control list for denying incoming
+	   SIP registrations and traffic.
+        '';
+      };
+
+      sipListenPort = mkOption {
+        type = types.int;
+        default = 5060;
+        description = ''
+	  Port to listen for incoming SIP messages.
+        '';
+      };
+
+      rtpPortLow = mkOption {
+        type = types.int;
+        default = 7070;
+        description = ''
+         Bottom of UDP port range for incoming and outgoing RTP traffic
+        '';
+      };
+
+      rtpPortHigh = mkOption {
+        type = types.int;
+        default = 7089;
+        description = ''
+         Top of UDP port range for incoming and outgoing RTP traffic
+        '';
+      };
+
+      rtpTimeout = mkOption {
+        type = types.int;
+        default = 300;
+        description = ''
+          Timeout for an RTP stream. If for the specified 
+          number of seconds no data is relayed on an active
+          stream, it is considered dead and will be killed.
+        '';
+      };
+
+      rtpDscp = mkOption {
+        type = types.int;
+        default = 46;
+        description = ''
+          DSCP (differentiated services) value to be assigned
+          to RTP packets. Allows QOS aware routers to handle 
+          different types traffic with different priorities.
+        '';
+      };
+
+      sipDscp = mkOption {
+        type = types.int;
+        default = 0;
+        description = ''
+          DSCP (differentiated services) value to be assigned
+          to SIP packets. Allows QOS aware routers to handle 
+          different types traffic with different priorities.
+        '';
+      };
+
+      passwordFile = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Path to per-user password file.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration to add to siproxd configuration.
+        '';
+      };
+
+    };
+
+  };
+
+  ##### implementation
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton {
+      name = "siproxyd";
+      uid = config.ids.uids.siproxd;
+    };
+
+    systemd.services.siproxd = {
+      description = "SIP proxy/masquerading daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      serviceConfig = {
+        ExecStart = "${pkgs.siproxd}/sbin/siproxd -c ${confFile}";
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index 966c2eca282a..21840bc67e8f 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -189,19 +189,18 @@ in
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.munin ];
       environment.MUNIN_PLUGSTATE = "/var/run/munin";
+      preStart = ''
+        echo "updating munin plugins..."
+
+        mkdir -p /etc/munin/plugins
+        rm -rf /etc/munin/plugins/*
+        PATH="/run/current-system/sw/bin:/run/current-system/sw/sbin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash
+      '';
       serviceConfig = {
         ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/";
       };
     };
 
-    system.activationScripts.munin-node = ''
-      echo "updating munin plugins..."
-
-      mkdir -p /etc/munin/plugins
-      rm -rf /etc/munin/plugins/*
-      PATH="/run/current-system/sw/bin:/run/current-system/sw/sbin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash
-    '';
-
   }) (mkIf cronCfg.enable {
 
     services.cron.systemCronJobs = [
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index 97d153153a55..c1f7ba0eca74 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -12,7 +12,7 @@ let
   nagiosObjectDefs = cfg.objectDefs;
 
   nagiosObjectDefsDir = pkgs.runCommand "nagios-objects" {inherit nagiosObjectDefs;}
-    "ensureDir $out; ln -s $nagiosObjectDefs $out/";
+    "mkdir -p $out; ln -s $nagiosObjectDefs $out/";
 
   nagiosCfgFile = pkgs.writeText "nagios.cfg"
     ''
diff --git a/nixos/modules/services/monitoring/systemhealth.nix b/nixos/modules/services/monitoring/systemhealth.nix
index b0e59595e133..20d1dadd3bf2 100644
--- a/nixos/modules/services/monitoring/systemhealth.nix
+++ b/nixos/modules/services/monitoring/systemhealth.nix
@@ -13,7 +13,7 @@ let
     };
     buildInputs = [ python ];
     installPhase = ''
-      ensureDir $out/bin
+      mkdir -p $out/bin
       # Make it work for kernels 3.x, not so different than 2.6
       sed -i 's/2\.6/4.0/' system_health.py
       cp system_health.py $out/bin
diff --git a/nixos/modules/services/network-filesystems/openafs-client/default.nix b/nixos/modules/services/network-filesystems/openafs-client/default.nix
index 23ab39eb05f3..0297da9e865f 100644
--- a/nixos/modules/services/network-filesystems/openafs-client/default.nix
+++ b/nixos/modules/services/network-filesystems/openafs-client/default.nix
@@ -11,7 +11,7 @@ let
   };
 
   afsConfig = pkgs.runCommand "afsconfig" {} ''
-    ensureDir $out
+    mkdir -p $out
     echo ${cfg.cellName} > $out/ThisCell
     cp ${cellServDB} $out/CellServDB
     echo "/afs:${cfg.cacheDirectory}:${cfg.cacheSize}" > $out/cacheinfo
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index 5a353fc0942a..866707c3a913 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -7,9 +7,10 @@ let
   dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; };
 
   # Don't start dhcpcd on explicitly configured interfaces or on
-  # interfaces that are part of a bridge.
+  # interfaces that are part of a bridge, bond or sit device.
   ignoredInterfaces =
     map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces))
+    ++ mapAttrsToList (i: _: i) config.networking.sits
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
     ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds))
     ++ config.networking.dhcpcd.denyInterfaces;
@@ -35,7 +36,7 @@ let
       # Ignore peth* devices; on Xen, they're renamed physical
       # Ethernet cards used for bridging.  Likewise for vif* and tap*
       # (Xen) and virbr* and vnet* (libvirt).
-      denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet*
+      denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit*
 
       ${config.networking.dhcpcd.extraConfig}
     '';
diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix
index e5e1c103c686..900df67b53aa 100644
--- a/nixos/modules/services/networking/dhcpd.nix
+++ b/nixos/modules/services/networking/dhcpd.nix
@@ -13,7 +13,7 @@ let
       default-lease-time 600;
       max-lease-time 7200;
       authoritative;
-      ddns-update-style ad-hoc;
+      ddns-update-style interim;
       log-facility local1; # see dhcpd.nix
 
       ${cfg.extraConfig}
@@ -108,22 +108,41 @@ in
 
   config = mkIf config.services.dhcpd.enable {
 
-    jobs.dhcpd =
+    users = {
+      extraUsers.dhcpd = {
+        uid = config.ids.uids.dhcpd;
+        description = "DHCP daemon user";
+      };
+    };
+
+    systemd.services.dhcpd =
       { description = "DHCP server";
 
-        startOn = "started network-interfaces";
-        stopOn = "stopping network-interfaces";
+        wantedBy = [ "multi-user.target" ];
 
-        script =
+        after = [ "network.target" ];
+
+        path = [ pkgs.dhcp ];
+
+        preStart =
           ''
             mkdir -m 755 -p ${stateDir}
 
             touch ${stateDir}/dhcpd.leases
 
-            exec ${pkgs.dhcp}/sbin/dhcpd -f -cf ${configFile} \
-                -lf ${stateDir}/dhcpd.leases \
-                ${toString cfg.interfaces}
+            mkdir -m 755 -p /run/dhcpd
+            chown dhcpd /run/dhcpd
           '';
+
+        serviceConfig =
+          { ExecStart = "@${pkgs.dhcp}/sbin/dhcpd dhcpd"
+              + " -pf /run/dhcpd/dhcpd.pid -cf ${configFile}"
+              + " -lf ${stateDir}/dhcpd.leases -user dhcpd -group nogroup"
+              + " ${toString cfg.interfaces}";
+            Restart = "always";
+            Type = "forking";
+            PIDFile = "/run/dhcpd/dhcpd.pid";
+          };
       };
 
   };
diff --git a/nixos/modules/services/networking/ircd-hybrid/builder.sh b/nixos/modules/services/networking/ircd-hybrid/builder.sh
index b8cb836db95e..f2c92878a4dc 100644
--- a/nixos/modules/services/networking/ircd-hybrid/builder.sh
+++ b/nixos/modules/services/networking/ircd-hybrid/builder.sh
@@ -3,7 +3,7 @@ source $stdenv/setup
 doSub() {
     local src=$1
     local dst=$2
-    ensureDir $(dirname $dst)
+    mkdir -p $(dirname $dst)
     substituteAll $src $dst
 }
 
@@ -28,4 +28,4 @@ for i in $substFiles; do
     fi
 done
 
-ensureDir $out/bin
+mkdir -p $out/bin
diff --git a/nixos/modules/services/networking/polipo.nix b/nixos/modules/services/networking/polipo.nix
new file mode 100644
index 000000000000..05ded84625d0
--- /dev/null
+++ b/nixos/modules/services/networking/polipo.nix
@@ -0,0 +1,118 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.polipo;
+
+  polipoConfig = pkgs.writeText "polipo.conf" ''
+    proxyAddress = ${cfg.proxyAddress}
+    proxyPort = ${toString cfg.proxyPort}
+    allowedClients = ${concatStringsSep ", " cfg.allowedClients}
+    ${optionalString (cfg.parentProxy != "") "parentProxy = ${cfg.parentProxy}" }
+    ${optionalString (cfg.socksParentProxy != "") "socksParentProxy = ${cfg.socksParentProxy}" }
+    ${config.services.polipo.extraConfig}
+  '';
+
+in
+
+{
+
+  options = {
+
+    services.polipo = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to run the polipo caching web proxy.";
+      };
+
+      proxyAddress = mkOption {
+        type = types.string;
+        default = "127.0.0.1";
+        description = "IP address on which Polipo will listen.";
+      };
+
+      proxyPort = mkOption {
+        type = types.int;
+        default = 8123;
+        description = "TCP port on which Polipo will listen.";
+      };
+
+      allowedClients = mkOption {
+        type = types.listOf types.string;
+        default = [ "127.0.0.1" "::1" ];
+        example = [ "127.0.0.1" "::1" "134.157.168.0/24" "2001:660:116::/48" ];
+        description = ''
+          List of IP addresses or network addresses that may connect to Polipo.
+        '';
+      };
+
+      parentProxy = mkOption {
+        type = types.string;
+        default = "";
+        example = "localhost:8124";
+        description = ''
+          Hostname and port number of an HTTP parent proxy;
+          it should have the form ‘host:port’.
+        '';
+      };
+
+      socksParentProxy = mkOption {
+        type = types.string;
+        default = "";
+        example = "localhost:9050";
+        description = ''
+          Hostname and port number of an SOCKS parent proxy;
+          it should have the form ‘host:port’.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Polio configuration. Contents will be added 
+          verbatim to the configuration file.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = singleton
+      { name = "polipo";
+        uid = config.ids.uids.polipo;
+        description = "Polipo caching proxy user";
+        home = "/var/cache/polipo";
+        createHome = true;
+      };
+
+    users.extraGroups = singleton
+      { name = "polipo";
+        gid = config.ids.gids.polipo;
+        members = [ "polipo" ];
+      };
+
+    systemd.services.polipo = {
+      description = "caching web proxy";
+      after = [ "network.target" "nss-lookup.target" ];
+      wantedBy = [ "multi-user.target"];
+      preStart = ''
+         ${pkgs.coreutils}/bin/chown polipo:polipo /var/cache/polipo -R
+      '';
+      serviceConfig = {
+        ExecStart  = "${pkgs.polipo}/bin/polipo -c ${polipoConfig}";
+        ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
+        User = "polipo";
+      };
+    };
+
+  };
+
+}
\ No newline at end of file
diff --git a/nixos/modules/services/networking/ssh/lshd.nix b/nixos/modules/services/networking/ssh/lshd.nix
index fca30a1fe49c..81e523fd2a51 100644
--- a/nixos/modules/services/networking/ssh/lshd.nix
+++ b/nixos/modules/services/networking/ssh/lshd.nix
@@ -99,7 +99,6 @@ in
       };
 
       subsystems = mkOption {
-        default = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ];
         description = ''
           List of subsystem-path pairs, where the head of the pair
           denotes the subsystem name, and the tail denotes the path to
@@ -116,6 +115,8 @@ in
 
   config = mkIf cfg.enable {
 
+    services.lshd.subsystems = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ];
+
     jobs.lshd =
       { description = "GNU lshd SSH2 daemon";
 
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
new file mode 100644
index 000000000000..634f760328f7
--- /dev/null
+++ b/nixos/modules/services/networking/unifi.nix
@@ -0,0 +1,88 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.unifi;
+  stateDir = "/var/lib/unifi";
+  cmd = "@${pkgs.icedtea7_jre}/bin/java java -jar ${stateDir}/lib/ace.jar";
+in
+{
+
+  options = {
+
+    services.unifi.enable = mkOption {
+      type = types.uniq types.bool;
+      default = false;
+      description = ''
+        Whether or not to enable the unifi controller service.
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers.unifi = {
+      uid = config.ids.uids.unifi;
+      description = "UniFi controller daemon user";
+      home = "${stateDir}";
+    };
+
+    # We must create the binary directories as bind mounts instead of symlinks
+    # This is because the controller resolves all symlinks to absolute paths
+    # to be used as the working directory.
+    systemd.mounts = map ({ what, where }: {
+        bindsTo = [ "unifi.service" ];
+        requiredBy = [ "unifi.service" ];
+        before = [ "unifi.service" ];
+        options = "bind";
+        what = what;
+        where = where;
+      }) [
+        {
+          what = "${pkgs.unifi}/dl";
+          where = "${stateDir}/dl";
+        }
+        {
+          what = "${pkgs.unifi}/lib";
+          where = "${stateDir}/lib";
+        }
+        {
+          what = "${pkgs.mongodb}/bin";
+          where = "${stateDir}/bin";
+        }
+      ];
+
+    systemd.services.unifi = {
+      description = "UniFi controller daemon";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      preStart = ''
+        # Ensure privacy of state
+        chown unifi "${stateDir}"
+        chmod 0700 "${stateDir}"
+
+        # Create the volatile webapps
+        mkdir -p "${stateDir}/webapps"
+        chown unifi "${stateDir}/webapps"
+        ln -s "${pkgs.unifi}/webapps/ROOT.war" "${stateDir}/webapps/ROOT.war"
+      '';
+
+      postStop = ''
+        rm "${stateDir}/webapps/ROOT.war"
+      '';
+
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = "${cmd} start";
+        ExecStop = "${cmd} stop";
+        User = "unifi";
+        PermissionsStartOnly = true;
+        UMask = "0077";
+        WorkingDirectory = "${stateDir}";
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
index a40fd924741b..4d53cd0750fb 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -20,6 +20,11 @@ let
         </Pass>
   ";
 
+  modules = pkgs.buildEnv {
+    name = "znc-modules";
+    paths = cfg.modulePackages;
+  };
+
   confOptions = { ... }: {
     options = {
       modules = mkOption {
@@ -31,6 +36,15 @@ let
         '';
       };
 
+      userModules = mkOption {
+        type = types.listOf types.string;
+        default = [ ];
+        example = [ "fish" "push" ];
+        description = ''
+          A list of user modules to include in the `znc.conf` file.
+        '';
+      };
+
       userName = mkOption {
         default = defaultUserName;
         example = "johntron";
@@ -63,9 +77,9 @@ let
       };
 
       port = mkOption {
-        default = "5000";
-        example = "5000";
-        type = types.string;
+        default = 5000;
+        example = 5000;
+        type = types.int;
         description = ''
           Specifies the port on which to listen.
         '';
@@ -80,6 +94,13 @@ let
         '';
       };
 
+      extraZncConf = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra config to `znc.conf` file
+        '';
+      };
     };
   };
 
@@ -104,7 +125,7 @@ let
             AllowWeb = true
             IPv4 = true
             IPv6 = false
-            Port = ${if confOpts.useSSL then "+" else ""}${confOpts.port}
+            Port = ${if confOpts.useSSL then "+" else ""}${toString confOpts.port}
             SSL = ${if confOpts.useSSL then "true" else "false"}
     </Listener>
     
@@ -128,9 +149,11 @@ let
             QuitMsg = Quit
             RealName = ${confOpts.nick}
             TimestampFormat = [%H:%M:%S]
+            ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.userModules}
             
             ${confOpts.passBlock}
     </User>
+    ${confOpts.extraZncConf}
   '';
 
   zncConfFile = pkgs.writeTextFile {
@@ -168,9 +191,9 @@ in
       };
 
       dataDir = mkOption {
-        default = "/home/${cfg.user}/.znc";
-        example = "/home/john/.znc";
-        type = types.string; 
+        default = "/var/lib/znc/";
+        example = "/home/john/.znc/";
+        type = types.path;
         description = ''
           The data directory. Used for configuration files and modules.
         '';
@@ -179,7 +202,7 @@ in
       zncConf = mkOption {
         default = "";
         example = "See: http://wiki.znc.in/Configuration";
-        type = types.string;
+        type = types.lines;
         description = ''
           The contents of the `znc.conf` file to use when creating it.
           If specified, `confOptions` will be ignored, and this value, as-is, will be used.
@@ -201,6 +224,15 @@ in
         '';
         options = confOptions; 
       };
+
+      modulePackages = mkOption {
+        type = types.listOf types.package;
+        default = [ ];
+        example = [ pkgs.zncModules.fish pkgs.zncModules.push ];
+        description = ''
+          A list of global znc module packages to add to znc.
+        '';
+      };
  
       mutable = mkOption {
         default = false;
@@ -218,9 +250,9 @@ in
       };
  
       extraFlags = mkOption {
-        default = "";
-        example = "--debug";
-        type = types.string;
+        default = [ ];
+        example = [ "--debug" ];
+        type = types.listOf types.str;
         description = ''
           Extra flags to use when executing znc command.
         '';
@@ -233,25 +265,22 @@ in
 
   config = mkIf cfg.enable {
 
-    systemd.services."znc-${cfg.user}" = {
-      description = "ZNC Server of ${cfg.user}.";
+    systemd.services.znc = {
+      description = "ZNC Server";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.service" ];
-      path = [ pkgs.znc ];
       serviceConfig = {
-        User = "${cfg.user}";
+        User = cfg.user;
         Restart = "always";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         ExecStop   = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
       };
       preStart = ''
-        ${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}
-        ${pkgs.coreutils}/bin/chown ${cfg.user} ${cfg.dataDir} -R
         ${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/configs
 
         # If mutable, regenerate conf file every time.
         ${optionalString (!cfg.mutable) ''
-          ${pkgs.coreutils}/echo "znc-${cfg.user} is set to be system-managed. Now deleting old znc.conf file to be regenerated."
+          ${pkgs.coreutils}/echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated."
           ${pkgs.coreutils}/rm -f ${cfg.dataDir}/configs/znc.conf
         ''}
 
@@ -259,7 +288,7 @@ in
         if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then
           ${pkgs.coreutils}/bin/echo "No znc.conf file found in ${cfg.dataDir}. Creating one now."
           ${if (!cfg.mutable)
-            then "${pkgs.coreutils}/bin/ln --force -s ${zncConfFile} ${cfg.dataDir}/configs/znc.conf"
+            then "${pkgs.coreutils}/bin/ln --force -s ${zncConfFile} ${cfg.dataDir}/.znc/configs/znc.conf"
             else ''
               ${pkgs.coreutils}/bin/cp --no-clobber ${zncConfFile} ${cfg.dataDir}/configs/znc.conf
               ${pkgs.coreutils}/bin/chmod u+rw ${cfg.dataDir}/configs/znc.conf
@@ -269,10 +298,14 @@ in
 
         if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then
           ${pkgs.coreutils}/bin/echo "No znc.pem file found in ${cfg.dataDir}. Creating one now."
-          ${pkgs.znc}/bin/znc --makepem
+          ${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir} 
         fi
+
+        # Symlink modules
+        rm ${cfg.dataDir}/modules || true
+        ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules
       '';
-      script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${cfg.extraFlags}";
+      script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${toString cfg.extraFlags}";
     };
 
     users.extraUsers = optional (cfg.user == defaultUser)
@@ -280,6 +313,7 @@ in
         description = "ZNC server daemon owner";
         group = defaultUser;
         uid = config.ids.uids.znc;
+        home = cfg.dataDir;
         createHome = true;
         createUser = true;
       };
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index eeae11dc4ff3..b74ef4370d76 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -21,6 +21,11 @@ let
     ];
   };
 
+  esPlugins = pkgs.buildEnv {
+    name = "elasticsearch-plugins";
+    paths = cfg.plugins;
+  };
+
 in {
 
   ###### interface
@@ -101,6 +106,12 @@ in {
       example = [ "-Djava.net.preferIPv4Stack=true" ];
     };
 
+    plugins = mkOption {
+      description = "Extra elasticsearch plugins";
+      default = [];
+      type = types.listOf types.package;
+    };
+
   };
 
   ###### implementation
@@ -119,6 +130,10 @@ in {
       preStart = ''
         mkdir -m 0700 -p ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown -R elasticsearch ${cfg.dataDir}; fi
+
+        # Install plugins
+        rm ${cfg.dataDir}/plugins || true
+        ln -s ${esPlugins}/plugins ${cfg.dataDir}/plugins
       '';
     };
 
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index af5450166379..3758652ebddf 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -25,12 +25,17 @@ in
   options = {
 
     services.fail2ban = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Whether to enable the fail2ban service.";
+      };
 
       daemonConfig = mkOption {
         default =
           ''
             [Definition]
-            loglevel  = 3
+            loglevel  = INFO
             logtarget = SYSLOG
             socket    = /run/fail2ban/fail2ban.sock
             pidfile   = /run/fail2ban/fail2ban.pid
@@ -80,7 +85,7 @@ in
 
   ###### implementation
 
-  config = {
+  config = mkIf cfg.enable {
 
     environment.systemPackages = [ pkgs.fail2ban ];
 
@@ -101,12 +106,13 @@ in
         preStart =
           ''
             mkdir -p /run/fail2ban -m 0755
+            mkdir -p /var/lib/fail2ban
           '';
 
         serviceConfig =
           { ExecStart = "${pkgs.fail2ban}/bin/fail2ban-server -f";
             ReadOnlyDirectories = "/";
-            ReadWriteDirectories = "/run /var/tmp";
+            ReadWriteDirectories = "/run /var/tmp /var/lib";
             CapabilityBoundingSet = "CAP_DAC_READ_SEARCH CAP_NET_ADMIN CAP_NET_RAW";
           };
 
@@ -131,15 +137,14 @@ in
         bantime  = 600
         findtime = 600
         maxretry = 3
-        backend  = auto
-      '';
+        backend  = systemd
+       '';
 
     # Block SSH if there are too many failing connection attempts.
     services.fail2ban.jails.ssh-iptables =
       ''
         filter   = sshd
         action   = iptables[name=SSH, port=ssh, protocol=tcp]
-        logpath  = /var/log/warn
         maxretry = 5
       '';
 
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 8d02a6404ac1..928f16c94489 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -14,7 +14,7 @@ let
     name = "dbus-conf";
     preferLocalBuild = true;
     buildCommand = ''
-      ensureDir $out
+      mkdir -p $out
 
       cp -v ${pkgs.dbus.daemon}/etc/dbus-1/system.conf $out/system.conf
 
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index b1a247163a47..b83cf276ed52 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -80,7 +80,7 @@ let
 
   # !!! should be in lib
   writeTextInDir = name: text:
-    pkgs.runCommand name {inherit text;} "ensureDir $out; echo -n \"$text\" > $out/$name";
+    pkgs.runCommand name {inherit text;} "mkdir -p $out; echo -n \"$text\" > $out/$name";
 
 
   enableSSL = any (vhost: vhost.enableSSL) allHosts;
@@ -196,7 +196,7 @@ let
     ) null ([ cfg ] ++ subservices);
 
     documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else
-      pkgs.runCommand "empty" {} "ensureDir $out";
+      pkgs.runCommand "empty" {} "mkdir -p $out";
 
     documentRootConf = ''
       DocumentRoot "${documentRoot}"
@@ -389,7 +389,7 @@ let
   '';
 
 
-  enablePHP = any (svc: svc.enablePHP) allSubservices;
+  enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices;
 
 
   # Generate the PHP configuration file.  Should probably be factored
@@ -533,6 +533,12 @@ in
         '';
       };
 
+      enablePHP = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the PHP module.";
+      };
+
       phpOptions = mkOption {
         type = types.lines;
         default = "";
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
index fa65ec0ef700..aa9aec87f0c4 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
@@ -92,7 +92,7 @@ let
 
     installPhase =
       ''
-        ensureDir $out
+        mkdir -p $out
         cp -r * $out
         cp ${mediawikiConfig} $out/LocalSettings.php
         sed -i \
@@ -106,7 +106,7 @@ let
   mediawikiScripts = pkgs.runCommand "mediawiki-${config.id}-scripts"
     { buildInputs = [ pkgs.makeWrapper ]; }
     ''
-      ensureDir $out/bin
+      mkdir -p $out/bin
       for i in changePassword.php createAndPromote.php userOptions.php edit.php nukePage.php update.php; do
         makeWrapper ${php}/bin/php $out/bin/mediawiki-${config.id}-$(basename $i .php) \
           --add-flags ${mediawikiRoot}/maintenance/$i
diff --git a/nixos/modules/services/web-servers/apache-httpd/mercurial.nix b/nixos/modules/services/web-servers/apache-httpd/mercurial.nix
index 1d4303b75b35..6dd91be00a73 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mercurial.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mercurial.nix
@@ -9,7 +9,7 @@ let
   cgi = pkgs.stdenv.mkDerivation {
     name = "mercurial-cgi";
     buildCommand = ''
-      ensureDir $out
+      mkdir -p $out
       cp -v ${mercurial}/share/cgi-bin/hgweb.cgi $out
       sed -i "s|/path/to/repo/or/config|$out/hgweb.config|" $out/hgweb.cgi
       echo "
diff --git a/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix b/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix
index b2cd53ae55cd..a883bb2b3433 100644
--- a/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix
@@ -29,6 +29,14 @@ ${extraWorkersProperties}
   '';
 in
 {
+
+  options = {
+    extraWorkersProperties = lib.mkOption {
+      default = "";
+      description = "Additional configuration for the workers.properties file.";
+    };
+  };
+
   extraModules = [
     { name = "jk"; path = "${pkgs.tomcat_connectors}/modules/mod_jk.so"; }
   ];
diff --git a/nixos/modules/services/web-servers/lighttpd/cgit.nix b/nixos/modules/services/web-servers/lighttpd/cgit.nix
index dbff565bd8a3..d4663781fd84 100644
--- a/nixos/modules/services/web-servers/lighttpd/cgit.nix
+++ b/nixos/modules/services/web-servers/lighttpd/cgit.nix
@@ -29,7 +29,7 @@ in
         cache-size=1000
         scan-path=/srv/git
       '';
-      type = types.string;
+      type = types.lines;
       description = ''
         Verbatim contents of the cgit runtime configuration file. Documentation
         (with cgitrc example file) is available in "man cgitrc". Or online:
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index 3ba934c72bf8..fc9487ab4859 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -9,9 +9,9 @@ let
   cfg = config.services.lighttpd;
 
   needModRedirect = cfg.gitweb.enable;
-  needModAlias = cfg.cgit.enable or cfg.gitweb.enable;
-  needModSetenv = cfg.cgit.enable or cfg.gitweb.enable;
-  needModCgi = cfg.cgit.enable or cfg.gitweb.enable;
+  needModAlias = cfg.cgit.enable || cfg.gitweb.enable;
+  needModSetenv = cfg.cgit.enable || cfg.gitweb.enable;
+  needModCgi = cfg.cgit.enable || cfg.gitweb.enable;
   needModStatus = cfg.mod_status;
   needModUserdir = cfg.mod_userdir;
 
@@ -102,7 +102,7 @@ in
 
       document-root = mkOption {
         default = "/srv/www";
-        type = types.str;
+        type = types.path;
         description = ''
           Document-root of the web server. Must be readable by the "lighttpd" user.
         '';
@@ -128,7 +128,7 @@ in
 
       configText = mkOption {
         default = "";
-        type = types.string;
+        type = types.lines;
 	example = ''...verbatim config file contents...'';
         description = ''
           Overridable config file contents to use for lighttpd. By default, use
@@ -138,7 +138,7 @@ in
 
       extraConfig = mkOption {
         default = "";
-        type = types.string;
+        type = types.lines;
         description = ''
           These configuration lines will be appended to the generated lighttpd
           config file. Note that this mechanism does not work when the manual
diff --git a/nixos/modules/services/web-servers/lighttpd/gitweb.nix b/nixos/modules/services/web-servers/lighttpd/gitweb.nix
index d49278be09a8..c407a1d89778 100644
--- a/nixos/modules/services/web-servers/lighttpd/gitweb.nix
+++ b/nixos/modules/services/web-servers/lighttpd/gitweb.nix
@@ -25,7 +25,7 @@ in
 
     projectroot = mkOption {
       default = "/srv/git";
-      type = types.str;
+      type = types.path;
       description = ''
         Path to git projects (bare repositories) that should be served by
         gitweb. Must not end with a slash.
@@ -34,7 +34,7 @@ in
 
     extraConfig = mkOption {
       default = "";
-      type = types.str;
+      type = types.lines;
       description = ''
         Verbatim configuration text appended to the generated gitweb.conf file.
       '';
diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix
index 1de3d40165e9..c2f464014ae6 100644
--- a/nixos/modules/services/web-servers/tomcat.nix
+++ b/nixos/modules/services/web-servers/tomcat.nix
@@ -77,6 +77,11 @@ in
         description = "Whether to enable logging per virtual host.";
       };
 
+      jdk = mkOption {
+        default = pkgs.jdk;
+        description = "Which JDK to use.";
+      };
+
       axis2 = {
 
         enable = mkOption {
@@ -332,13 +337,13 @@ in
           '';
 
         script = ''
-            ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c 'CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${pkgs.jdk} JAVA_OPTS="${cfg.javaOpts}" CATALINA_OPTS="${cfg.catalinaOpts}" ${tomcat}/bin/startup.sh'
+            ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c 'CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} JAVA_OPTS="${cfg.javaOpts}" CATALINA_OPTS="${cfg.catalinaOpts}" ${tomcat}/bin/startup.sh'
         '';
 
         postStop =
           ''
             echo "Stopping tomcat..."
-            CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${pkgs.jdk} ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c ${tomcat}/bin/shutdown.sh
+            CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c ${tomcat}/bin/shutdown.sh
           '';
 
       };
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index b82398ccf9dd..c62beca60d84 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -17,7 +17,10 @@ in
   # Note: the order in which desktop manager modules are imported here
   # determines the default: later modules (if enabled) are preferred.
   # E.g., if KDE is enabled, it supersedes xterm.
-  imports = [ ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./e17.nix ./gnome3.nix ./xbmc.nix ];
+  imports = [
+    ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix
+    ./e17.nix ./e18.nix ./gnome3.nix ./xbmc.nix
+  ];
 
   options = {
 
diff --git a/nixos/modules/services/x11/desktop-managers/e18.nix b/nixos/modules/services/x11/desktop-managers/e18.nix
new file mode 100644
index 000000000000..faafd21b07dd
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/e18.nix
@@ -0,0 +1,43 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.e18;
+  e18_enlightenment = pkgs.e18.enlightenment.override { set_freqset_setuid = true; };
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.e18.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable the E18 desktop environment.";
+    };
+
+  };
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    environment.systemPackages = [
+      pkgs.e18.efl pkgs.e18.evas pkgs.e18.emotion pkgs.e18.elementary e18_enlightenment
+      pkgs.e18.terminology pkgs.e18.econnman
+    ];
+
+    services.xserver.desktopManager.session = [
+    { name = "E18";
+      start = ''
+        ${e18_enlightenment}/bin/enlightenment_start
+        waitPID=$!
+      '';
+    }];
+
+    security.setuidPrograms = [ "e18_freqset" ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index df50ca8c905c..06bcb6dbb8be 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -35,6 +35,14 @@ in {
       description = "Enable Gnome 3 desktop manager.";
     };
 
+    services.xserver.desktopManager.gnome3.sessionPath = mkOption {
+      default = [];
+      example = "[ pkgs.gnome3.gpaste ]";
+      description = "Additional list of packages to be added to the session search path.
+                     Useful for gnome shell extensions or gsettings-conditionated autostart.";
+      apply = list: list ++ [ gnome3.gnome_shell ]; 
+    };
+
     environment.gnome3.packageSet = mkOption {
       default = pkgs.gnome3;
       example = literalExample "pkgs.gnome3_12";
@@ -86,10 +94,19 @@ in {
 
           export XDG_MENU_PREFIX=gnome
 
-          # Don't let epiphany depend upon gnome-shell
-          # Don't let gnome-session depend upon vino (for .desktop autostart condition)
+          ${concatMapStrings (p: ''
+            if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
+              export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
+            fi
+
+            if [ -d "${p}/lib/girepository-1.0" ]; then
+              export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
+              export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
+            fi
+          '') cfg.sessionPath}
+
           # Override default mimeapps
-          export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${gnome3.gnome_shell}/share/gsettings-schemas/${gnome3.gnome_shell.name}:${gnome3.vino}/share/gsettings-schemas/${gnome3.vino.name}:${mimeAppsList}/share
+          export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share
 
           # Let gnome-control-center find gnome-shell search providers
           export GNOME_SEARCH_PROVIDERS_DIR=${config.system.path}/share/gnome-shell/search-providers/
@@ -123,7 +140,7 @@ in {
         gnome3.gnome_settings_daemon
         gnome3.gnome_shell
         gnome3.gnome_themes_standard
-      ] ++ (removePackagesByName [
+      ] ++ cfg.sessionPath ++ (removePackagesByName [
         gnome3.baobab
         gnome3.empathy
         gnome3.eog
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
new file mode 100644
index 000000000000..9d14fc2e137c
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -0,0 +1,151 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.xserver.displayManager;
+  gdm = pkgs.gnome3_12.gdm; # gdm 3.10 not supported
+  gnome3 = config.environment.gnome3.packageSet;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.displayManager.gdm = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = ''
+          Whether to enable GDM as the display manager.
+          <emphasis>GDM is very experimental and may render system unusable.</emphasis>
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.gdm.enable {
+
+    services.xserver.displayManager.slim.enable = false;
+
+    users.extraUsers.gdm =
+      { name = "gdm";
+        uid = config.ids.uids.gdm;
+        group = "gdm";
+        home = "/run/gdm";
+        description = "GDM user";
+      };
+
+    users.extraGroups.gdm.gid = config.ids.gids.gdm;
+
+    services.xserver.displayManager.job =
+      { 
+        environment = {
+          GDM_X_SERVER = "${cfg.xserverBin} ${cfg.xserverArgs}";
+          GDM_SESSIONS_DIR = "${cfg.session.desktops}";
+          XDG_CONFIG_DIRS = "${gnome3.gnome_settings_daemon}/etc/xdg";
+        };
+        execCmd = "exec ${gdm}/sbin/gdm";
+      };
+
+    # Because sd_login_monitor_new requires /run/systemd/machines
+    systemd.services.display-manager.wants = [ "systemd-machined.service" ];
+    systemd.services.display-manager.after = [ "systemd-machined.service" ];
+
+    systemd.services.display-manager.path = [ gnome3.gnome_shell gnome3.caribou ];
+
+    services.dbus.packages = [ gdm ];
+
+    programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm";
+
+    # GDM LFS PAM modules, adapted somehow to NixOS
+    security.pam.services = {
+      gdm-launch-environment.text = ''
+        auth     required       pam_succeed_if.so audit quiet_success user = gdm
+        auth     optional       pam_permit.so
+
+        account  required       pam_succeed_if.so audit quiet_success user = gdm
+        account  sufficient     pam_unix.so
+
+        password required       pam_deny.so
+
+        session  required       pam_succeed_if.so audit quiet_success user = gdm
+        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
+        session  optional       pam_keyinit.so force revoke
+        session  optional       pam_permit.so
+      '';
+
+     gdm.text = ''
+        auth     requisite      pam_nologin.so
+        auth     required       pam_env.so
+
+        auth     required       pam_succeed_if.so uid >= 1000 quiet
+        auth     optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so
+        auth     sufficient     pam_unix.so nullok likeauth
+        auth     required       pam_deny.so
+
+        account  sufficient     pam_unix.so
+
+        password requisite      pam_unix.so nullok sha512
+
+        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required       pam_unix.so
+        session  required       pam_loginuid.so
+        session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
+        session  optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start
+      '';
+
+      gdm-password.text = ''
+        auth     requisite      pam_nologin.so
+        auth     required       pam_env.so envfile=${config.system.build.pamEnvironment}
+
+        auth     required       pam_succeed_if.so uid >= 1000 quiet
+        auth     optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so
+        auth     sufficient     pam_unix.so nullok likeauth
+        auth     required       pam_deny.so 
+
+        account  sufficient     pam_unix.so
+        
+        password requisite      pam_unix.so nullok sha512
+
+        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required       pam_unix.so
+        session  required       pam_loginuid.so
+        session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
+        session  optional       ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start
+      '';
+
+      gdm-autologin.text = ''
+        auth     requisite      pam_nologin.so
+
+        auth     required       pam_succeed_if.so uid >= 1000 quiet
+        auth     required       pam_permit.so
+
+        account  sufficient     pam_unix.so
+
+        password requisite      pam_unix.so nullok sha512
+
+        session  optional       pam_keyinit.so revoke
+        session  required       pam_env.so envfile=${config.system.build.pamEnvironment}
+        session  required       pam_unix.so
+        session  required       pam_loginuid.so
+        session  optional       ${pkgs.systemd}/lib/security/pam_systemd.so
+      '';
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index d459c59b0483..f8ce06738fee 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -26,7 +26,7 @@ let
     buildInputs = [ pkgs.makeWrapper ];
 
     buildCommand = ''
-      ensureDir $out/gtk-3.0/
+      mkdir -p $out/gtk-3.0/
 
       # This wrapper ensures that we actually get fonts
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
index 48feb12d044c..9ee4e0dc7cb0 100644
--- a/nixos/modules/services/x11/display-managers/slim.nix
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -27,7 +27,7 @@ let
       unpackedTheme = pkgs.stdenv.mkDerivation {
         name = "slim-theme";
         buildCommand = ''
-          ensureDir $out
+          mkdir -p $out
           cd $out
           unpackFile ${cfg.theme}
           ln -s * default
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index f2227a34a20c..f5b394b6d98b 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -41,16 +41,19 @@ in {
       };
 
       accelFactor = mkOption {
+        type = types.nullOr types.string;
         default = "0.001";
         description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).";
       };
 
       minSpeed = mkOption {
+        type = types.nullOr types.string;
         default = "0.6";
         description = "Cursor speed factor for precision finger motion.";
       };
 
       maxSpeed = mkOption {
+        type = types.nullOr types.string;
         default = "1.0";
         description = "Cursor speed factor for highest-speed finger motion.";
       };
@@ -120,9 +123,9 @@ in {
           MatchIsTouchpad "on"
           ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''}
           Driver "synaptics"
-          Option "MinSpeed" "${cfg.minSpeed}"
-          Option "MaxSpeed" "${cfg.maxSpeed}"
-          Option "AccelFactor" "${cfg.accelFactor}"
+          ${optionalString (cfg.minSpeed != null) ''Option "MinSpeed" "${cfg.minSpeed}"''}
+          ${optionalString (cfg.maxSpeed != null) ''Option "MaxSpeed" "${cfg.maxSpeed}"''}
+          ${optionalString (cfg.accelFactor != null) ''Option "AccelFactor" "${cfg.accelFactor}"''}
           ${optionalString cfg.tapButtons tapConfig}
           Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}"
           Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}"
diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
new file mode 100644
index 000000000000..d234a432e9a9
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/bspwm.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.bspwm;
+in
+
+{
+  options = {
+    services.xserver.windowManager.bspwm.enable = mkOption {
+      type = types.bool;
+      default = false;
+      example = true;
+      description = "Enable the bspwm window manager.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager.session = singleton {
+      name = "bspwm";
+      start = "
+        ${pkgs.sxhkd}/bin/sxhkd &
+        ${pkgs.bspwm}/bin/bspwm
+      ";
+    };
+    environment.systemPackages = [ pkgs.bspwm ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index f27ba3661413..45a4e947e0aa 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -17,6 +17,7 @@ in
       ./xmonad.nix
       ./i3.nix
       ./herbstluftwm.nix
+      ./bspwm.nix
     ];
 
   options = {
diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix
index b1bad956b4bb..2e5a70b3aa54 100644
--- a/nixos/modules/system/activation/activation-script.nix
+++ b/nixos/modules/system/activation/activation-script.nix
@@ -66,6 +66,9 @@ in
                 PATH=$PATH:$i/bin:$i/sbin
             done
 
+            _status=0
+            trap "_status=1" ERR
+
             # Ensure a consistent umask.
             umask 0022
 
@@ -84,6 +87,8 @@ in
 
             # Prevent the current configuration from being garbage-collected.
             ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
+
+            exit $_status
           '';
       };
 
diff --git a/nixos/modules/system/boot/emergency-mode.nix b/nixos/modules/system/boot/emergency-mode.nix
new file mode 100644
index 000000000000..9cdab8416192
--- /dev/null
+++ b/nixos/modules/system/boot/emergency-mode.nix
@@ -0,0 +1,37 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    systemd.enableEmergencyMode = mkOption {
+      default = true;
+      type = types.bool;
+      description = ''
+        Whether to enable emergency mode, which is an
+        <command>sulogin</command> shell started on the console if
+        mounting a filesystem fails.  Since some machines (like EC2
+        instances) have no console of any kind, emergency mode doesn't
+        make sense, and it's better to continue with the boot insofar
+        as possible.
+      '';
+    };
+
+  };
+
+  ###### implementation
+
+  config = {
+
+    systemd.additionalUpstreamSystemUnits = optionals
+      config.systemd.enableEmergencyMode [
+        "emergency.target" "emergency.service"
+      ];
+
+  };
+
+}
\ No newline at end of file
diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix
index 7b214cd1e1f5..652eb046f50a 100644
--- a/nixos/modules/system/boot/modprobe.nix
+++ b/nixos/modules/system/boot/modprobe.nix
@@ -68,20 +68,15 @@ with lib;
 
   config = mkIf (!config.boot.isContainer) {
 
-    environment.etc = [
-      { source = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf";
-        target = "modprobe.d/ubuntu.conf";
-      }
-      { source = pkgs.writeText "modprobe.conf"
-          ''
-            ${flip concatMapStrings config.boot.blacklistedKernelModules (name: ''
-              blacklist ${name}
-            '')}
-            ${config.boot.extraModprobeConfig}
-          '';
-        target = "modprobe.d/nixos.conf";
-      }
-    ];
+    environment.etc."modprobe.d/ubuntu.conf".source = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf";
+
+    environment.etc."modprobe.d/nixos.conf".text =
+      ''
+        ${flip concatMapStrings config.boot.blacklistedKernelModules (name: ''
+          blacklist ${name}
+        '')}
+        ${config.boot.extraModprobeConfig}
+      '';
 
     environment.systemPackages = [ config.system.sbin.modprobe pkgs.kmod ];
 
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 7adb932aba7f..73fc6ce543cf 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -4,7 +4,8 @@ targetRoot=/mnt-root
 console=tty1
 
 export LD_LIBRARY_PATH=@extraUtils@/lib
-export PATH=@extraUtils@/bin:@extraUtils@/sbin
+export PATH=@extraUtils@/bin
+ln -s @extraUtils@/bin /bin
 
 
 fail() {
@@ -193,6 +194,9 @@ checkFS() {
     # Don't check ROM filesystems.
     if [ "$fsType" = iso9660 -o "$fsType" = udf ]; then return 0; fi
 
+    # Don't check resilient COWs as they validate the fs structures at mount time
+    if [ "$fsType" = btrfs -o "$fsType" = zfs ]; then return 0; fi
+
     # If we couldn't figure out the FS type, then skip fsck.
     if [ "$fsType" = auto ]; then
         echo 'cannot check filesystem with type "auto"!'
@@ -262,6 +266,13 @@ mountFS() {
 
     checkFS "$device" "$fsType"
 
+    # Create backing directories for unionfs-fuse.
+    if [ "$fsType" = unionfs-fuse ]; then
+        for i in $(IFS=:; echo ${options##*,dirs=}); do
+            mkdir -m 0700 -p /mnt-root"${i%=*}"
+        done
+    fi
+
     echo "mounting $device on $mountPoint..."
 
     mkdir -p "/mnt-root$mountPoint" || true
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index b6249b6c0915..6a069c5d0540 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -23,22 +23,6 @@ let
   };
 
 
-  needsCifsUtils = kernelPackages.kernel ? features
-                && kernelPackages.kernel.features ? needsCifsUtils
-                && kernelPackages.kernel.features.needsCifsUtils
-                && any (fs: fs.fsType == "cifs") fileSystems;
-
-  busybox =
-    if needsCifsUtils
-    then pkgs.busybox.override {
-           extraConfig = ''
-             CONFIG_FEATURE_MOUNT_CIFS n
-             CONFIG_FEATURE_MOUNT_HELPERS y
-           '';
-         }
-    else pkgs.busybox;
-
-
   # Some additional utilities needed in stage 1, like mount, lvm, fsck
   # etc.  We don't want to bring in all of those packages, so we just
   # copy what we need.  Instead of using statically linked binaries,
@@ -51,6 +35,7 @@ let
     }
     ''
       mkdir -p $out/bin $out/lib
+      ln -s $out/bin $out/sbin
 
       # Copy what we need from Glibc.
       cp -pv ${pkgs.glibc}/lib/ld*.so.? $out/lib
@@ -62,11 +47,10 @@ let
       cp -pv ${pkgs.gcc.gcc}/lib*/libgcc_s.so.* $out/lib
 
       # Copy BusyBox.
-      cp -rvd ${busybox}/{bin,sbin} $out/
-      chmod -R u+w $out
+      cp -pvd ${pkgs.busybox}/bin/* ${pkgs.busybox}/sbin/* $out/bin/
 
       # Copy some utillinux stuff.
-      cp -v ${pkgs.utillinux}/sbin/blkid $out/bin
+      cp -vf ${pkgs.utillinux}/sbin/blkid $out/bin
       cp -pdv ${pkgs.utillinux}/lib/libblkid*.so.* $out/lib
       cp -pdv ${pkgs.utillinux}/lib/libuuid*.so.* $out/lib
 
@@ -89,12 +73,7 @@ let
 
       # Copy modprobe.
       cp -v ${pkgs.kmod}/bin/kmod $out/bin/
-      ln -s kmod $out/bin/modprobe
-
-      # Maybe copy cifs utils
-      ${optionalString needsCifsUtils ''
-        cp -v ${pkgs.cifs_utils}/sbin/mount.cifs $out/bin
-      ''}
+      ln -sf kmod $out/bin/modprobe
 
       ${config.boot.initrd.extraUtilsCommands}
 
@@ -140,7 +119,7 @@ let
   udevRules = pkgs.stdenv.mkDerivation {
     name = "udev-rules";
     buildCommand = ''
-      ensureDir $out
+      mkdir -p $out
 
       echo 'ENV{LD_LIBRARY_PATH}="${extraUtils}/lib"' > $out/00-env.rules
 
@@ -313,6 +292,13 @@ in
       example = "xz";
     };
 
+    boot.initrd.supportedFilesystems = mkOption {
+      default = [ ];
+      example = [ "btrfs" ];
+      type = types.listOf types.string;
+      description = "Names of supported filesystem types in the initial ramdisk.";
+    };
+
     fileSystems = mkOption {
       options.neededForBoot = mkOption {
         default = false;
@@ -347,5 +333,7 @@ in
     # Prevent systemd from waiting for the /dev/root symlink.
     systemd.units."dev-root.device".text = "";
 
+    boot.initrd.supportedFilesystems = map (fs: fs.fsType) fileSystems;
+
   };
 }
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index eff2fb583bab..6fff776f8581 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -29,7 +29,9 @@ setPath "@path@"
 # Normally, stage 1 mounts the root filesystem read/writable.
 # However, in some environments, stage 2 is executed directly, and the
 # root is read-only.  So make it writable here.
-mount -n -o remount,rw /
+if [ "$container" != systemd-nspawn ]; then
+    mount -n -o remount,rw none /
+fi
 
 
 # Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a
@@ -98,12 +100,6 @@ mkdir -m 0755 -p /etc/nixos
 rm -rf /var/run /var/lock
 rm -f /etc/{group,passwd,shadow}.lock
 
-if test -n "@cleanTmpDir@"; then
-    echo -n "cleaning \`/tmp'..."
-    find /tmp -maxdepth 1 -mindepth 1 -print0 | xargs -0r rm -rf --one-file-system
-    echo " done"
-fi
-
 
 # Also get rid of temporary GC roots.
 rm -rf /nix/var/nix/gcroots/tmp /nix/var/nix/temproots
@@ -186,4 +182,4 @@ echo "starting systemd..."
 PATH=/run/current-system/systemd/lib/systemd \
     MODULE_DIR=/run/booted-system/kernel-modules/lib/modules \
     LOCALE_ARCHIVE=/run/current-system/sw/lib/locale/locale-archive \
-    exec systemd --log-target=journal # --log-level=debug --log-target=console --crash-shell
+    exec systemd
diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix
index f53c3b8b8e70..6155bb37cc52 100644
--- a/nixos/modules/system/boot/stage-2.nix
+++ b/nixos/modules/system/boot/stage-2.nix
@@ -17,7 +17,7 @@ let
     src = ./stage-2-init.sh;
     shellDebug = "${pkgs.bashInteractive}/bin/bash";
     isExecutable = true;
-    inherit (config.boot) devShmSize runSize cleanTmpDir;
+    inherit (config.boot) devShmSize runSize;
     inherit (config.nix) readOnlyStore;
     inherit (config.networking) useHostResolvConf;
     ttyGid = config.ids.gids.tty;
@@ -26,8 +26,7 @@ let
         pkgs.utillinux
         pkgs.sysvtools
         pkgs.openresolv
-      ] ++ (optional config.boot.cleanTmpDir pkgs.findutils)
-      ++ optional config.nix.readOnlyStore readonlyMountpoint;
+      ] ++ optional config.nix.readOnlyStore readonlyMountpoint;
     postBootCommands = pkgs.writeText "local-cmds"
       ''
         ${config.boot.postBootCommands}
@@ -81,15 +80,6 @@ in
         '';
       };
 
-      # FIXME: should replace this with something that uses systemd-tmpfiles.
-      cleanTmpDir = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to delete all files in <filename>/tmp</filename> during boot.
-        '';
-      };
-
     };
 
   };
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 51ebca7dd43c..e353e9246b0e 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -162,10 +162,7 @@ let
       "systemd-sysctl.service"
     ]
 
-    ++ optionals cfg.enableEmergencyMode [
-      "emergency.target"
-      "emergency.service"
-    ];
+    ++ cfg.additionalUpstreamSystemUnits;
 
   upstreamSystemWants =
     [ #"basic.target.wants"
@@ -317,7 +314,9 @@ let
         ''
           [Service]
           ${let env = cfg.globalEnvironment // def.environment;
-            in concatMapStrings (n: "Environment=\"${n}=${getAttr n env}\"\n") (attrNames env)}
+            in concatMapStrings (n:
+              let s = "Environment=\"${n}=${getAttr n env}\"\n";
+              in if stringLength s >= 2048 then throw "The value of the environment variable ‘${n}’ in systemd service ‘${name}.service’ is too long." else s) (attrNames env)}
           ${if def.reloadIfChanged then ''
             X-ReloadIfChanged=true
           '' else if !def.restartIfChanged then ''
@@ -635,19 +634,6 @@ in
       '';
     };
 
-    systemd.enableEmergencyMode = mkOption {
-      default = true;
-      type = types.bool;
-      description = ''
-        Whether to enable emergency mode, which is an
-        <command>sulogin</command> shell started on the console if
-        mounting a filesystem fails.  Since some machines (like EC2
-        instances) have no console of any kind, emergency mode doesn't
-        make sense, and it's better to continue with the boot insofar
-        as possible.
-      '';
-    };
-
     systemd.tmpfiles.rules = mkOption {
       type = types.listOf types.str;
       default = [];
@@ -690,6 +676,15 @@ in
       description = "Definition of systemd per-user socket units.";
     };
 
+    systemd.additionalUpstreamSystemUnits = mkOption {
+      default = [ ];
+      type = types.listOf types.str;
+      example = [ "debug-shell.service" "systemd-quotacheck.service" ];
+      description = ''
+        Additional units shipped with systemd that shall be enabled.
+      '';
+    };
+
   };
 
 
@@ -749,7 +744,7 @@ in
         # Make all journals readable to users in the wheel and adm
         # groups, in addition to those in the systemd-journal group.
         # Users can always read their own journals.
-        ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal
+        ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal || true
       '';
 
     # Target for ‘charon send-keys’ to hook into.
@@ -824,5 +819,8 @@ in
 
     systemd.services."user@".restartIfChanged = false;
 
+    systemd.services.systemd-remount-fs.restartIfChanged = false;
+    systemd.services.systemd-journal-flush.restartIfChanged = false;
+
   };
 }
diff --git a/nixos/modules/system/boot/tmp.nix b/nixos/modules/system/boot/tmp.nix
new file mode 100644
index 000000000000..5bf5e2eb2ec5
--- /dev/null
+++ b/nixos/modules/system/boot/tmp.nix
@@ -0,0 +1,39 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+
+  ###### interface
+
+  options = {
+
+    boot.cleanTmpDir = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to delete all files in <filename>/tmp</filename> during boot.
+      '';
+    };
+
+    boot.tmpOnTmpfs = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+         Whether to mount a tmpfs on <filename>/tmp</filename> during boot.
+      '';
+    };
+
+  };
+
+  ###### implementation
+
+  config = {
+
+    systemd.additionalUpstreamSystemUnits = optional config.boot.tmpOnTmpfs "tmp.mount";
+
+    systemd.tmpfiles.rules = optional config.boot.cleanTmpDir "D! /tmp 1777 root root";
+
+  };
+
+}
\ No newline at end of file
diff --git a/nixos/modules/system/etc/etc.nix b/nixos/modules/system/etc/etc.nix
index 22d55a9e246c..b57b03bcf962 100644
--- a/nixos/modules/system/etc/etc.nix
+++ b/nixos/modules/system/etc/etc.nix
@@ -132,7 +132,7 @@ in
       ''
         # Set up the statically computed bits of /etc.
         echo "setting up /etc..."
-        ${pkgs.perl}/bin/perl ${./setup-etc.pl} ${etc}/etc
+        ${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl ${./setup-etc.pl} ${etc}/etc
       '';
 
   };
diff --git a/nixos/modules/system/etc/setup-etc.pl b/nixos/modules/system/etc/setup-etc.pl
index 8ba9a370b27a..d7e15eccefcd 100644
--- a/nixos/modules/system/etc/setup-etc.pl
+++ b/nixos/modules/system/etc/setup-etc.pl
@@ -3,6 +3,7 @@ use File::Find;
 use File::Copy;
 use File::Path;
 use File::Basename;
+use File::Slurp;
 
 my $etc = $ARGV[0] or die;
 my $static = "/etc/static";
@@ -46,35 +47,55 @@ sub cleanup {
 find(\&cleanup, "/etc");
 
 
+# Use /etc/.clean to keep track of copied files.
+my @oldCopied = read_file("/etc/.clean", chomp => 1, err_mode => 'quiet');
+open CLEAN, ">>/etc/.clean";
+
+
 # For every file in the etc tree, create a corresponding symlink in
 # /etc to /etc/static.  The indirection through /etc/static is to make
 # switching to a new configuration somewhat more atomic.
+my %created;
+my @copied;
+
 sub link {
     my $fn = substr $File::Find::name, length($etc) + 1 or next;
     my $target = "/etc/$fn";
     File::Path::make_path(dirname $target);
+    $created{$fn} = 1;
     if (-e "$_.mode") {
-        open MODE, "<$_.mode";
-        my $mode = <MODE>; chomp $mode;
-        close MODE;
+        my $mode = read_file("$_.mode"); chomp $mode;
         if ($mode eq "direct-symlink") {
             atomicSymlink readlink("$static/$fn"), $target or warn;
         } else {
-            open UID, "<$_.uid";
-            my $uid = <UID>; chomp $uid;
-            close UID;
-            open GID, "<$_.gid";
-            my $gid = <GID>; chomp $gid;
-            close GID;
-
+            my $uid = read_file("$_.uid"); chomp $uid;
+            my $gid = read_file("$_.gid"); chomp $gid;
             copy "$static/$fn", "$target.tmp" or warn;
             chown int($uid), int($gid), "$target.tmp" or warn;
             chmod oct($mode), "$target.tmp" or warn;
             rename "$target.tmp", $target or warn;
         }
+        push @copied, $fn;
+        print CLEAN "$fn\n";
     } elsif (-l "$_") {
         atomicSymlink "$static/$fn", $target or warn;
     }
 }
 
 find(\&link, $etc);
+
+
+# Delete files that were copied in a previous version but not in the
+# current.
+foreach my $fn (@oldCopied) {
+    if (!defined $created{$fn}) {
+        $fn = "/etc/$fn";
+        print STDERR "removing obsolete file ‘$fn’...\n";
+        unlink "$fn";
+    }
+}
+
+
+# Rewrite /etc/.clean.
+close CLEAN;
+write_file("/etc/.clean", map { "$_\n" } @copied);
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
index d350bc1b5d0e..64a20034f3cc 100644
--- a/nixos/modules/tasks/filesystems.nix
+++ b/nixos/modules/tasks/filesystems.nix
@@ -9,7 +9,7 @@ let
 
   prioOption = prio: optionalString (prio !=null) " pri=${toString prio}";
 
-  fileSystemOpts = { name, ... }: {
+  fileSystemOpts = { name, config, ... }: {
 
     options = {
 
@@ -68,6 +68,7 @@ let
 
     config = {
       mountPoint = mkDefault name;
+      device = mkIf (config.fsType == "tmpfs") (mkDefault config.fsType);
     };
 
   };
@@ -124,13 +125,6 @@ in
       description = "Names of supported filesystem types.";
     };
 
-    boot.initrd.supportedFilesystems = mkOption {
-      default = [ ];
-      example = [ "btrfs" ];
-      type = types.listOf types.string;
-      description = "Names of supported filesystem types in the initial ramdisk.";
-    };
-
   };
 
 
@@ -140,15 +134,11 @@ in
 
     boot.supportedFilesystems = map (fs: fs.fsType) fileSystems;
 
-    boot.initrd.supportedFilesystems =
-      map (fs: fs.fsType)
-        (filter (fs: fs.mountPoint == "/" || fs.neededForBoot) fileSystems);
-
     # Add the mount helpers to the system path so that `mount' can find them.
     system.fsPackages = [ pkgs.dosfstools ];
 
     environment.systemPackages =
-      [ pkgs.ntfs3g pkgs.cifs_utils pkgs.fuse ]
+      [ pkgs.ntfs3g pkgs.fuse ]
       ++ config.system.fsPackages;
 
     environment.etc.fstab.text =
@@ -157,7 +147,9 @@ in
 
         # Filesystems.
         ${flip concatMapStrings fileSystems (fs:
-            (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}")
+            (if fs.device != null then fs.device
+             else if fs.label != null then "/dev/disk/by-label/${fs.label}"
+             else throw "No device specified for mount point ‘${fs.mountPoint}’.")
             + " " + fs.mountPoint
             + " " + fs.fsType
             + " " + fs.options
diff --git a/nixos/modules/tasks/filesystems/cifs.nix b/nixos/modules/tasks/filesystems/cifs.nix
new file mode 100644
index 000000000000..c60f175db841
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/cifs.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  inInitrd = any (fs: fs == "cifs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = {
+
+    system.fsPackages = [ pkgs.cifs_utils ];
+
+    boot.initrd.availableKernelModules = mkIf inInitrd
+      [ "cifs" "nls_utf8" "hmac" "md4" "ecb" "des_generic" "sha256" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        cp -v ${pkgs.cifs_utils}/sbin/mount.cifs $out/bin
+      '';
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/unionfs-fuse.nix b/nixos/modules/tasks/filesystems/unionfs-fuse.nix
index 5b7777180568..fe195e0db0b6 100644
--- a/nixos/modules/tasks/filesystems/unionfs-fuse.nix
+++ b/nixos/modules/tasks/filesystems/unionfs-fuse.nix
@@ -2,14 +2,21 @@
 
 {
   config = lib.mkMerge [
+
     (lib.mkIf (lib.any (fs: fs == "unionfs-fuse") config.boot.initrd.supportedFilesystems) {
       boot.initrd.kernelModules = [ "fuse" ];
-  
+
       boot.initrd.extraUtilsCommands = ''
         cp -v ${pkgs.fuse}/lib/libfuse* $out/lib
+        cp -v ${pkgs.fuse}/sbin/mount.fuse $out/bin
         cp -v ${pkgs.unionfs-fuse}/bin/unionfs $out/bin
+        substitute ${pkgs.unionfs-fuse}/sbin/mount.unionfs-fuse $out/bin/mount.unionfs-fuse \
+          --replace '${pkgs.bash}/bin/bash' /bin/sh \
+          --replace '${pkgs.fuse}/sbin' /bin \
+          --replace '${pkgs.unionfs-fuse}/bin' /bin
+        chmod +x $out/bin/mount.unionfs-fuse
       '';
-  
+
       boot.initrd.postDeviceCommands = ''
           # Hacky!!! fuse hard-codes the path to mount
           mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
@@ -17,8 +24,10 @@
           ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
         '';
     })
+
     (lib.mkIf (lib.any (fs: fs == "unionfs-fuse") config.boot.supportedFilesystems) {
       system.fsPackages = [ pkgs.unionfs-fuse ];
     })
+
   ];
 }
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 991f9f261450..7dabe70f00c4 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -7,6 +7,7 @@ let
   cfg = config.networking;
   interfaces = attrValues cfg.interfaces;
   hasVirtuals = any (i: i.virtual) interfaces;
+  hasSits = cfg.sits != { };
   hasBonds = cfg.bonds != { };
 
   interfaceOpts = { name, ... }: {
@@ -321,6 +322,66 @@ in
       };
     };
 
+    networking.sits = mkOption {
+      type = types.attrsOf types.optionSet;
+      default = { };
+      example = {
+        hurricane = {
+          remote = "10.0.0.1";
+          local = "10.0.0.22";
+          ttl = 255;
+        };
+        msipv6 = {
+          remote = "192.168.0.1";
+          dev = "enp3s0";
+          ttl = 127;
+        };
+      };
+      description = ''
+        This option allows you to define 6-to-4 interfaces which should be automatically created.
+      '';
+      options = {
+
+        remote = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "10.0.0.1";
+          description = ''
+            The address of the remote endpoint to forward traffic over.
+          '';
+        };
+
+        local = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "10.0.0.22";
+          description = ''
+            The address of the local endpoint which the remote
+            side should send packets to.
+          '';
+        };
+
+        ttl = mkOption {
+          type = types.nullOr types.int;
+          default = null;
+          example = 255;
+          description = ''
+            The time-to-live of the connection to the remote tunnel endpoint.
+          '';
+        };
+
+        dev = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "enp4s0f0";
+          description = ''
+            The underlying network device on which the tunnel resides.
+          '';
+        };
+
+      };
+    };
+
     networking.vlans = mkOption {
       default = { };
       example = {
@@ -380,6 +441,7 @@ in
     boot.kernelModules = [ ]
       ++ optional cfg.enableIPv6 "ipv6"
       ++ optional hasVirtuals "tun"
+      ++ optional hasSits "sit"
       ++ optional hasBonds "bonding";
 
     boot.extraModprobeConfig =
@@ -641,6 +703,32 @@ in
             '';
           };
 
+        createSitDevice = n: v:
+          let
+            deps = optional (v.dev != null) "sys-subsystem-net-devices-${v.dev}.device";
+          in
+          { description = "6-to-4 Tunnel Interface ${n}";
+            wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ];
+            bindsTo = deps;
+            after = deps;
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute ];
+            script = ''
+              # Remove Dead Interfaces
+              ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}"
+              ip link add "${n}" type sit \
+                ${optionalString (v.remote != null) "remote \"${v.remote}\""} \
+                ${optionalString (v.local != null) "local \"${v.local}\""} \
+                ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \
+                ${optionalString (v.dev != null) "dev \"${v.dev}\""}
+              ip link set "${n}" up
+            '';
+            postStop = ''
+              ip link delete "${n}"
+            '';
+          };
+
         createVlanDevice = n: v:
           let
             deps = [ "sys-subsystem-net-devices-${v.interface}.device" ];
@@ -668,6 +756,7 @@ in
            map createTunDevice (filter (i: i.virtual) interfaces))
          // mapAttrs createBridgeDevice cfg.bridges
          // mapAttrs createBondDevice cfg.bonds
+         // mapAttrs createSitDevice cfg.sits
          // mapAttrs createVlanDevice cfg.vlans
          // { "network-setup" = networkSetup; };
 
diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix
index 4be2c3eb4c47..d1c6f8ac1565 100644
--- a/nixos/modules/tasks/trackpoint.nix
+++ b/nixos/modules/tasks/trackpoint.nix
@@ -46,21 +46,15 @@ with lib;
 
   config = mkIf config.hardware.trackpoint.enable {
 
-    jobs.trackpoint =
-      { description = "Initialize trackpoint";
-
-        startOn = "started udev";
-
-        task = true;
-
-        script = ''
-          echo -n ${toString config.hardware.trackpoint.sensitivity} \
-            > /sys/devices/platform/i8042/serio1/sensitivity
-          echo -n ${toString config.hardware.trackpoint.speed} \
-            > /sys/devices/platform/i8042/serio1/speed
-        '';
-      };
-         
+    services.udev.extraRules =
+    ''
+      ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="TPPS/2 IBM TrackPoint", ATTR{device/speed}="${toString config.hardware.trackpoint.speed}", ATTR{device/sensitivity}="${toString config.hardware.trackpoint.sensitivity}"
+    '';
+
+    system.activationScripts.trackpoint =
+      ''
+        ${config.systemd.package}/bin/udevadm trigger --attr-match=name="TPPS/2 IBM TrackPoint"
+      '';
   };
 
 }
diff --git a/nixos/modules/tasks/tty-backgrounds-combine.sh b/nixos/modules/tasks/tty-backgrounds-combine.sh
index 1e0d8758a6ee..55c3a1ebfa8a 100644
--- a/nixos/modules/tasks/tty-backgrounds-combine.sh
+++ b/nixos/modules/tasks/tty-backgrounds-combine.sh
@@ -3,7 +3,7 @@ source $stdenv/setup
 ttys=($ttys)
 themes=($themes)
 
-ensureDir $out
+mkdir -p $out
 
 defaultName=$(cd $default && ls | grep -v default)
 echo $defaultName
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index 9100a433cd63..54a376c9560e 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -66,13 +66,22 @@ let kernel = config.boot.kernelPackages.kernel; in
     # Panic if an error occurs in stage 1 (rather than waiting for
     # user intervention).
     boot.kernelParams =
-      [ "console=tty1" "console=ttyS0" "panic=1" "boot.panic_on_fail" ];
+      [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ];
 
     # `xwininfo' is used by the test driver to query open windows.
     environment.systemPackages = [ pkgs.xorg.xwininfo ];
 
     # Log everything to the serial console.
-    services.journald.console = "/dev/console";
+    services.journald.extraConfig =
+      ''
+        ForwardToConsole=yes
+        MaxLevelConsole=debug
+      '';
+
+    # Don't clobber the console with duplicate systemd messages.
+    systemd.extraConfig = "ShowStatus=no";
+
+    boot.consoleLogLevel = 7;
 
     # Prevent tests from accessing the Internet.
     networking.defaultGateway = mkOverride 150 "";
@@ -88,6 +97,9 @@ let kernel = config.boot.kernelPackages.kernel; in
 
     networking.usePredictableInterfaceNames = false;
 
+    # Make it easy to log in as root when running the test interactively.
+    security.initialRootPassword = mkDefault "";
+
   };
 
 }
diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix
index 7d6109f212ac..e129e496fe36 100644
--- a/nixos/modules/virtualisation/amazon-image.nix
+++ b/nixos/modules/virtualisation/amazon-image.nix
@@ -172,7 +172,7 @@ in
     boot.initrd.extraUtilsCommands =
       ''
         # We need swapon in the initrd.
-        cp ${pkgs.utillinux}/sbin/swapon $out/bin
+        cp --remove-destination ${pkgs.utillinux}/sbin/swapon $out/bin
       '';
 
     # Don't put old configurations in the GRUB menu.  The user has no
diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix
index b81f97f2b4ec..84e3aa283520 100644
--- a/nixos/modules/virtualisation/container-config.nix
+++ b/nixos/modules/virtualisation/container-config.nix
@@ -89,6 +89,8 @@ with lib;
         restartIfChanged = false;
       };
 
+    systemd.services.systemd-remount-fs.enable = false;
+
   };
 
 }
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index d0d04d9a1e5d..292b96e6eb24 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -32,7 +32,10 @@ let
         fi
       fi
 
-      exec "$1"
+      # Start the regular stage 1 script, passing the bind-mounted
+      # notification socket from the host to allow the container
+      # systemd to signal readiness to the host systemd.
+      NOTIFY_SOCKET=/var/lib/private/host-notify exec "$1"
     '';
 
   system = config.nixpkgs.system;
@@ -168,17 +171,18 @@ in
 
         preStart =
           ''
-            mkdir -p -m 0755 $root/var/lib
+            # Clean up existing machined registration and interfaces.
+            machinectl terminate "$INSTANCE" 2> /dev/null || true
 
-            # Create a named pipe to get a signal when the container
-            # has finished booting.
-            rm -f $root/var/lib/startup-done
-            mkfifo -m 0600 $root/var/lib/startup-done
+            if [ "$PRIVATE_NETWORK" = 1 ]; then
+              ip link del dev "ve-$INSTANCE" 2> /dev/null || true
+            fi
          '';
 
         script =
           ''
             mkdir -p -m 0755 "$root/etc" "$root/var/lib"
+            mkdir -p -m 0700 "$root/var/lib/private"
             if ! [ -e "$root/etc/os-release" ]; then
               touch "$root/etc/os-release"
             fi
@@ -187,6 +191,8 @@ in
               "/nix/var/nix/profiles/per-container/$INSTANCE" \
               "/nix/var/nix/gcroots/per-container/$INSTANCE"
 
+            cp -f /etc/resolv.conf "$root/etc/resolv.conf"
+
             if [ "$PRIVATE_NETWORK" = 1 ]; then
               extraFlags+=" --network-veth"
             fi
@@ -203,12 +209,16 @@ in
               fi
             ''}
 
+            # Run systemd-nspawn without startup notification (we'll
+            # wait for the container systemd to signal readiness).
+            EXIT_ON_REBOOT=1 NOTIFY_SOCKET= \
             exec ${config.systemd.package}/bin/systemd-nspawn \
               --keep-unit \
               -M "$INSTANCE" -D "$root" $extraFlags \
               --bind-ro=/nix/store \
               --bind-ro=/nix/var/nix/db \
               --bind-ro=/nix/var/nix/daemon-socket \
+              --bind=/run/systemd/notify:/var/lib/private/host-notify \
               --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
               --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
               --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
@@ -220,12 +230,6 @@ in
 
         postStart =
           ''
-            # This blocks until the container-startup-done service
-            # writes something to this pipe.  FIXME: it also hangs
-            # until the start timeout expires if systemd-nspawn exits.
-            read x < $root/var/lib/startup-done
-            rm -f $root/var/lib/startup-done
-
             if [ "$PRIVATE_NETWORK" = 1 ]; then
               ifaceHost=ve-$INSTANCE
               ip link set dev $ifaceHost up
@@ -240,23 +244,42 @@ in
 
         preStop =
           ''
-            machinectl poweroff "$INSTANCE"
+            machinectl poweroff "$INSTANCE" || true
           '';
 
         restartIfChanged = false;
         #reloadIfChanged = true; # FIXME
 
-        serviceConfig.ExecReload = pkgs.writeScript "reload-container"
-          ''
-            #! ${pkgs.stdenv.shell} -e
-            SYSTEM_PATH=/nix/var/nix/profiles/system
-            echo $SYSTEM_PATH/bin/switch-to-configuration test | \
-              ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket -
-          '';
+        serviceConfig = {
+          ExecReload = pkgs.writeScript "reload-container"
+            ''
+              #! ${pkgs.stdenv.shell} -e
+              SYSTEM_PATH=/nix/var/nix/profiles/system
+              echo $SYSTEM_PATH/bin/switch-to-configuration test | \
+                ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket -
+            '';
+
+          SyslogIdentifier = "container %i";
+
+          EnvironmentFile = "-/etc/containers/%i.conf";
+
+          Type = "notify";
+
+          NotifyAccess = "all";
 
-        serviceConfig.SyslogIdentifier = "container %i";
+          # Note that on reboot, systemd-nspawn returns 10, so this
+          # unit will be restarted. On poweroff, it returns 0, so the
+          # unit won't be restarted.
+          Restart = "on-failure";
 
-        serviceConfig.EnvironmentFile = "-/etc/containers/%i.conf";
+          # Hack: we don't want to kill systemd-nspawn, since we call
+          # "machinectl poweroff" in preStop to shut down the
+          # container cleanly. But systemd requires sending a signal
+          # (at least if we want remaining processes to be killed
+          # after the timeout). So send an ignored signal.
+          KillMode = "mixed";
+          KillSignal = "WINCH";
+        };
       };
 
     # Generate a configuration file in /etc/containers for each
@@ -290,5 +313,30 @@ in
 
     environment.systemPackages = [ nixos-container ];
 
+    # Start containers at boot time.
+    systemd.services.all-containers =
+      { description = "All Containers";
+
+        wantedBy = [ "multi-user.target" ];
+
+        unitConfig.ConditionDirectoryNotEmpty = "/etc/containers";
+
+        serviceConfig.Type = "oneshot";
+
+        script =
+          ''
+            res=0
+            shopt -s nullglob
+            for i in /etc/containers/*.conf; do
+              AUTO_START=
+              source "$i"
+              if [ "$AUTO_START" = 1 ]; then
+                systemctl start "container@$(basename "$i" .conf).service" || res=1
+              fi
+            done
+            exit $res
+          ''; # */
+      };
+
   };
 }
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
new file mode 100644
index 000000000000..a0aa61353269
--- /dev/null
+++ b/nixos/modules/virtualisation/docker.nix
@@ -0,0 +1,109 @@
+# Systemd services for docker.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.virtualisation.docker;
+
+in
+
+{
+  ###### interface
+
+  options.virtualisation.docker = {
+    enable =
+      mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            This option enables docker, a daemon that manages
+            linux containers. Users in the "docker" group can interact with
+            the daemon (e.g. to start or stop containers) using the
+            <command>docker</command> command line tool.
+          '';
+      };
+    socketActivation =
+      mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            This option enables docker with socket activation. I.e. docker will
+            start when first called by client.
+
+            Note: This is false by default because systemd lower than 214 that
+            nixos uses so far, doesn't support SocketGroup option, so socket
+            created by docker has root group now. This will likely be changed
+            in future.  So set this option explicitly to false if you wish.
+          '';
+      };
+    extraOptions =
+      mkOption {
+        type = types.str;
+        default = "";
+        description =
+          ''
+            The extra command-line options to pass to
+            <command>docker</command> daemon.
+          '';
+      };
+
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable (mkMerge [
+    { environment.systemPackages = [ pkgs.docker ];
+    }
+    (mkIf cfg.socketActivation {
+
+      systemd.services.docker = {
+        description = "Docker Application Container Engine";
+        after = [ "network.target" "docker.socket" ];
+        requires = [ "docker.socket" ];
+        serviceConfig = {
+          ExecStart = "${pkgs.docker}/bin/docker --daemon=true --host=fd:// --group=docker ${cfg.extraOptions}";
+          #  I'm not sure if that limits aren't too high, but it's what
+          #  goes in config bundled with docker itself
+          LimitNOFILE = 1048576;
+          LimitNPROC = 1048576;
+        };
+      };
+
+      systemd.sockets.docker = {
+        description = "Docker Socket for the API";
+        wantedBy = [ "sockets.target" ];
+        socketConfig = {
+          ListenStream = "/var/run/docker.sock";
+          SocketMode = "0660";
+          SocketUser = "root";
+          SocketGroup = "docker";
+        };
+      };
+    })
+    (mkIf (!cfg.socketActivation) {
+
+      systemd.services.docker = {
+        description = "Docker Application Container Engine";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+        serviceConfig = {
+          ExecStart = "${pkgs.docker}/bin/docker --daemon=true --group=docker ${cfg.extraOptions}";
+          #  I'm not sure if that limits aren't too high, but it's what
+          #  goes in config bundled with docker itself
+          LimitNOFILE = 1048576;
+          LimitNPROC = 1048576;
+        };
+
+        # Presumably some containers are running we don't want to interrupt
+        restartIfChanged = false;
+      };
+    })
+  ]);
+
+}
diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix
index 246d35065317..93a83a3e42af 100644
--- a/nixos/modules/virtualisation/ec2-data.nix
+++ b/nixos/modules/virtualisation/ec2-data.nix
@@ -22,21 +22,22 @@ with lib;
     systemd.services."fetch-ec2-data" =
       { description = "Fetch EC2 Data";
 
-        wantedBy = [ "multi-user.target" ];
+        wantedBy = [ "multi-user.target" "sshd.service" ];
         before = [ "sshd.service" ];
-        after = [ "network.target" ];
+        wants = [ "ip-up.target" ];
+        after = [ "ip-up.target" ];
 
-        path = [ pkgs.curl pkgs.iproute ];
+        path = [ pkgs.wget pkgs.iproute ];
 
         script =
           ''
             ip route del blackhole 169.254.169.254/32 || true
 
-            curl="curl --retry 3 --retry-delay 0 --fail"
+            wget="wget -q --retry-connrefused -O -"
 
             echo "setting host name..."
             ${optionalString (config.networking.hostName == "") ''
-              ${pkgs.nettools}/bin/hostname $($curl http://169.254.169.254/1.0/meta-data/hostname)
+              ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/1.0/meta-data/hostname)
             ''}
 
             # Don't download the SSH key if it has already been injected
@@ -44,7 +45,7 @@ with lib;
             if ! [ -e /root/.ssh/authorized_keys ]; then
                 echo "obtaining SSH key..."
                 mkdir -p /root/.ssh
-                $curl -o /root/key.pub http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key
+                $wget http://169.254.169.254/1.0/meta-data/public-keys/0/openssh-key > /root/key.pub
                 if [ $? -eq 0 -a -e /root/key.pub ]; then
                     if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then
                         cat /root/key.pub >> /root/.ssh/authorized_keys
@@ -58,7 +59,7 @@ with lib;
             # Extract the intended SSH host key for this machine from
             # the supplied user data, if available.  Otherwise sshd will
             # generate one normally.
-            $curl http://169.254.169.254/2011-01-01/user-data > /root/user-data || true
+            $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true
             key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)"
             key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)"
             if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then
diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix
index d55b74202436..697423ac60be 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -119,21 +119,25 @@ in
     169.254.169.254 metadata.google.internal metadata
   '';
 
-  systemd.services.fetch-root-authorized-keys =
-    { description = "Fetch authorized_keys for root user";
+  networking.usePredictableInterfaceNames = false;
 
-      wantedBy = [ "multi-user.target" ];
+  systemd.services.fetch-ssh-keys =
+    { description = "Fetch host keys and authorized_keys for root user";
+
+      wantedBy = [ "sshd.service" ];
       before = [ "sshd.service" ];
-      after = [ "network.target" ];
+      after = [ "network-online.target" ];
+      wants = [ "network-online.target" ];
 
-      path  = [ pkgs.curl ];
+      path  = [ pkgs.wget ];
       script =
         ''
+          wget="wget --retry-connrefused -t 6 --waitretry=10"
           # Don't download the SSH key if it has already been downloaded
           if ! [ -e /root/.ssh/authorized_keys ]; then
                 echo "obtaining SSH key..."
                 mkdir -p /root/.ssh
-                curl -o /root/authorized-keys-metadata http://metadata/0.1/meta-data/authorized-keys
+                $wget -O /root/authorized-keys-metadata http://metadata/0.1/meta-data/authorized-keys
                 if [ $? -eq 0 -a -e /root/authorized-keys-metadata ]; then
                     cat /root/authorized-keys-metadata | cut -d: -f2- > /root/key.pub
                     if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then
@@ -144,10 +148,26 @@ in
                     rm -f /root/key.pub /root/authorized-keys-metadata
                 fi
           fi
+
+          echo "obtaining SSH private host key..."
+          $wget -O /root/ssh_host_ecdsa_key  http://metadata/0.1/meta-data/attributes/ssh_host_ecdsa_key
+          if [ $? -eq 0 -a -e /root/ssh_host_ecdsa_key ]; then
+              mv -f /root/ssh_host_ecdsa_key /etc/ssh/ssh_host_ecdsa_key
+              echo "downloaded ssh_host_ecdsa_key"
+              chmod 600 /etc/ssh/ssh_host_ecdsa_key
+          fi
+
+          echo "obtaining SSH public host key..."
+          $wget -O /root/ssh_host_ecdsa_key.pub http://metadata/0.1/meta-data/attributes/ssh_host_ecdsa_key_pub
+          if [ $? -eq 0 -a -e /root/ssh_host_ecdsa_key.pub ]; then
+              mv -f /root/ssh_host_ecdsa_key.pub /etc/ssh/ssh_host_ecdsa_key.pub
+              echo "downloaded ssh_host_ecdsa_key.pub"
+              chmod 644 /etc/ssh/ssh_host_ecdsa_key.pub
+          fi
         '';
       serviceConfig.Type = "oneshot";
       serviceConfig.RemainAfterExit = true;
+      serviceConfig.StandardError = "journal+console";
+      serviceConfig.StandardOutput = "journal+console";
      };
-
-
 }
diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl
index 5083abd84489..bf6f16fc6c77 100644
--- a/nixos/modules/virtualisation/nixos-container.pl
+++ b/nixos/modules/virtualisation/nixos-container.pl
@@ -17,25 +17,31 @@ umask 0022;
 sub showHelp {
     print <<EOF;
 Usage: nixos-container list
-       nixos-container create <container-name> [--config <string>] [--ensure-unique-name]
+       nixos-container create <container-name> [--system-path <path>] [--config <string>] [--ensure-unique-name] [--auto-start]
        nixos-container destroy <container-name>
        nixos-container start <container-name>
        nixos-container stop <container-name>
+       nixos-container status <container-name>
        nixos-container login <container-name>
        nixos-container root-login <container-name>
        nixos-container run <container-name> -- args...
        nixos-container set-root-password <container-name> <password>
        nixos-container show-ip <container-name>
+       nixos-container show-host-key <container-name>
 EOF
     exit 0;
 }
 
+my $systemPath;
 my $ensureUniqueName = 0;
+my $autoStart = 0;
 my $extraConfig;
 
 GetOptions(
     "help" => sub { showHelp() },
     "ensure-unique-name" => \$ensureUniqueName,
+    "auto-start" => \$autoStart,
+    "system-path=s" => \$systemPath,
     "config=s" => \$extraConfig
     ) or exit 1;
 
@@ -122,17 +128,13 @@ if ($action eq "create") {
     push @conf, "PRIVATE_NETWORK=1\n";
     push @conf, "HOST_ADDRESS=$hostAddress\n";
     push @conf, "LOCAL_ADDRESS=$localAddress\n";
+    push @conf, "AUTO_START=$autoStart\n";
     write_file($confFile, \@conf);
 
     close($lock);
 
     print STDERR "host IP is $hostAddress, container IP is $localAddress\n";
 
-    mkpath("$root/etc/nixos", 0, 0755);
-
-    my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
-    writeNixOSConfig $nixosConfigFile;
-
     # The per-container directory is restricted to prevent users on
     # the host from messing with guest users who happen to have the
     # same uid.
@@ -141,10 +143,21 @@ if ($action eq "create") {
     $profileDir = "$profileDir/$containerName";
     mkpath($profileDir, 0, 0755);
 
-    system("nix-env", "-p", "$profileDir/system",
-           "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>",
-           "--set", "-A", "system") == 0
-        or die "$0: failed to build initial container configuration\n";
+    # Build/set the initial configuration.
+    if (defined $systemPath) {
+        system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0
+            or die "$0: failed to set initial container configuration\n";
+    } else {
+        mkpath("$root/etc/nixos", 0, 0755);
+
+        my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
+        writeNixOSConfig $nixosConfigFile;
+
+        system("nix-env", "-p", "$profileDir/system",
+               "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>",
+               "--set", "-A", "system") == 0
+            or die "$0: failed to build initial container configuration\n";
+    }
 
     print "$containerName\n" if $ensureUniqueName;
     exit 0;
@@ -152,8 +165,16 @@ if ($action eq "create") {
 
 my $root = "/var/lib/containers/$containerName";
 my $profileDir = "/nix/var/nix/profiles/per-container/$containerName";
+my $gcRootsDir = "/nix/var/nix/gcroots/per-container/$containerName";
 my $confFile = "/etc/containers/$containerName.conf";
-die "$0: container ‘$containerName’ does not exist\n" if !-e $confFile;
+if (!-e $confFile) {
+    if ($action eq "destroy") {
+        exit 0;
+    } elsif ($action eq "status") {
+        print "gone\n";
+    }
+    die "$0: container ‘$containerName’ does not exist\n" ;
+}
 
 sub isContainerRunning {
     my $status = `systemctl show 'container\@$containerName'`;
@@ -172,6 +193,7 @@ if ($action eq "destroy") {
     stopContainer if isContainerRunning;
 
     rmtree($profileDir) if -e $profileDir;
+    rmtree($gcRootsDir) if -e $gcRootsDir;
     rmtree($root) if -e $root;
     unlink($confFile) or die;
 }
@@ -185,6 +207,10 @@ elsif ($action eq "stop") {
     stopContainer;
 }
 
+elsif ($action eq "status") {
+    print isContainerRunning() ? "up" : "down", "\n";
+}
+
 elsif ($action eq "update") {
     my $nixosConfigFile = "$root/etc/nixos/configuration.nix";
 
@@ -239,6 +265,12 @@ elsif ($action eq "show-ip") {
     print "$1\n";
 }
 
+elsif ($action eq "show-host-key") {
+    my $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub";
+    exit 1 if ! -f $fn;
+    print read_file($fn);
+}
+
 else {
     die "$0: unknown action ‘$action’\n";
 }
diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index bccf6583e47d..58386ce5cf56 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -275,12 +275,10 @@ in
 
     boot.loader.grub.device = mkVMOverride "/dev/vda";
 
-    boot.initrd.supportedFilesystems = optional cfg.writableStore "unionfs-fuse";
-
     boot.initrd.extraUtilsCommands =
       ''
         # We need mke2fs in the initrd.
-        cp ${pkgs.e2fsprogs}/sbin/mke2fs $out/bin
+        cp -f ${pkgs.e2fsprogs}/sbin/mke2fs $out/bin
       '';
 
     boot.initrd.postDeviceCommands =
@@ -303,20 +301,6 @@ in
         chmod 1777 $targetRoot/tmp
 
         mkdir -p $targetRoot/boot
-        ${optionalString cfg.writableStore ''
-          mkdir -p /unionfs-chroot/ro-store
-          mount --rbind $targetRoot/nix/store /unionfs-chroot/ro-store
-
-          mkdir /unionfs-chroot/rw-store
-          ${if cfg.writableStoreUseTmpfs then ''
-          mount -t tmpfs -o "mode=755" none /unionfs-chroot/rw-store
-          '' else ''
-          mkdir $targetRoot/.nix-rw-store
-          mount --bind $targetRoot/.nix-rw-store /unionfs-chroot/rw-store
-          ''}
-
-          unionfs -o allow_other,cow,nonempty,chroot=/unionfs-chroot,max_files=32768,hide_meta_files /rw-store=RW:/ro-store=RO $targetRoot/nix/store
-        ''}
       '';
 
     # After booting, register the closure of the paths in
@@ -343,12 +327,13 @@ in
     # configuration, where the regular value for the `fileSystems'
     # attribute should be disregarded for the purpose of building a VM
     # test image (since those filesystems don't exist in the VM).
-    fileSystems = mkVMOverride
+    fileSystems = mkVMOverride (
       { "/".device = "/dev/vda";
-        "/nix/store" =
+        ${if cfg.writableStore then "/nix/.ro-store" else "/nix/store"} =
           { device = "store";
             fsType = "9p";
             options = "trans=virtio,version=9p2000.L,msize=1048576,cache=loose";
+            neededForBoot = true;
           };
         "/tmp/xchg" =
           { device = "xchg";
@@ -362,6 +347,18 @@ in
             options = "trans=virtio,version=9p2000.L,msize=1048576";
             neededForBoot = true;
           };
+      } // optionalAttrs cfg.writableStore
+      { "/nix/store" =
+          { fsType = "unionfs-fuse";
+            device = "unionfs";
+            options = "allow_other,cow,nonempty,chroot=/mnt-root,max_files=32768,hide_meta_files,dirs=/nix/.rw-store=rw:/nix/.ro-store=ro";
+          };
+      } // optionalAttrs (cfg.writableStore && cfg.writableStoreUseTmpfs)
+      { "/nix/.rw-store" =
+          { fsType = "tmpfs";
+            options = "mode=0755";
+            neededForBoot = true;
+          };
       } // optionalAttrs cfg.useBootLoader
       { "/boot" =
           { device = "/dev/disk/by-label/boot";
@@ -369,7 +366,7 @@ in
             options = "ro";
             noCheck = true; # fsck fails on a r/o filesystem
           };
-      };
+      });
 
     swapDevices = mkVMOverride [ ];
     boot.initrd.luks.devices = mkVMOverride [];
@@ -379,7 +376,7 @@ in
 
     system.build.vm = pkgs.runCommand "nixos-vm" { preferLocalBuild = true; }
       ''
-        ensureDir $out/bin
+        mkdir -p $out/bin
         ln -s ${config.system.build.toplevel} $out/system
         ln -s ${pkgs.writeScript "run-nixos-vm" startVM} $out/bin/run-${vmName}-vm
       '';
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index 594b3e93ffeb..106b269d9e1f 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -2,109 +2,132 @@
 
 with lib;
 
-{
-  system.build.virtualBoxImage =
-    pkgs.vmTools.runInLinuxVM (
-      pkgs.runCommand "virtualbox-image"
-        { memSize = 768;
-          preVM =
-            ''
-              mkdir $out
-              diskImage=$out/image
-              ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "10G"
-              mv closure xchg/
-            '';
-          postVM =
-            ''
-              echo "creating VirtualBox disk image..."
-              ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vdi $diskImage $out/disk.vdi
-              rm $diskImage
-            '';
-          buildInputs = [ pkgs.utillinux pkgs.perl ];
-          exportReferencesGraph =
-            [ "closure" config.system.build.toplevel ];
-        }
-        ''
-          # Create a single / partition.
-          ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
-          ${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s
-          . /sys/class/block/vda1/uevent
-          mknod /dev/vda1 b $MAJOR $MINOR
-
-          # Create an empty filesystem and mount it.
-          ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
-          ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1
-          mkdir /mnt
-          mount /dev/vda1 /mnt
-
-          # The initrd expects these directories to exist.
-          mkdir /mnt/dev /mnt/proc /mnt/sys
-          mount --bind /proc /mnt/proc
-          mount --bind /dev /mnt/dev
-          mount --bind /sys /mnt/sys
-
-          # Copy all paths in the closure to the filesystem.
-          storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
-
-          echo "filling Nix store..."
-          mkdir -p /mnt/nix/store
-          set -f
-          cp -prd $storePaths /mnt/nix/store/
-
-          # Register the paths in the Nix database.
-          printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
-              chroot /mnt ${config.nix.package}/bin/nix-store --load-db
-
-          # Create the system profile to allow nixos-rebuild to work.
-          chroot /mnt ${config.nix.package}/bin/nix-env \
-              -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
-
-          # `nixos-rebuild' requires an /etc/NIXOS.
-          mkdir -p /mnt/etc/nixos
-          touch /mnt/etc/NIXOS
-
-          # `switch-to-configuration' requires a /bin/sh
-          mkdir -p /mnt/bin
-          ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
-
-          # Generate the GRUB menu.
-          ln -s vda /dev/sda
-          chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
-
-          umount /mnt/proc /mnt/dev /mnt/sys
-          umount /mnt
-        ''
-    );
-
-  system.build.virtualBoxOVA = pkgs.runCommand "virtualbox-ova"
-    { buildInputs = [ pkgs.linuxPackages.virtualbox ];
-      vmName = "NixOS ${config.system.nixosVersion} (${pkgs.stdenv.system})";
-      fileName = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.ova";
-    }
-    ''
-      echo "creating VirtualBox VM..."
-      export HOME=$PWD
-      VBoxManage createvm --name "$vmName" --register \
-        --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"}
-      VBoxManage modifyvm "$vmName" \
-        --memory 1536 --acpi on --vram 10 \
-        --nictype1 virtio --nic1 nat \
-        --audiocontroller ac97 --audio alsa \
-        --rtcuseutc on \
-        --usb on --mouse usbtablet
-      VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on
-      VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \
-        --medium ${config.system.build.virtualBoxImage}/disk.vdi
-
-      echo "exporting VirtualBox VM..."
-      mkdir -p $out
-      VBoxManage export "$vmName" --output "$out/$fileName"
-    '';
-
-  fileSystems."/".device = "/dev/disk/by-label/nixos";
-
-  boot.loader.grub.version = 2;
-  boot.loader.grub.device = "/dev/sda";
-
-  services.virtualbox.enable = true;
+let
+
+  cfg = config.virtualbox;
+
+in {
+
+  options = {
+    virtualbox = {
+      baseImageSize = mkOption {
+        type = types.str;
+        default = "10G";
+        description = ''
+          The size of the VirtualBox base image. The size string should be on
+          a format the qemu-img command accepts.
+        '';
+      };
+    };
+  };
+
+  config = {
+    system.build.virtualBoxImage =
+      pkgs.vmTools.runInLinuxVM (
+        pkgs.runCommand "virtualbox-image"
+          { memSize = 768;
+            preVM =
+              ''
+                mkdir $out
+                diskImage=$out/image
+                ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage "${cfg.baseImageSize}"
+                mv closure xchg/
+              '';
+            postVM =
+              ''
+                echo "creating VirtualBox disk image..."
+                ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vdi $diskImage $out/disk.vdi
+                rm $diskImage
+              '';
+            buildInputs = [ pkgs.utillinux pkgs.perl ];
+            exportReferencesGraph =
+              [ "closure" config.system.build.toplevel ];
+          }
+          ''
+            # Create a single / partition.
+            ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos
+            ${pkgs.parted}/sbin/parted /dev/vda -- mkpart primary ext2 1M -1s
+            . /sys/class/block/vda1/uevent
+            mknod /dev/vda1 b $MAJOR $MINOR
+  
+            # Create an empty filesystem and mount it.
+            ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1
+            ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1
+            mkdir /mnt
+            mount /dev/vda1 /mnt
+  
+            # The initrd expects these directories to exist.
+            mkdir /mnt/dev /mnt/proc /mnt/sys
+            mount --bind /proc /mnt/proc
+            mount --bind /dev /mnt/dev
+            mount --bind /sys /mnt/sys
+  
+            # Copy all paths in the closure to the filesystem.
+            storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure)
+  
+            echo "filling Nix store..."
+            mkdir -p /mnt/nix/store
+            set -f
+            cp -prd $storePaths /mnt/nix/store/
+  
+            mkdir -p /mnt/etc/nix
+            echo 'build-users-group = ' > /mnt/etc/nix/nix.conf
+  
+            # Register the paths in the Nix database.
+            printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
+                chroot /mnt ${config.nix.package}/bin/nix-store --load-db
+  
+            # Create the system profile to allow nixos-rebuild to work.
+            chroot /mnt ${config.nix.package}/bin/nix-env \
+                -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel}
+  
+            # `nixos-rebuild' requires an /etc/NIXOS.
+            mkdir -p /mnt/etc/nixos
+            touch /mnt/etc/NIXOS
+  
+            # `switch-to-configuration' requires a /bin/sh
+            mkdir -p /mnt/bin
+            ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh
+  
+            # Generate the GRUB menu.
+            ln -s vda /dev/sda
+            chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot
+  
+            umount /mnt/proc /mnt/dev /mnt/sys
+            umount /mnt
+          ''
+      );
+  
+    system.build.virtualBoxOVA = pkgs.runCommand "virtualbox-ova"
+      { buildInputs = [ pkgs.linuxPackages.virtualbox ];
+        vmName = "NixOS ${config.system.nixosVersion} (${pkgs.stdenv.system})";
+        fileName = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.ova";
+      }
+      ''
+        echo "creating VirtualBox VM..."
+        export HOME=$PWD
+        VBoxManage createvm --name "$vmName" --register \
+          --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"}
+        VBoxManage modifyvm "$vmName" \
+          --memory 1536 --acpi on --vram 10 \
+          --nictype1 virtio --nic1 nat \
+          --audiocontroller ac97 --audio alsa \
+          --rtcuseutc on \
+          --usb on --mouse usbtablet
+        VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on
+        VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \
+          --medium ${config.system.build.virtualBoxImage}/disk.vdi
+  
+        echo "exporting VirtualBox VM..."
+        mkdir -p $out
+        VBoxManage export "$vmName" --output "$out/$fileName"
+      '';
+  
+    fileSystems."/".device = "/dev/disk/by-label/nixos";
+  
+    boot.loader.grub.version = 2;
+    boot.loader.grub.device = "/dev/sda";
+  
+    services.virtualbox.enable = true;
+  };
 }