WriteShellScriptBin system path in udev rule

Hello everyone,

I’ve been configuring my laptop (a Thinkpad T14s Gen 3) to run nixos for the past 2 weeks. Great and stable experience using configuration.nix and home-manager installed as a module. Will migrate later to flakes when I’m more comfortable. It is really exciting to learn Nix while configuring my machine and environment to be just right for me.

As written here, I need to add some AMD Pstate EPP udev rules + scripts since tlp does not fully support this:
https://wiki.archlinux.org/title/Lenovo_ThinkPad_T14s_(AMD)_Gen_3

I have the two scripts udev scripts and I add them to system packages like so:

  //configuration.nix
  ...
  environment.systemPackages = with pkgs; [
    powertop
    (writeShellScriptBin "udev_on_bat" (builtins.readFile ./udev_on_bat.sh))
    (writeShellScriptBin "udev_on_ac" (builtins.readFile ./udev_on_ac.sh))
  ];

I have the script in my path afterwards and it is ok.

Now, I try to put it into udev rules like so:

services.udev.extraRules = ''
SUBSYSTEM=="power_supply", ATTR{online}=="0", RUN+="udev_on_bat"
SUBSYSTEM=="power_supply", ATTR{online}=="1", RUN+="udev_on_ac"
'';

But I get this error on nixos-rebuild:

Checking that all programs called by relative paths in udev rules exist in /nix/store/8lgs0dqh9ks1164fp4g14gq7w1ihjbf0-systemd-253.5/lib/udev... FAIL
udev_on_bat is called in udev rules but not installed by udev
error: builder for '/nix/store/c321ffb5lbv8r8isp89flc1vwq19r7m4-udev-rules.drv' failed with exit code 1
error: 1 dependencies of derivation '/nix/store/yd3xgyndqk9dnwr9bvwhc2q461fpkilb-etc.drv' failed to build
error: 1 dependencies of derivation '/nix/store/713amm5r6bw0yiligsqak8kwsx1w7vnf-nixos-system-nixos-23.05.1249.ef0bc397634.drv' failed to build

I don’t know what to do in this case, could you please help me?

Thanks!

udev rules have access to only a very minimal runtime path, and that does not include access to what’s declared in systemPackages. if you don’t use those scripts elsewhere you can inline them into the rule like this:

services.udev.extraRules = ''
  SUBSYSTEM=="power_supply", ATTR{online}=="0", RUN+="${writeShellScriptBin "udev_on_bat" (builtins.readFile ./udev_on_bat.sh)}"
  # etc
'';

if you do use them elsewhere it’s better to bind the scripts in a let and use that binding in all places.

1 Like

Thanks so much! Works like a charm!