diff options
Diffstat (limited to 'nixos/modules/tasks')
-rw-r--r-- | nixos/modules/tasks/cpu-freq.nix | 51 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems.nix | 216 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/btrfs.nix | 47 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/ext.nix | 22 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/nfs.nix | 94 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/reiserfs.nix | 25 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/unionfs-fuse.nix | 24 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/vfat.nix | 25 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/xfs.nix | 29 | ||||
-rw-r--r-- | nixos/modules/tasks/filesystems/zfs.nix | 94 | ||||
-rw-r--r-- | nixos/modules/tasks/kbd.nix | 73 | ||||
-rw-r--r-- | nixos/modules/tasks/lvm.nix | 15 | ||||
-rw-r--r-- | nixos/modules/tasks/network-interfaces.nix | 447 | ||||
-rw-r--r-- | nixos/modules/tasks/scsi-link-power-management.nix | 44 | ||||
-rw-r--r-- | nixos/modules/tasks/swraid.nix | 11 | ||||
-rw-r--r-- | nixos/modules/tasks/tty-backgrounds-combine.sh | 32 |
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 |