diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services/hardware/udev.nix')
-rw-r--r-- | nixpkgs/nixos/modules/services/hardware/udev.nix | 190 |
1 files changed, 148 insertions, 42 deletions
diff --git a/nixpkgs/nixos/modules/services/hardware/udev.nix b/nixpkgs/nixos/modules/services/hardware/udev.nix index 61448af2d33b..1723cb508485 100644 --- a/nixpkgs/nixos/modules/services/hardware/udev.nix +++ b/nixpkgs/nixos/modules/services/hardware/udev.nix @@ -8,6 +8,24 @@ let cfg = config.services.udev; + initrdUdevRules = pkgs.runCommand "initrd-udev-rules" {} '' + mkdir -p $out/etc/udev/rules.d + for f in 60-cdrom_id 60-persistent-storage 75-net-description 80-drivers 80-net-setup-link; do + ln -s ${config.boot.initrd.systemd.package}/lib/udev/rules.d/$f.rules $out/etc/udev/rules.d + done + ''; + + + # networkd link files are used early by udev to set up interfaces early. + # This must be done in stage 1 to avoid race conditions between udev and + # network daemons. + # TODO move this into the initrd-network module when it exists + initrdLinkUnits = pkgs.runCommand "initrd-link-units" {} '' + mkdir -p $out + ln -s ${udev}/lib/systemd/network/*.link $out/ + ${lib.concatMapStringsSep "\n" (file: "ln -s ${file} $out/") (lib.mapAttrsToList (n: v: "${v.unit}/${n}") (lib.filterAttrs (n: _: hasSuffix ".link" n) config.systemd.network.units))} + ''; + extraUdevRules = pkgs.writeTextFile { name = "extra-udev-rules"; text = cfg.extraRules; @@ -23,17 +41,16 @@ let nixosRules = '' # Miscellaneous devices. KERNEL=="kvm", MODE="0666" - KERNEL=="kqemu", MODE="0666" # Needed for gpm. SUBSYSTEM=="input", KERNEL=="mice", TAG+="systemd" ''; # Perform substitutions in all udev rules files. - udevRules = pkgs.runCommand "udev-rules" + udevRulesFor = { name, udevPackages, udevPath, udev, systemd, binPackages, initrdBin ? null }: pkgs.runCommand name { preferLocalBuild = true; allowSubstitutes = false; - packages = unique (map toString cfg.packages); + packages = unique (map toString udevPackages); } '' mkdir -p $out @@ -61,6 +78,9 @@ let --replace \"/bin/mount \"${pkgs.util-linux}/bin/mount \ --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \ --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename + ${optionalString (initrdBin != null) '' + substituteInPlace $i --replace '/run/current-system/systemd' "${removeSuffix "/bin" initrdBin}" + ''} done echo -n "Checking that all programs called by relative paths in udev rules exist in ${udev}/lib/udev... " @@ -85,8 +105,9 @@ let for i in $import_progs $run_progs; do # if the path refers to /run/current-system/systemd, replace with config.systemd.package if [[ $i == /run/current-system/systemd* ]]; then - i="${config.systemd.package}/''${i#/run/current-system/systemd/}" + i="${systemd}/''${i#/run/current-system/systemd/}" fi + if [[ ! -x $i ]]; then echo "FAIL" echo "$i is called in udev rules but is not executable or does not exist" @@ -103,7 +124,7 @@ let echo "Consider fixing the following udev rules:" echo "$filesToFixup" | while read localFile; do remoteFile="origin unknown" - for i in ${toString cfg.packages}; do + for i in ${toString binPackages}; do for j in "$i"/*/udev/rules.d/*; do [ -e "$out/$(basename "$j")" ] || continue [ "$(basename "$j")" = "$(basename "$localFile")" ] || continue @@ -126,7 +147,7 @@ let ${optionalString (!config.boot.hardwareScan) '' ln -s /dev/null $out/80-drivers.rules ''} - ''; # */ + ''; hwdbBin = pkgs.runCommand "hwdb.bin" { preferLocalBuild = true; @@ -150,6 +171,11 @@ let mv etc/udev/hwdb.bin $out ''; + compressFirmware = if config.boot.kernelPackages.kernelAtLeast "5.3" then + pkgs.compressFirmwareXz + else + id; + # Udev has a 512-character limit for ENV{PATH}, so create a symlink # tree to work around this. udevPath = pkgs.buildEnv { @@ -170,7 +196,7 @@ in boot.hardwareScan = mkOption { type = types.bool; default = true; - description = '' + description = lib.mdDoc '' Whether to try to load kernel modules for all detected hardware. Usually this does a good job of providing you with the modules you need, but sometimes it can crash the system or cause other @@ -183,11 +209,11 @@ in packages = mkOption { type = types.listOf types.path; default = []; - description = '' - List of packages containing <command>udev</command> rules. + description = lib.mdDoc '' + List of packages containing {command}`udev` rules. All files found in - <filename><replaceable>pkg</replaceable>/etc/udev/rules.d</filename> and - <filename><replaceable>pkg</replaceable>/lib/udev/rules.d</filename> + {file}`«pkg»/etc/udev/rules.d` and + {file}`«pkg»/lib/udev/rules.d` will be included. ''; apply = map getBin; @@ -202,29 +228,15 @@ in ''; }; - initrdRules = mkOption { - default = ""; - example = '' - SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1D:60:B9:6D:4F", KERNEL=="eth*", NAME="my_fast_network_card" - ''; - type = types.lines; - description = '' - <command>udev</command> rules to include in the initrd - <emphasis>only</emphasis>. They'll be written into file - <filename>99-local.rules</filename>. Thus they are read and applied - after the essential initrd rules. - ''; - }; - extraRules = mkOption { default = ""; example = '' ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="0825", ENV{PULSE_IGNORE}="1" ''; type = types.lines; - description = '' - Additional <command>udev</command> rules. They'll be written - into file <filename>99-local.rules</filename>. Thus they are + description = lib.mdDoc '' + Additional {command}`udev` rules. They'll be written + into file {file}`99-local.rules`. Thus they are read and applied after all other rules. ''; }; @@ -237,9 +249,9 @@ in KEYBOARD_KEY_700e2=leftctrl ''; type = types.lines; - description = '' - Additional <command>hwdb</command> files. They'll be written - into file <filename>99-local.hwdb</filename>. Thus they are + description = lib.mdDoc '' + Additional {command}`hwdb` files. They'll be written + into file {file}`99-local.hwdb`. Thus they are read after all other files. ''; }; @@ -249,7 +261,7 @@ in hardware.firmware = mkOption { type = types.listOf types.package; default = []; - description = '' + description = lib.mdDoc '' List of packages containing firmware files. Such files will be loaded automatically if the kernel asks for them (i.e., when it has detected specific hardware that requires @@ -260,7 +272,7 @@ in ''; apply = list: pkgs.buildEnv { name = "firmware"; - paths = list; + paths = map compressFirmware list; pathsToLink = [ "/lib/firmware" ]; ignoreCollisions = true; }; @@ -269,20 +281,65 @@ in networking.usePredictableInterfaceNames = mkOption { default = true; type = types.bool; - description = '' - Whether to assign <link - xlink:href='http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames'>predictable - names to network interfaces</link>. If enabled, interfaces + description = lib.mdDoc '' + Whether to assign [predictable names to network interfaces](http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames). + If enabled, interfaces are assigned names that contain topology information - (e.g. <literal>wlp3s0</literal>) and thus should be stable + (e.g. `wlp3s0`) and thus should be stable across reboots. If disabled, names depend on the order in which interfaces are discovered by the kernel, which may change randomly across reboots; for instance, you may find - <literal>eth0</literal> and <literal>eth1</literal> flipping + `eth0` and `eth1` flipping unpredictably. ''; }; + boot.initrd.services.udev = { + + packages = mkOption { + type = types.listOf types.path; + default = []; + visible = false; + description = '' + <emphasis>This will only be used when systemd is used in stage 1.</emphasis> + + List of packages containing <command>udev</command> rules that will be copied to stage 1. + All files found in + <filename>«pkg»/etc/udev/rules.d</filename> and + <filename>«pkg»/lib/udev/rules.d</filename> + will be included. + ''; + }; + + binPackages = mkOption { + type = types.listOf types.path; + default = []; + visible = false; + description = '' + <emphasis>This will only be used when systemd is used in stage 1.</emphasis> + + Packages to search for binaries that are referenced by the udev rules in stage 1. + This list always contains /bin of the initrd. + ''; + apply = map getBin; + }; + + rules = mkOption { + default = ""; + example = '' + SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1D:60:B9:6D:4F", KERNEL=="eth*", NAME="my_fast_network_card" + ''; + type = types.lines; + description = lib.mdDoc '' + {command}`udev` rules to include in the initrd + *only*. They'll be written into file + {file}`99-local.rules`. Thus they are read and applied + after the essential initrd rules. + ''; + }; + + }; + }; @@ -298,16 +355,61 @@ in boot.kernelParams = mkIf (!config.networking.usePredictableInterfaceNames) [ "net.ifnames=0" ]; - boot.initrd.extraUdevRulesCommands = optionalString (cfg.initrdRules != "") + boot.initrd.extraUdevRulesCommands = optionalString (!config.boot.initrd.systemd.enable && config.boot.initrd.services.udev.rules != "") '' cat <<'EOF' > $out/99-local.rules - ${cfg.initrdRules} + ${config.boot.initrd.services.udev.rules} EOF ''; + boot.initrd.systemd.additionalUpstreamUnits = [ + # TODO: "initrd-udevadm-cleanup-db.service" is commented out because of https://github.com/systemd/systemd/issues/12953 + "systemd-udevd-control.socket" + "systemd-udevd-kernel.socket" + "systemd-udevd.service" + "systemd-udev-settle.service" + "systemd-udev-trigger.service" + ]; + boot.initrd.systemd.storePaths = [ + "${config.boot.initrd.systemd.package}/lib/systemd/systemd-udevd" + "${config.boot.initrd.systemd.package}/lib/udev/ata_id" + "${config.boot.initrd.systemd.package}/lib/udev/cdrom_id" + "${config.boot.initrd.systemd.package}/lib/udev/scsi_id" + "${config.boot.initrd.systemd.package}/lib/udev/rules.d" + ] ++ map (x: "${x}/bin") config.boot.initrd.services.udev.binPackages; + + # Generate the udev rules for the initrd + boot.initrd.systemd.contents = { + "/etc/udev/rules.d".source = udevRulesFor { + name = "initrd-udev-rules"; + initrdBin = config.boot.initrd.systemd.contents."/bin".source; + udevPackages = config.boot.initrd.services.udev.packages; + udevPath = config.boot.initrd.systemd.contents."/bin".source; + udev = config.boot.initrd.systemd.package; + systemd = config.boot.initrd.systemd.package; + binPackages = config.boot.initrd.services.udev.binPackages ++ [ config.boot.initrd.systemd.contents."/bin".source ]; + }; + "/etc/systemd/network".source = initrdLinkUnits; + }; + # Insert initrd rules + boot.initrd.services.udev.packages = [ + initrdUdevRules + (mkIf (config.boot.initrd.services.udev.rules != "") (pkgs.writeTextFile { + name = "initrd-udev-rules"; + destination = "/etc/udev/rules.d/99-local.rules"; + text = config.boot.initrd.services.udev.rules; + })) + ]; + environment.etc = { - "udev/rules.d".source = udevRules; + "udev/rules.d".source = udevRulesFor { + name = "udev-rules"; + udevPackages = cfg.packages; + systemd = config.systemd.package; + binPackages = cfg.packages; + inherit udevPath udev; + }; "udev/hwdb.bin".source = hwdbBin; }; @@ -338,4 +440,8 @@ in }; }; + + imports = [ + (mkRenamedOptionModule [ "services" "udev" "initrdRules" ] [ "boot" "initrd" "services" "udev" "rules" ]) + ]; } |