From 76485883fab8af051602a610f551b90fd2d3e559 Mon Sep 17 00:00:00 2001 From: Aaron Andersen Date: Sun, 24 May 2026 10:59:42 -0400 Subject: [PATCH] modules/keventd: init --- modules/default.nix | 2 + modules/finit/initrd.nix | 21 +++- modules/programs/brightnessctl/default.nix | 2 +- modules/programs/hyprland/default.nix | 8 +- modules/programs/labwc/default.nix | 4 +- modules/programs/lxqt/default.nix | 2 +- modules/programs/mangowc/default.nix | 4 +- modules/programs/niri/default.nix | 22 ++-- modules/programs/regreet/default.nix | 8 +- modules/programs/sway/default.nix | 6 +- modules/programs/tuigreet/default.nix | 4 +- modules/services/keventd/default.nix | 134 +++++++++++++++++++++ modules/services/rsyslog/default.nix | 3 +- modules/services/sysklogd/default.nix | 3 +- 14 files changed, 189 insertions(+), 34 deletions(-) create mode 100644 modules/services/keventd/default.nix diff --git a/modules/default.nix b/modules/default.nix index 80bfd68a..3ad8a942 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -21,6 +21,7 @@ let # required modules - included by default "dbus" "elogind" + "keventd" "mdevd" "seatd" "udev" @@ -52,6 +53,7 @@ in ./security ./services/dbus ./services/elogind + ./services/keventd ./services/mdevd ./services/seatd ./services/udev diff --git a/modules/finit/initrd.nix b/modules/finit/initrd.nix index 0fe29d75..92cd248b 100644 --- a/modules/finit/initrd.nix +++ b/modules/finit/initrd.nix @@ -248,6 +248,7 @@ in task [S] name:fs-import tty:@console \ ${lib.optionalString config.services.mdevd.enable ""} \ ${lib.optionalString config.services.udev.enable ""} \ + ${lib.optionalString config.services.keventd.enable ""} \ finix-fs-import task [S] name:mount-all finix-mount-all @@ -260,6 +261,10 @@ in service [S] notify:s6 /bin/udevd --ready-notify=%n ''} + ${lib.optionalString config.services.keventd.enable '' + service [S] name:keventd notify:pid keventd -n -c + ''} + run [1] name:switch-root finix-switch-root tty [1] @console rescue ''; @@ -281,9 +286,13 @@ in } { target = "/etc/group"; - source = pkgs.writeText "group" '' - root:x:0: - ''; + source = pkgs.writeText "group" ( + lib.concatStringsSep "\n" ( + lib.concatMap (g: lib.optionals (g.gid != null) [ "${g.name}:x:${toString g.gid}" ]) ( + lib.attrValues config.users.groups + ) + ) + ); } { target = "/etc/shadow"; @@ -314,6 +323,12 @@ in { source = "${config.finit.package}/lib/finit/rescue.conf"; } { source = "${config.finit.package}/lib/finit/tmpfiles.d"; } { source = "${config.finit.package}/lib/tmpfiles.d"; } + ] + ++ lib.optionals config.services.keventd.enable [ + { + target = "/etc/udev/rules.d"; # keventd reads /etc - avoids collision + source = "${config.finit.package}/lib/udev/rules.d"; + } ]; }; } diff --git a/modules/programs/brightnessctl/default.nix b/modules/programs/brightnessctl/default.nix index f11466c5..ae37e12e 100644 --- a/modules/programs/brightnessctl/default.nix +++ b/modules/programs/brightnessctl/default.nix @@ -23,7 +23,7 @@ in type = lib.types.package; default = package.override { logindSupport = config.services.elogind.enable; - udevSupport = config.services.udev.enable; + udevSupport = config.services.udev.enable || config.services.keventd.enable; systemdLibs = config.services.elogind.package; }; diff --git a/modules/programs/hyprland/default.nix b/modules/programs/hyprland/default.nix index 0293718c..387a979d 100644 --- a/modules/programs/hyprland/default.nix +++ b/modules/programs/hyprland/default.nix @@ -17,16 +17,16 @@ let Keywords=tiling;wayland;compositor; ''; - # libudev-zero is a hard requirement when running mdevd + # libudev-zero is a hard requirement when running mdevd or keventd libinput = pkgs.libinput.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; wacomSupport = false; } ); aquamarine = pkgs.aquamarine.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { inherit libinput; udev = pkgs.libudev-zero; @@ -49,7 +49,7 @@ in inherit aquamarine libinput; # since we're recompiling go ahead and disable systemd - withSystemd = !config.services.mdevd.enable; + withSystemd = !(config.services.mdevd.enable || config.services.keventd.enable); }; defaultText = lib.literalExpression "pkgs.hyprland"; description = '' diff --git a/modules/programs/labwc/default.nix b/modules/programs/labwc/default.nix index 7040a5c8..843d46d7 100644 --- a/modules/programs/labwc/default.nix +++ b/modules/programs/labwc/default.nix @@ -17,9 +17,9 @@ let Type=Application ''; - # libudev-zero is a hard requirement when running mdevd + # libudev-zero is a hard requirement when running mdevd or keventd libinput = pkgs.libinput.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; wacomSupport = false; } diff --git a/modules/programs/lxqt/default.nix b/modules/programs/lxqt/default.nix index 88a46ddd..1724b3ed 100644 --- a/modules/programs/lxqt/default.nix +++ b/modules/programs/lxqt/default.nix @@ -29,7 +29,7 @@ let ''; libinput = pkgs.libinput.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; wacomSupport = false; } diff --git a/modules/programs/mangowc/default.nix b/modules/programs/mangowc/default.nix index b4083904..85d83ba7 100644 --- a/modules/programs/mangowc/default.nix +++ b/modules/programs/mangowc/default.nix @@ -18,9 +18,9 @@ let Type=Application ''; - # libudev-zero is a hard requirement when running mdevd + # libudev-zero is a hard requirement when running mdevd or keventd libinput = pkgs.libinput.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; wacomSupport = false; } diff --git a/modules/programs/niri/default.nix b/modules/programs/niri/default.nix index 10a4dbbb..4cbf1cc2 100644 --- a/modules/programs/niri/default.nix +++ b/modules/programs/niri/default.nix @@ -16,18 +16,20 @@ let Type=Application ''; - overrideAttrs = lib.optionalAttrs config.services.mdevd.enable { - eudev = pkgs.libudev-zero; + overrideAttrs = + # libudev-zero is a hard requirement when running mdevd or keventd + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { + eudev = pkgs.libudev-zero; - # since we're recompiling go ahead and disable systemd - withSystemd = false; - - # libudev-zero is a hard requirement when running mdevd - libinput = pkgs.libinput.override { - udev = pkgs.libudev-zero; - wacomSupport = false; + libinput = pkgs.libinput.override { + udev = pkgs.libudev-zero; + wacomSupport = false; + }; + } + // lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { + # since we're recompiling go ahead and disable systemd + withSystemd = false; }; - }; in { options.programs.niri = { diff --git a/modules/programs/regreet/default.nix b/modules/programs/regreet/default.nix index ade63154..c9ea5e51 100644 --- a/modules/programs/regreet/default.nix +++ b/modules/programs/regreet/default.nix @@ -11,9 +11,9 @@ let configFile = format.generate "regreet.toml" cfg.settings; - # libudev-zero is a hard requirement when running mdevd + # libudev-zero is a hard requirement when running mdevd or keventd libinput = pkgs.libinput.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; wacomSupport = false; } @@ -27,9 +27,9 @@ let }; xinit' = pkgs.xinit.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { xorg-server = pkgs.xorg-server.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; } ); diff --git a/modules/programs/sway/default.nix b/modules/programs/sway/default.nix index c3d646f0..779b35ac 100644 --- a/modules/programs/sway/default.nix +++ b/modules/programs/sway/default.nix @@ -16,9 +16,9 @@ let DesktopNames=sway;wlroots ''; - # libudev-zero is a hard requirement when running mdevd + # libudev-zero is a hard requirement when running mdevd or keventd libinput = pkgs.libinput.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; wacomSupport = false; } @@ -35,7 +35,7 @@ let inherit libinput wlroots_0_20; # since we're recompiling go ahead and disable systemd - systemdSupport = !config.services.mdevd.enable; + systemdSupport = !(config.services.mdevd.enable || config.services.keventd.enable); }; in { diff --git a/modules/programs/tuigreet/default.nix b/modules/programs/tuigreet/default.nix index 4da24239..6b3ecdcb 100644 --- a/modules/programs/tuigreet/default.nix +++ b/modules/programs/tuigreet/default.nix @@ -9,9 +9,9 @@ let cfg = config.programs.tuigreet; xinit' = pkgs.xinit.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { xorg-server = pkgs.xorg-server.override ( - lib.optionalAttrs config.services.mdevd.enable { + lib.optionalAttrs (config.services.mdevd.enable || config.services.keventd.enable) { udev = pkgs.libudev-zero; } ); diff --git a/modules/services/keventd/default.nix b/modules/services/keventd/default.nix new file mode 100644 index 00000000..c604228b --- /dev/null +++ b/modules/services/keventd/default.nix @@ -0,0 +1,134 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.services.keventd; +in +{ + options.services.keventd = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable [keventd](${pkgs.finit.meta.homepage}) as a system service. + ''; + }; + + debug = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable debug logging. + ''; + }; + + extraArgs = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + description = '' + Additional arguments to pass to `keventd`. + ''; + }; + + path = lib.mkOption { + type = with lib.types; listOf path; + default = [ ]; + description = '' + Packages added to the {env}`PATH` environment variable when + executing programs from Udev rules. + + coreutils, gnu{sed,grep}, util-linux + automatically included. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = lib.versionAtLeast config.finit.package.version "5.0"; + message = "finit version must be at least 5.0"; + } + ]; + + services.keventd.extraArgs = [ + "-c" + (if cfg.debug then "-d" else "-n") + ]; + + services.keventd.path = [ + config.programs.coreutils.package + pkgs.gnugrep + pkgs.gnused + pkgs.kmod + pkgs.util-linux + ]; + + # contribute finit's bundled rules to the udev packages list. + services.udev.packages = [ config.finit.package ]; + + environment.etc."udev/rules.d".source = + pkgs.runCommand "keventd-rules" + { + __structuredAttrs = true; + preferLocalBuild = true; + allowSubstitutes = false; + packages = lib.unique config.services.udev.packages; + } + '' + mkdir -p $out + shopt -s nullglob + + for i in "''${packages[@]}"; do + echo "Adding rules for package $i" + for j in $i/{etc,lib,var/lib}/udev/rules.d/*; do + echo "Copying $j to $out/$(basename $j)" + cat $j > $out/$(basename $j) + done + done + + for i in $out/*.rules; do + substituteInPlace $i \ + --replace-quiet \"/sbin/modprobe \"${pkgs.kmod}/bin/modprobe \ + --replace-quiet \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \ + --replace-quiet \"/sbin/blkid \"${pkgs.util-linux}/sbin/blkid \ + --replace-quiet \"/bin/mount \"${pkgs.util-linux}/bin/mount \ + --replace-quiet /usr/bin/readlink ${lib.getExe' config.programs.coreutils.package "readlink"} \ + --replace-quiet /usr/bin/cat ${lib.getExe' config.programs.coreutils.package "cat"} \ + --replace-quiet /usr/bin/basename ${lib.getExe' config.programs.coreutils.package "basename"} 2>/dev/null + done + ''; + + finit.services.keventd = { + inherit (cfg) path; + + description = "device event daemon (keventd)"; + command = "${config.finit.package}/libexec/finit/keventd " + lib.escapeShellArgs cfg.extraArgs; + runlevels = "S12345789"; + cgroup.name = "init"; + notify = "pid"; + log = true; + }; + + # TODO: add finit.services.reloadTriggers option + environment.etc."finit.d/keventd.conf".text = lib.mkAfter '' + + # reload trigger + # ${config.environment.etc."udev/rules.d".source} + ''; + + # TODO: share between device managers + system.activation.scripts.keventd = lib.mkIf config.boot.kernel.enable { + text = '' + # Allow the kernel to find our firmware. + if [ -e /sys/module/firmware_class/parameters/path ]; then + echo -n "${config.hardware.firmware}/lib/firmware" > /sys/module/firmware_class/parameters/path + fi + ''; + }; + }; +} diff --git a/modules/services/rsyslog/default.nix b/modules/services/rsyslog/default.nix index eef04945..3f7f7bd1 100644 --- a/modules/services/rsyslog/default.nix +++ b/modules/services/rsyslog/default.nix @@ -53,7 +53,8 @@ in runlevels = "S0123456789"; conditions = lib.optionals config.services.udev.enable [ "run/udevadm:5/success" ] - ++ lib.optionals config.services.mdevd.enable [ "run/coldplug/success" ]; + ++ lib.optionals config.services.mdevd.enable [ "run/coldplug/success" ] + ++ lib.optionals config.services.keventd.enable [ "pid/keventd" ]; command = "${pkgs.rsyslog-light}/bin/rsyslogd -n -d -f ${configFile}"; }; diff --git a/modules/services/sysklogd/default.nix b/modules/services/sysklogd/default.nix index 107e514d..8446efca 100644 --- a/modules/services/sysklogd/default.nix +++ b/modules/services/sysklogd/default.nix @@ -63,7 +63,8 @@ in runlevels = "S0123456789"; conditions = lib.optionals config.services.udev.enable [ "run/udevadm:5/success" ] - ++ lib.optionals config.services.mdevd.enable [ "run/coldplug/success" ]; + ++ lib.optionals config.services.mdevd.enable [ "run/coldplug/success" ] + ++ lib.optionals config.services.keventd.enable [ "pid/keventd" ]; command = "${cfg.package}/bin/syslogd -F"; notify = "pid"; };