summary refs log tree commit diff
path: root/nixos/modules/tasks
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-10 13:28:20 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-10 13:28:20 +0200
commit5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010 (patch)
treea6c0f605be6de3f372ae69905b331f9f75452da7 /nixos/modules/tasks
parent6070bc016bd2fd945b04347e25cfd3738622d2ac (diff)
downloadnixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.gz
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.bz2
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.lz
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.xz
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.zst
nixlib-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.zip
Move all of NixOS to nixos/ in preparation of the repository merge
Diffstat (limited to 'nixos/modules/tasks')
-rw-r--r--nixos/modules/tasks/cpu-freq.nix51
-rw-r--r--nixos/modules/tasks/filesystems.nix216
-rw-r--r--nixos/modules/tasks/filesystems/btrfs.nix47
-rw-r--r--nixos/modules/tasks/filesystems/ext.nix22
-rw-r--r--nixos/modules/tasks/filesystems/nfs.nix94
-rw-r--r--nixos/modules/tasks/filesystems/reiserfs.nix25
-rw-r--r--nixos/modules/tasks/filesystems/unionfs-fuse.nix24
-rw-r--r--nixos/modules/tasks/filesystems/vfat.nix25
-rw-r--r--nixos/modules/tasks/filesystems/xfs.nix29
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix94
-rw-r--r--nixos/modules/tasks/kbd.nix73
-rw-r--r--nixos/modules/tasks/lvm.nix15
-rw-r--r--nixos/modules/tasks/network-interfaces.nix447
-rw-r--r--nixos/modules/tasks/scsi-link-power-management.nix44
-rw-r--r--nixos/modules/tasks/swraid.nix11
-rw-r--r--nixos/modules/tasks/tty-backgrounds-combine.sh32
16 files changed, 1249 insertions, 0 deletions
diff --git a/nixos/modules/tasks/cpu-freq.nix b/nixos/modules/tasks/cpu-freq.nix
new file mode 100644
index 000000000000..3b21d8310871
--- /dev/null
+++ b/nixos/modules/tasks/cpu-freq.nix
@@ -0,0 +1,51 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+{
+  ###### interface
+
+  options = {
+
+    powerManagement.cpuFreqGovernor = mkOption {
+      default = "";
+      example = "ondemand";
+      type = types.uniq types.string;
+      description = ''
+        Configure the governor used to regulate the frequence of the
+        available CPUs. By default, the kernel configures the
+        on-demand governor.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf (config.powerManagement.cpuFreqGovernor != "") {
+
+    environment.systemPackages = [ pkgs.cpufrequtils ];
+
+    jobs.cpufreq =
+      { description = "CPU Frequency Governor Setup";
+
+        after = [ "systemd-modules-load.service" ];
+        wantedBy = [ "multi-user.target" ];
+
+        path = [ pkgs.cpufrequtils ];
+
+        preStart = ''
+          for i in $(seq 0 $(($(nproc) - 1))); do
+            for gov in $(cpufreq-info -c $i -g); do
+              if [ "$gov" = ${config.powerManagement.cpuFreqGovernor} ]; then
+                echo "<6>setting governor on CPU $i to ‘$gov’"
+                cpufreq-set -c $i -g $gov
+              fi
+            done
+          done
+        '';
+      };
+  };
+
+}
diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix
new file mode 100644
index 000000000000..4ca309f5a108
--- /dev/null
+++ b/nixos/modules/tasks/filesystems.nix
@@ -0,0 +1,216 @@
+{ config, pkgs, utils, ... }:
+
+with pkgs.lib;
+with utils;
+
+let
+
+  fileSystems = attrValues config.fileSystems;
+
+  prioOption = prio: optionalString (prio !=null) " pri=${toString prio}";
+
+  fileSystemOpts = { name, ... }: {
+
+    options = {
+
+      mountPoint = mkOption {
+        example = "/mnt/usb";
+        type = types.uniq types.string;
+        description = "Location of the mounted the file system.";
+      };
+
+      device = mkOption {
+        default = null;
+        example = "/dev/sda";
+        type = types.uniq (types.nullOr types.string);
+        description = "Location of the device.";
+      };
+
+      label = mkOption {
+        default = null;
+        example = "root-partition";
+        type = types.uniq (types.nullOr types.string);
+        description = "Label of the device (if any).";
+      };
+
+      fsType = mkOption {
+        default = "auto";
+        example = "ext3";
+        type = types.uniq types.string;
+        description = "Type of the file system.";
+      };
+
+      options = mkOption {
+        default = "defaults,relatime";
+        example = "data=journal";
+        type = types.string;
+        merge = pkgs.lib.concatStringsSep ",";
+        description = "Options used to mount the file system.";
+      };
+
+      autoFormat = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          If the device does not currently contain a filesystem (as
+          determined by <command>blkid</command>, then automatically
+          format it with the filesystem type specified in
+          <option>fsType</option>.  Use with caution.
+        '';
+      };
+
+      noCheck = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Disable running fsck on this filesystem.";
+      };
+
+    };
+
+    config = {
+      mountPoint = mkDefault name;
+    };
+
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    fileSystems = mkOption {
+      example = {
+        "/".device = "/dev/hda1";
+        "/data" = {
+          device = "/dev/hda2";
+          fsType = "ext3";
+          options = "data=journal";
+        };
+        "/bigdisk".label = "bigdisk";
+      };
+      type = types.loaOf types.optionSet;
+      options = [ fileSystemOpts ];
+      description = ''
+        The file systems to be mounted.  It must include an entry for
+        the root directory (<literal>mountPoint = \"/\"</literal>).  Each
+        entry in the list is an attribute set with the following fields:
+        <literal>mountPoint</literal>, <literal>device</literal>,
+        <literal>fsType</literal> (a file system type recognised by
+        <command>mount</command>; defaults to
+        <literal>\"auto\"</literal>), and <literal>options</literal>
+        (the mount options passed to <command>mount</command> using the
+        <option>-o</option> flag; defaults to <literal>\"defaults\"</literal>).
+
+        Instead of specifying <literal>device</literal>, you can also
+        specify a volume label (<literal>label</literal>) for file
+        systems that support it, such as ext2/ext3 (see <command>mke2fs
+        -L</command>).
+      '';
+    };
+
+    system.fsPackages = mkOption {
+      internal = true;
+      default = [ ];
+      description = "Packages supplying file system mounters and checkers.";
+    };
+
+    boot.supportedFilesystems = mkOption {
+      default = [ ];
+      example = [ "btrfs" ];
+      type = types.listOf types.string;
+      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.";
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    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 ]
+      ++ config.system.fsPackages;
+
+    environment.etc.fstab.text =
+      ''
+        # This is a generated file.  Do not edit!
+
+        # Filesystems.
+        ${flip concatMapStrings fileSystems (fs:
+            (if fs.device != null then fs.device else "/dev/disk/by-label/${fs.label}")
+            + " " + fs.mountPoint
+            + " " + fs.fsType
+            + " " + fs.options
+            + " 0"
+            + " " + (if fs.fsType == "none" || fs.device == "none" || fs.fsType == "btrfs" || fs.fsType == "tmpfs" || fs.noCheck then "0" else
+                     if fs.mountPoint == "/" then "1" else "2")
+            + "\n"
+        )}
+
+        # Swap devices.
+        ${flip concatMapStrings config.swapDevices (sw:
+            "${sw.device} none swap${prioOption sw.priority}\n"
+        )}
+      '';
+
+    # Provide a target that pulls in all filesystems.
+    systemd.targets.fs =
+      { description = "All File Systems";
+        wants = [ "local-fs.target" "remote-fs.target" ];
+      };
+
+    # Emit systemd services to format requested filesystems.
+    systemd.services =
+      let
+
+        formatDevice = fs:
+          let
+            mountPoint' = escapeSystemdPath fs.mountPoint;
+            device' = escapeSystemdPath fs.device;
+          in nameValuePair "mkfs-${device'}"
+          { description = "Initialisation of Filesystem ${fs.device}";
+            wantedBy = [ "${mountPoint'}.mount" ];
+            before = [ "${mountPoint'}.mount" "systemd-fsck@${device'}.service" ];
+            requires = [ "${device'}.device" ];
+            after = [ "${device'}.device" ];
+            path = [ pkgs.utillinux ] ++ config.system.fsPackages;
+            script =
+              ''
+                if ! [ -e "${fs.device}" ]; then exit 1; fi
+                # FIXME: this is scary.  The test could be more robust.
+                type=$(blkid -p -s TYPE -o value "${fs.device}" || true)
+                if [ -z "$type" ]; then
+                  echo "creating ${fs.fsType} filesystem on ${fs.device}..."
+                  mkfs.${fs.fsType} "${fs.device}"
+                fi
+              '';
+            unitConfig.RequiresMountsFor = [ "${dirOf fs.device}" ];
+            unitConfig.DefaultDependencies = false; # needed to prevent a cycle
+            serviceConfig.Type = "oneshot";
+          };
+
+      in listToAttrs (map formatDevice (filter (fs: fs.autoFormat) fileSystems));
+
+  };
+
+}
diff --git a/nixos/modules/tasks/filesystems/btrfs.nix b/nixos/modules/tasks/filesystems/btrfs.nix
new file mode 100644
index 000000000000..d95a32e2e3f7
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/btrfs.nix
@@ -0,0 +1,47 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  inInitrd = any (fs: fs == "btrfs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "btrfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.btrfsProgs ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "btrfs" "crc32c" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        mkdir -p $out/bin
+        cp -v ${pkgs.btrfsProgs}/bin/btrfs $out/bin
+        ln -sv btrfs $out/bin/btrfsck
+        ln -sv btrfsck $out/bin/fsck.btrfs
+        # !!! Increases uncompressed initrd by 240k
+        cp -pv ${pkgs.zlib}/lib/libz.so* $out/lib
+        cp -pv ${pkgs.lzo}/lib/liblzo2.so* $out/lib
+      '';
+
+    boot.initrd.extraUtilsCommandsTest = mkIf inInitrd
+      ''
+        $out/bin/btrfs --version
+      '';
+
+    boot.initrd.postDeviceCommands = mkIf inInitrd
+      ''
+        btrfs device scan
+      '';
+
+    # !!! This is broken.  There should be a udev rule to do this when
+    # new devices are discovered.
+    jobs.udev.postStart =
+      ''
+        ${pkgs.btrfsProgs}/bin/btrfs device scan
+      '';
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/ext.nix b/nixos/modules/tasks/filesystems/ext.nix
new file mode 100644
index 000000000000..24592e9d5882
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/ext.nix
@@ -0,0 +1,22 @@
+{ config, pkgs, ... }:
+
+{
+  config = {
+
+    system.fsPackages = [ pkgs.e2fsprogs ];
+
+    boot.initrd.availableKernelModules = [ "ext2" "ext3" "ext4" ];
+
+    boot.initrd.extraUtilsCommands =
+      ''
+        # Copy e2fsck and friends.
+        cp -v ${pkgs.e2fsprogs}/sbin/e2fsck $out/bin
+        cp -v ${pkgs.e2fsprogs}/sbin/tune2fs $out/bin
+        ln -sv e2fsck $out/bin/fsck.ext2
+        ln -sv e2fsck $out/bin/fsck.ext3
+        ln -sv e2fsck $out/bin/fsck.ext4
+        cp -pdv ${pkgs.e2fsprogs}/lib/lib*.so.* $out/lib
+      '';
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/nfs.nix b/nixos/modules/tasks/filesystems/nfs.nix
new file mode 100644
index 000000000000..2b720a93b893
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/nfs.nix
@@ -0,0 +1,94 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  inInitrd = any (fs: fs == "nfs") config.boot.initrd.supportedFilesystems;
+
+  nfsStateDir = "/var/lib/nfs";
+
+  rpcMountpoint = "${nfsStateDir}/rpc_pipefs";
+
+  idmapdConfFile = pkgs.writeText "idmapd.conf" ''
+    [General]
+    Pipefs-Directory = ${rpcMountpoint}
+    ${optionalString (config.networking.domain != "")
+      "Domain = ${config.networking.domain}"}
+
+    [Mapping]
+    Nobody-User = nobody
+    Nobody-Group = nogroup
+
+    [Translation]
+    Method = nsswitch
+  '';
+
+in
+
+{
+
+  ###### implementation
+
+  config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) {
+
+    services.rpcbind.enable = true;
+
+    system.fsPackages = [ pkgs.nfsUtils ];
+
+    boot.kernelModules = [ "sunrpc" ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "nfs" ];
+
+    systemd.services.statd =
+      { description = "NFSv3 Network Status Monitor";
+
+        path = [ pkgs.nfsUtils pkgs.sysvtools pkgs.utillinux ];
+
+        wantedBy = [ "network-online.target" "multi-user.target" ];
+        before = [ "network-online.target" ];
+        requires = [ "basic.target" "rpcbind.service" ];
+        after = [ "basic.target" "rpcbind.service" "network.target" ];
+
+        unitConfig.DefaultDependencies = false; # don't stop during shutdown
+
+        preStart =
+          ''
+            mkdir -p ${nfsStateDir}/sm
+            mkdir -p ${nfsStateDir}/sm.bak
+            sm-notify -d
+          '';
+
+        serviceConfig.Type = "forking";
+        serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.statd rpc.statd --no-notify";
+        serviceConfig.Restart = "always";
+      };
+
+    systemd.services.idmapd =
+      { description = "NFSv4 ID Mapping Daemon";
+
+        path = [ pkgs.sysvtools pkgs.utillinux ];
+
+        wantedBy = [ "network-online.target" "multi-user.target" ];
+        before = [ "network-online.target" ];
+        requires = [ "rpcbind.service" ];
+        after = [ "rpcbind.service" ];
+
+        preStart =
+          ''
+            mkdir -p ${rpcMountpoint}
+            mount -t rpc_pipefs rpc_pipefs ${rpcMountpoint}
+          '';
+
+        postStop =
+          ''
+            umount ${rpcMountpoint}
+          '';
+
+        serviceConfig.Type = "forking";
+        serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.idmapd rpc.idmapd -c ${idmapdConfFile}";
+        serviceConfig.Restart = "always";
+      };
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/reiserfs.nix b/nixos/modules/tasks/filesystems/reiserfs.nix
new file mode 100644
index 000000000000..f8c6a7000040
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/reiserfs.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  inInitrd = any (fs: fs == "reiserfs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "reiserfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.reiserfsprogs ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "reiserfs" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        cp -v ${pkgs.reiserfsprogs}/sbin/reiserfsck $out/bin
+        ln -sv reiserfsck $out/bin/fsck.reiserfs
+      '';
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/unionfs-fuse.nix b/nixos/modules/tasks/filesystems/unionfs-fuse.nix
new file mode 100644
index 000000000000..177c97f85c78
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/unionfs-fuse.nix
@@ -0,0 +1,24 @@
+{ config, pkgs, ... }:
+
+{
+  config = pkgs.lib.mkMerge [
+    (pkgs.lib.mkIf (pkgs.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.unionfs-fuse}/bin/unionfs $out/bin
+      '';
+  
+      boot.initrd.postDeviceCommands = ''
+          # Hacky!!! fuse hard-codes the path to mount
+          mkdir -p /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
+          ln -s $(which mount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
+          ln -s $(which umount) /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-${pkgs.utillinux.name}/bin
+        '';
+    })
+    (pkgs.lib.mkIf (pkgs.lib.any (fs: fs == "unionfs-fuse") config.boot.supportedFilesystems) {
+      system.fsPackages = [ pkgs.unionfs-fuse ];
+    })
+  ];
+}
diff --git a/nixos/modules/tasks/filesystems/vfat.nix b/nixos/modules/tasks/filesystems/vfat.nix
new file mode 100644
index 000000000000..5ca72f142b7d
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/vfat.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  inInitrd = any (fs: fs == "vfat") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "vfat") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.dosfstools ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "vfat" "nls_cp437" "nls_iso8859-1" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        cp -v ${pkgs.dosfstools}/sbin/dosfsck $out/bin
+        ln -sv dosfsck $out/bin/fsck.vfat
+      '';
+
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/xfs.nix b/nixos/modules/tasks/filesystems/xfs.nix
new file mode 100644
index 000000000000..5f9eb741c2ab
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/xfs.nix
@@ -0,0 +1,29 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  inInitrd = any (fs: fs == "xfs") config.boot.initrd.supportedFilesystems;
+
+in
+
+{
+  config = mkIf (any (fs: fs == "xfs") config.boot.supportedFilesystems) {
+
+    system.fsPackages = [ pkgs.xfsprogs ];
+
+    boot.initrd.kernelModules = mkIf inInitrd [ "xfs" "crc32c" ];
+
+    boot.initrd.extraUtilsCommands = mkIf inInitrd
+      ''
+        cp -v ${pkgs.xfsprogs}/sbin/fsck.xfs $out/bin
+      '';
+
+    # Trick just to set 'sh' after the extraUtils nuke-refs.
+    boot.initrd.extraUtilsCommandsTest = mkIf inInitrd
+      ''
+        sed -i -e 's,^#!.*,#!'$out/bin/sh, $out/bin/fsck.xfs
+      '';
+  };
+}
diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix
new file mode 100644
index 000000000000..c1955b146918
--- /dev/null
+++ b/nixos/modules/tasks/filesystems/zfs.nix
@@ -0,0 +1,94 @@
+{ config, pkgs, ... }:
+#
+# todo:
+#   - crontab for scrubs, etc
+#   - zfs tunables
+#   - /etc/zfs/zpool.cache handling
+
+
+with pkgs.lib;
+
+let
+
+  cfgSpl = config.boot.spl;
+  inInitrd = any (fs: fs == "zfs") config.boot.initrd.supportedFilesystems;
+  inSystem = any (fs: fs == "zfs") config.boot.supportedFilesystems;
+  kernel = config.boot.kernelPackages;
+
+in
+
+{
+
+  ###### interface
+  
+  options = { 
+    boot.spl.hostid = mkOption { 
+      default = "";
+      example = "0xdeadbeef";
+      description = ''
+        ZFS uses a system's hostid to determine if a storage pool (zpool) is
+        native to this system, and should thus be imported automatically.
+        Unfortunately, this hostid can change under linux from boot to boot (by
+        changing network adapters, for instance). Specify a unique 32 bit hostid in
+        hex here for zfs to prevent getting a random hostid between boots and having to
+        manually import pools.
+      '';
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf ( inInitrd || inSystem ) {
+
+    boot = { 
+      kernelModules = [ "spl" "zfs" ] ;
+      extraModulePackages = [ kernel.zfs kernel.spl ];
+      extraModprobeConfig = mkIf (cfgSpl.hostid != "") ''
+        options spl spl_hostid=${cfgSpl.hostid}
+      '';
+    };
+
+    boot.initrd = mkIf inInitrd { 
+      kernelModules = [ "spl" "zfs" ] ;
+      extraUtilsCommands =
+        ''
+          cp -v ${kernel.zfs}/sbin/zfs $out/bin
+          cp -v ${kernel.zfs}/sbin/zdb $out/bin
+          cp -v ${kernel.zfs}/sbin/zpool $out/bin
+        '';
+      postDeviceCommands =
+        ''
+          zpool import -f -a -d /dev
+          zfs mount -a
+        '';
+    };
+
+    systemd.services."zpool-import" = {
+      description = "Import zpools";
+      after = [ "systemd-udev-settle.service" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        restartIfChanged = false;
+        ExecStart = "${kernel.zfs}/sbin/zpool import -f -a -d /dev";
+      };
+    };
+
+    systemd.services."zfs-mount" = {
+      description = "Mount zfs volumes";
+      after = [ "zpool-import.service" ];
+      wantedBy = [ "local-fs.target" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        restartIfChanged = false;
+        ExecStart = "${kernel.zfs}/sbin/zfs mount -a";
+        ExecStop = "${kernel.zfs}/sbin/zfs umount -a";
+      };
+    };
+
+    system.fsPackages = [ kernel.zfs ];                  # XXX: needed? zfs doesn't have (need) a fsck
+    environment.systemPackages = [ kernel.zfs ];
+    services.udev.packages = [ kernel.zfs ];             # to hook zvol naming, etc. 
+  };
+}
diff --git a/nixos/modules/tasks/kbd.nix b/nixos/modules/tasks/kbd.nix
new file mode 100644
index 000000000000..9f294a5f93e3
--- /dev/null
+++ b/nixos/modules/tasks/kbd.nix
@@ -0,0 +1,73 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  vconsoleConf = pkgs.writeText "vconsole.conf"
+    ''
+      KEYMAP=${config.i18n.consoleKeyMap}
+      FONT=${config.i18n.consoleFont}
+    '';
+
+in
+
+{
+  ###### interface
+
+  options = {
+
+    # most options are defined in i18n.nix
+
+    # FIXME: still needed?
+    boot.extraTTYs = mkOption {
+      default = [];
+      example = ["tty8" "tty9"];
+      description = ''
+        Tty (virtual console) devices, in addition to the consoles on
+        which mingetty and syslogd run, that must be initialised.
+        Only useful if you have some program that you want to run on
+        some fixed console.  For example, the NixOS installation CD
+        opens the manual in a web browser on console 7, so it sets
+        <option>boot.extraTTYs</option> to <literal>["tty7"]</literal>.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    environment.systemPackages = [ pkgs.kbd ];
+
+    # Let systemd-vconsole-setup.service do the work of setting up the
+    # virtual consoles.  FIXME: trigger a restart of
+    # systemd-vconsole-setup.service if /etc/vconsole.conf changes.
+    environment.etc."vconsole.conf".source = vconsoleConf;
+
+    # This is identical to the systemd-vconsole-setup.service unit
+    # shipped with systemd, except that it uses /dev/tty1 instead of
+    # /dev/tty0 to prevent putting the X server in non-raw mode, and
+    # it has a restart trigger.
+    systemd.services."systemd-vconsole-setup" =
+      { description = "Setup Virtual Console";
+        wantedBy = [ "sysinit.target" "multi-user.target" ];
+        before = [ "sysinit.target" "shutdown.target" ];
+        unitConfig =
+          { DefaultDependencies = "no";
+            Conflicts = "shutdown.target";
+            ConditionPathExists = "/dev/tty1";
+          };
+        serviceConfig =
+          { Type = "oneshot";
+            RemainAfterExit = true;
+            ExecStart = "${config.systemd.package}/lib/systemd/systemd-vconsole-setup /dev/tty1";
+          };
+        restartTriggers = [ vconsoleConf ];
+      };
+
+  };
+
+}
diff --git a/nixos/modules/tasks/lvm.nix b/nixos/modules/tasks/lvm.nix
new file mode 100644
index 000000000000..0e0272388c76
--- /dev/null
+++ b/nixos/modules/tasks/lvm.nix
@@ -0,0 +1,15 @@
+{ config, pkgs, ... }:
+
+{
+
+  ###### implementation
+
+  config = {
+
+    environment.systemPackages = [ pkgs.lvm2 ];
+
+    services.udev.packages = [ pkgs.lvm2 ];
+
+  };
+
+}
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
new file mode 100644
index 000000000000..0177d6396dfa
--- /dev/null
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -0,0 +1,447 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.networking;
+  interfaces = attrValues cfg.interfaces;
+  hasVirtuals = any (i: i.virtual) interfaces;
+
+  interfaceOpts = { name, ... }: {
+
+    options = {
+
+      name = mkOption {
+        example = "eth0";
+        type = types.string;
+        description = "Name of the interface.";
+      };
+
+      ipAddress = mkOption {
+        default = null;
+        example = "10.0.0.1";
+        type = types.nullOr types.string;
+        description = ''
+          IP address of the interface.  Leave empty to configure the
+          interface using DHCP.
+        '';
+      };
+
+      prefixLength = mkOption {
+        default = null;
+        example = 24;
+        type = types.nullOr types.int;
+        description = ''
+          Subnet mask of the interface, specified as the number of
+          bits in the prefix (<literal>24</literal>).
+        '';
+      };
+
+      subnetMask = mkOption {
+        default = "";
+        example = "255.255.255.0";
+        type = types.string;
+        description = ''
+          Subnet mask of the interface, specified as a bitmask.
+          This is deprecated; use <option>prefixLength</option>
+          instead.
+        '';
+      };
+
+      macAddress = mkOption {
+        default = null;
+        example = "00:11:22:33:44:55";
+        type = types.nullOr types.string;
+        description = ''
+          MAC address of the interface. Leave empty to use the default.
+        '';
+      };
+
+      virtual = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Whether this interface is virtual and should be created by tunctl.
+          This is mainly useful for creating bridges between a host a virtual
+          network such as VPN or a virtual machine.
+
+          Defaults to tap device, unless interface contains "tun" in its name.
+        '';
+      };
+
+      virtualOwner = mkOption {
+        default = "root";
+        type = types.uniq types.string;
+        description = ''
+          In case of a virtual device, the user who owns it.
+        '';
+      };
+
+      proxyARP = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Turn on proxy_arp for this device (and proxy_ndp for ipv6).
+          This is mainly useful for creating pseudo-bridges between a real
+          interface and a virtual network such as VPN or a virtual machine for
+          interfaces that don't support real bridging (most wlan interfaces).
+          As ARP proxying acts slightly above the link-layer, below-ip traffic
+          isn't bridged, so things like DHCP won't work. The advantage above
+          using NAT lies in the fact that no IP addresses are shared, so all
+          hosts are reachable/routeable.
+
+          WARNING: turns on ip-routing, so if you have multiple interfaces, you
+          should think of the consequence and setup firewall rules to limit this.
+        '';
+      };
+
+    };
+
+    config = {
+      name = mkDefault name;
+    };
+
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    networking.hostName = mkOption {
+      default = "nixos";
+      description = ''
+        The name of the machine.  Leave it empty if you want to obtain
+        it from a DHCP server (if using DHCP).
+      '';
+    };
+
+    networking.enableIPv6 = mkOption {
+      default = true;
+      description = ''
+        Whether to enable support for IPv6.
+      '';
+    };
+
+    networking.defaultGateway = mkOption {
+      default = "";
+      example = "131.211.84.1";
+      description = ''
+        The default gateway.  It can be left empty if it is auto-detected through DHCP.
+      '';
+    };
+
+    networking.defaultGatewayWindowSize = mkOption {
+      default = null;
+      example = 524288;
+      type = types.nullOr types.int;
+      description = ''
+        The window size of the default gateway. It limits maximal data bursts that TCP peers
+        are allowed to send to us.
+      '';
+    };
+
+    networking.nameservers = mkOption {
+      default = [];
+      example = ["130.161.158.4" "130.161.33.17"];
+      description = ''
+        The list of nameservers.  It can be left empty if it is auto-detected through DHCP.
+      '';
+    };
+
+    networking.domain = mkOption {
+      default = "";
+      example = "home";
+      description = ''
+        The domain.  It can be left empty if it is auto-detected through DHCP.
+      '';
+    };
+
+    networking.localCommands = mkOption {
+      default = "";
+      example = "text=anything; echo You can put $text here.";
+      description = ''
+        Shell commands to be executed at the end of the
+        <literal>network-setup</literal> systemd service.  Note that if
+        you are using DHCP to obtain the network configuration,
+        interfaces may not be fully configured yet.
+      '';
+    };
+
+    networking.interfaces = mkOption {
+      default = {};
+      example =
+        { eth0 = {
+            ipAddress = "131.211.84.78";
+            subnetMask = "255.255.255.128";
+          };
+        };
+      description = ''
+        The configuration for each network interface.  If
+        <option>networking.useDHCP</option> is true, then every
+        interface not listed here will be configured using DHCP.
+      '';
+      type = types.loaOf types.optionSet;
+      options = [ interfaceOpts ];
+    };
+
+    networking.bridges = mkOption {
+      default = { };
+      example =
+        { br0.interfaces = [ "eth0" "eth1" ];
+          br1.interfaces = [ "eth2" "wlan0" ];
+        };
+      description =
+        ''
+          This option allows you to define Ethernet bridge devices
+          that connect physical networks together.  The value of this
+          option is an attribute set.  Each attribute specifies a
+          bridge, with the attribute name specifying the name of the
+          bridge's network interface.
+        '';
+
+      type = types.attrsOf types.optionSet;
+
+      options = {
+
+        interfaces = mkOption {
+          example = [ "eth0" "eth1" ];
+          type = types.listOf types.string;
+          description =
+            "The physical network interfaces connected by the bridge.";
+        };
+
+      };
+
+    };
+
+    networking.useDHCP = mkOption {
+      default = true;
+      merge = mergeEnableOption;
+      description = ''
+        Whether to use DHCP to obtain an IP address and other
+        configuration for all network interfaces that are not manually
+        configured.
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    boot.kernelModules = optional cfg.enableIPv6 "ipv6" ++ optional hasVirtuals "tun";
+
+    environment.systemPackages =
+      [ pkgs.host
+        pkgs.iproute
+        pkgs.iputils
+        pkgs.nettools
+        pkgs.wirelesstools
+        pkgs.iw
+        pkgs.rfkill
+        pkgs.openresolv
+      ]
+      ++ optional (cfg.bridges != {}) pkgs.bridge_utils
+      ++ optional hasVirtuals pkgs.tunctl
+      ++ optional cfg.enableIPv6 pkgs.ndisc6;
+
+    security.setuidPrograms = [ "ping" "ping6" ];
+
+    systemd.targets."network-interfaces" =
+      { description = "All Network Interfaces";
+        wantedBy = [ "network.target" ];
+        unitConfig.X-StopOnReconfiguration = true;
+      };
+
+    systemd.services =
+      let
+
+        networkSetup =
+          { description = "Networking Setup";
+
+            after = [ "network-interfaces.target" ];
+            before = [ "network.target" ];
+            wantedBy = [ "network.target" ];
+
+            path = [ pkgs.iproute ];
+
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+
+            script =
+              ''
+                # Set the static DNS configuration, if given.
+                ${pkgs.openresolv}/sbin/resolvconf -m 1 -a static <<EOF
+                ${optionalString (cfg.nameservers != [] && cfg.domain != "") ''
+                  domain ${cfg.domain}
+                ''}
+                ${flip concatMapStrings cfg.nameservers (ns: ''
+                  nameserver ${ns}
+                '')}
+                EOF
+
+                # Disable or enable IPv6.
+                if [ -e /proc/sys/net/ipv6/conf/all/disable_ipv6 ]; then
+                  echo ${if cfg.enableIPv6 then "0" else "1"} > /proc/sys/net/ipv6/conf/all/disable_ipv6
+                fi
+
+                # Set the default gateway.
+                ${optionalString (cfg.defaultGateway != "") ''
+                  # FIXME: get rid of "|| true" (necessary to make it idempotent).
+                  ip route add default via "${cfg.defaultGateway}" ${
+                    optionalString (cfg.defaultGatewayWindowSize != null)
+                      "window ${cfg.defaultGatewayWindowSize}"} || true
+                ''}
+
+                # Turn on forwarding if any interface has enabled proxy_arp.
+                ${optionalString (any (i: i.proxyARP) interfaces) ''
+                  echo 1 > /proc/sys/net/ipv4/ip_forward
+                ''}
+
+                # Run any user-specified commands.
+                ${cfg.localCommands}
+              '';
+          };
+
+        # For each interface <foo>, create a job ‘<foo>-cfg.service"
+        # that performs static configuration.  It has a "wants"
+        # dependency on ‘<foo>.service’, which is supposed to create
+        # the interface and need not exist (i.e. for hardware
+        # interfaces).  It has a binds-to dependency on the actual
+        # network device, so it only gets started after the interface
+        # has appeared, and it's stopped when the interface
+        # disappears.
+        configureInterface = i: nameValuePair "${i.name}-cfg"
+          (let mask =
+                if i.prefixLength != null then toString i.prefixLength else
+                if i.subnetMask != "" then i.subnetMask else "32";
+          in
+          { description = "Configuration of ${i.name}";
+            wantedBy = [ "network-interfaces.target" ];
+            bindsTo = [ "sys-subsystem-net-devices-${i.name}.device" ];
+            after = [ "sys-subsystem-net-devices-${i.name}.device" ];
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.iproute pkgs.gawk ];
+            script =
+              ''
+                echo "bringing up interface..."
+                ip link set "${i.name}" up
+              ''
+              + optionalString (i.macAddress != null)
+                ''
+                  echo "setting MAC address to ${i.macAddress}..."
+                  ip link set "${i.name}" address "${i.macAddress}"
+                ''
+              + optionalString (i.ipAddress != null)
+                ''
+                  cur=$(ip -4 -o a show dev "${i.name}" | awk '{print $4}')
+                  # Only do a flush/add if it's necessary.  This is
+                  # useful when the Nix store is accessed via this
+                  # interface (e.g. in a QEMU VM test).
+                  if [ "$cur" != "${i.ipAddress}/${mask}" ]; then
+                    echo "configuring interface..."
+                    ip -4 addr flush dev "${i.name}"
+                    ip -4 addr add "${i.ipAddress}/${mask}" dev "${i.name}"
+                    # Ensure that the default gateway remains set.
+                    # (Flushing this interface may have removed it.)
+                    ${config.systemd.package}/bin/systemctl try-restart --no-block network-setup.service
+                  else
+                    echo "skipping configuring interface"
+                  fi
+                  ${config.systemd.package}/bin/systemctl start ip-up.target
+                ''
+              + optionalString i.proxyARP
+                ''
+                  echo 1 > /proc/sys/net/ipv4/conf/${i.name}/proxy_arp
+                ''
+              + optionalString (i.proxyARP && cfg.enableIPv6)
+                ''
+                  echo 1 > /proc/sys/net/ipv6/conf/${i.name}/proxy_ndp
+                '';
+          });
+
+        createTunDevice = i: nameValuePair "${i.name}"
+          { description = "Virtual Network Interface ${i.name}";
+            requires = [ "dev-net-tun.device" ];
+            after = [ "dev-net-tun.device" ];
+            wantedBy = [ "network.target" ];
+            requiredBy = [ "sys-subsystem-net-devices-${i.name}.device" ];
+            serviceConfig =
+              { Type = "oneshot";
+                RemainAfterExit = true;
+                ExecStart = "${pkgs.tunctl}/bin/tunctl -t '${i.name}' -u '${i.virtualOwner}'";
+                ExecStop = "${pkgs.tunctl}/bin/tunctl -d '${i.name}'";
+              };
+          };
+
+        createBridgeDevice = n: v:
+          let
+            deps = map (i: "sys-subsystem-net-devices-${i}.device") v.interfaces;
+          in
+          { description = "Bridge Interface ${n}";
+            wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ];
+            bindsTo = deps;
+            after = deps;
+            serviceConfig.Type = "oneshot";
+            serviceConfig.RemainAfterExit = true;
+            path = [ pkgs.bridge_utils pkgs.iproute ];
+            script =
+              ''
+                brctl addbr "${n}"
+
+                # Set bridge's hello time to 0 to avoid startup delays.
+                brctl setfd "${n}" 0
+
+                ${flip concatMapStrings v.interfaces (i: ''
+                  brctl addif "${n}" "${i}"
+                  ip link set "${i}" up
+                  ip addr flush dev "${i}"
+
+                  echo "bringing up network device ${n}..."
+                  ip link set "${n}" up
+                '')}
+
+                # !!! Should delete (brctl delif) any interfaces that
+                # no longer belong to the bridge.
+              '';
+            postStop =
+              ''
+                ip link set "${n}" down
+                brctl delbr "${n}"
+              '';
+          };
+
+      in listToAttrs (
+           map configureInterface interfaces ++
+           map createTunDevice (filter (i: i.virtual) interfaces))
+         // mapAttrs createBridgeDevice cfg.bridges
+         // { "network-setup" = networkSetup; };
+
+    # Set the host and domain names in the activation script.  Don't
+    # clear it if it's not configured in the NixOS configuration,
+    # since it may have been set by dhclient in the meantime.
+    system.activationScripts.hostname =
+      optionalString (config.networking.hostName != "") ''
+        hostname "${config.networking.hostName}"
+      '';
+    system.activationScripts.domain =
+      optionalString (config.networking.domain != "") ''
+        domainname "${config.networking.domain}"
+      '';
+
+    services.udev.extraRules =
+      ''
+        KERNEL=="tun", TAG+="systemd"
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/tasks/scsi-link-power-management.nix b/nixos/modules/tasks/scsi-link-power-management.nix
new file mode 100644
index 000000000000..4ab67aee3956
--- /dev/null
+++ b/nixos/modules/tasks/scsi-link-power-management.nix
@@ -0,0 +1,44 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+{
+  ###### interface
+
+  options = {
+
+    powerManagement.scsiLinkPolicy = mkOption {
+      default = "";
+      example = "min_power";
+      type = types.uniq types.string;
+      description = ''
+        Configure the SCSI link power management policy. By default,
+        the kernel configures "max_performance".
+      '';
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf (config.powerManagement.scsiLinkPolicy != "") {
+
+    jobs."scsi-link-pm" =
+      { description = "SCSI Link Power Management Policy";
+
+        startOn = "stopped udevtrigger";
+
+        task = true;
+
+        script = ''
+          shopt -s nullglob
+          for x in /sys/class/scsi_host/host*/link_power_management_policy; do
+            echo ${config.powerManagement.scsiLinkPolicy} > $x
+          done
+        '';
+      };
+
+  };
+
+}
diff --git a/nixos/modules/tasks/swraid.nix b/nixos/modules/tasks/swraid.nix
new file mode 100644
index 000000000000..3b4aa9875f26
--- /dev/null
+++ b/nixos/modules/tasks/swraid.nix
@@ -0,0 +1,11 @@
+{ config, pkgs, ... }:
+
+{
+
+  environment.systemPackages = [ pkgs.mdadm ];
+
+  services.udev.packages = [ pkgs.mdadm ];
+
+  boot.initrd.availableKernelModules = [ "md_mod" "raid0" "raid1" "raid456" ];
+
+}
diff --git a/nixos/modules/tasks/tty-backgrounds-combine.sh b/nixos/modules/tasks/tty-backgrounds-combine.sh
new file mode 100644
index 000000000000..1e0d8758a6ee
--- /dev/null
+++ b/nixos/modules/tasks/tty-backgrounds-combine.sh
@@ -0,0 +1,32 @@
+source $stdenv/setup
+
+ttys=($ttys)
+themes=($themes)
+
+ensureDir $out
+
+defaultName=$(cd $default && ls | grep -v default)
+echo $defaultName
+ln -s $default/$defaultName $out/$defaultName
+ln -s $defaultName $out/default
+
+for ((n = 0; n < ${#ttys[*]}; n++)); do
+    tty=${ttys[$n]}
+    theme=${themes[$n]}
+
+    echo "TTY $tty -> $theme"
+
+    if [ "$theme" != default ]; then
+        themeName=$(cd $theme && ls | grep -v default)
+        ln -sfn $theme/$themeName $out/$themeName
+    else
+        themeName=default
+    fi
+
+    if test -e $out/$tty; then
+        echo "Multiple themes defined for the same TTY!"
+        exit 1
+    fi
+
+    ln -sfn $themeName $out/$tty
+done