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/misc/ids.nix5
-rw-r--r--nixos/modules/module-list.nix6
-rw-r--r--nixos/modules/programs/dconf.nix34
-rw-r--r--nixos/modules/security/rngd.nix3
-rw-r--r--nixos/modules/services/amqp/activemq/default.nix2
-rw-r--r--nixos/modules/services/audio/mopidy.nix11
-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/syslog-ng.nix83
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix17
-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/dhcpd.nix35
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/builder.sh4
-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.nix66
-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.nix2
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix6
-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.nix4
-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/boot/stage-1-init.sh3
-rw-r--r--nixos/modules/system/boot/stage-1.nix2
-rw-r--r--nixos/modules/system/boot/stage-2-init.sh2
-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/ec2-data.nix15
-rw-r--r--nixos/modules/virtualisation/qemu-vm.nix2
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix236
49 files changed, 897 insertions, 230 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/misc/ids.nix b/nixos/modules/misc/ids.nix
index 4ba81dadb315..fa81ff8a8398 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -138,6 +138,9 @@
       znc = 128;
       polipo = 129;
       mopidy = 130;
+      unifi = 131;
+      gdm = 132;
+      dhcpd = 133;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -251,6 +254,8 @@
       polipo = 129;
       mopidy = 130;
       docker = 131;
+      gdm = 132;
+      tss = 133;
 
       # 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 2e0230f2b5e5..453899175e01 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -50,6 +50,7 @@
   ./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
@@ -126,6 +127,7 @@
   ./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
@@ -136,6 +138,7 @@
   ./services/logging/logstash.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
@@ -234,6 +237,7 @@
   ./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
@@ -278,6 +282,7 @@
   ./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/lightdm.nix
   ./services/x11/display-managers/slim.nix
@@ -289,6 +294,7 @@
   #./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
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/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/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/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix
index df3837d47f29..5b865cf4c1be 100644
--- a/nixos/modules/services/audio/mopidy.nix
+++ b/nixos/modules/services/audio/mopidy.nix
@@ -92,6 +92,17 @@ in {
       };
     };
 
+    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";
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/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/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/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/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 56946f37aaf9..4d53cd0750fb 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -20,10 +20,15 @@ let
         </Pass>
   ";
 
+  modules = pkgs.buildEnv {
+    name = "znc-modules";
+    paths = cfg.modulePackages;
+  };
+
   confOptions = { ... }: {
     options = {
       modules = mkOption {
-        type = types.listOf types.str;
+        type = types.listOf types.string;
         default = [ "partyline" "webadmin" "adminlog" "log" ];
         example = [ "partyline" "webadmin" "adminlog" "log" ];
         description = ''
@@ -31,10 +36,19 @@ 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";
-        type = types.str;
+        type = types.string;
         description = ''
           The user name to use when generating the `znc.conf` file.
           This is the user name used by the user logging into the ZNC web admin. 
@@ -44,7 +58,7 @@ let
       nick = mkOption {
         default = "znc-user";
         example = "john";
-        type = types.str;
+        type = types.string;
         description = ''
           The IRC nick to use when generating the `znc.conf` file.
         '';
@@ -53,7 +67,7 @@ let
       passBlock = mkOption {
         default = defaultPassBlock;
         example = "Must be the block generated by the `znc --makepass` command.";
-        type = types.str;
+        type = types.string;
         description = ''
           The pass block to use when generating the `znc.conf` file.
           This is the password used by the user logging into the ZNC web admin.
@@ -80,6 +94,13 @@ let
         '';
       };
 
+      extraZncConf = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra config to `znc.conf` file
+        '';
+      };
     };
   };
 
@@ -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 {
@@ -160,7 +183,7 @@ in
       user = mkOption {
         default = "znc";
         example = "john";
-        type = types.str;
+        type = types.string;
         description = ''
           The name of an existing user account to use to own the ZNC server process.
           If not specified, a default user will be created to own the process.
@@ -168,8 +191,8 @@ in
       };
 
       dataDir = mkOption {
-        default = "/home/${cfg.user}/.znc";
-        example = "/home/john/.znc";
+        default = "/var/lib/znc/";
+        example = "/home/john/.znc/";
         type = types.path;
         description = ''
           The data directory. Used for configuration files and modules.
@@ -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;
@@ -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,8 +298,12 @@ 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} ${toString cfg.extraFlags}";
     };
@@ -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/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 6d0416fbb155..78f3cf2b7e49 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;
@@ -194,7 +194,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}"
@@ -387,7 +387,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
@@ -531,6 +531,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 d4165c8c5bac..a883bb2b3433 100644
--- a/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/tomcat-connector.nix
@@ -31,7 +31,7 @@ in
 {
 
   options = {
-    extraWorkersProperties = pkgs.lib.mkOption {
+    extraWorkersProperties = lib.mkOption {
       default = "";
       description = "Additional configuration for the workers.properties file.";
     };
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index f0f59a664026..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;
 
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 991c68471a67..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 ./e18.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
index cb717eea909c..faafd21b07dd 100644
--- a/nixos/modules/services/x11/desktop-managers/e18.nix
+++ b/nixos/modules/services/x11/desktop-managers/e18.nix
@@ -1,6 +1,6 @@
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
 
-with pkgs.lib;
+with lib;
 
 let
 
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/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 1b51c11e351a..73fc6ce543cf 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -194,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"!'
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 58ff97671f3d..6a069c5d0540 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -119,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
 
diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh
index bfc3c9b5da39..fcefdfa88a36 100644
--- a/nixos/modules/system/boot/stage-2-init.sh
+++ b/nixos/modules/system/boot/stage-2-init.sh
@@ -180,4 +180,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/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/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/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix
index 17acd08f086c..58386ce5cf56 100644
--- a/nixos/modules/virtualisation/qemu-vm.nix
+++ b/nixos/modules/virtualisation/qemu-vm.nix
@@ -376,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 2e30f4c62f97..106b269d9e1f 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -2,112 +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/
-
-          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;
+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;
+  };
 }