How to modify systemd script?

Hi,
I am trying to get the suspend-then-hibernate command to work on my machine. The problem is, I have an Nvidia GPU, which breaks things.

In order to fix this issue, I need to modify the systemd/system-sleep/nvidia script with following code.

#!/bin/sh

case "$1" in
    pre)
        case "$SYSTEMD_SLEEP_ACTION" in
            suspend|hibernate)
                /usr/bin/nvidia-sleep.sh "$SYSTEMD_SLEEP_ACTION"
                ;;
            suspend-after-failed-hibernate)
                /usr/bin/nvidia-sleep.sh "suspend"
                ;;
        esac
        ;;
    post)
        /usr/bin/nvidia-sleep.sh "resume"
        sleep 4
        ;;
esac

As an unexperienced NixOS user, I have no clue how to do that on my machine. Can it be done in configuration.nix?

If I understand it correctly, it resides in run/opengl-driver/lib/systemd/system-sleep/nvidia. This is however just a link from /nix/store, isn’t it?

I’d be grateful for any advice.

Yes. You would need to modify the package to change that. You’d probably do this something like:

hardware.nvidia.package = pkgs.symlinkJoin {
  name = "custom-nvidia";
  paths = [
    config.boot.kernelPackages.nvidia_x11
    # The latter probably needs to be a different function that can
    # put the script in the right path, for illustration purposes only
    (pkgs.writeShellScriptBin "sleep.sh" ''code here'')
  ];
};

It may not be that simple though, quite likely the nvidia package has some passthru things that are required for the module, at which point you’d probably need to override the nvidia package (this is probably fine, it’s built downstream anyway because it’s proprietaty).

It might also not be used this way, but grabbed through some other mechanism, at which point you’d need to dig into how NixOS’ suspend config works.

Thank you. Unfortunately, it won’t rebuild.

error:
       … while calling the 'head' builtin

         at /nix/store/0g53xyh39z3y90p4d8r341wbqyjy1zhl-source/lib/attrsets.nix:960:11:

          959|         || pred here (elemAt values 1) (head values) then
          960|           head values
             |           ^
          961|         else

       … while evaluating the attribute 'value'

         at /nix/store/0g53xyh39z3y90p4d8r341wbqyjy1zhl-source/lib/modules.nix:809:9:

          808|     in warnDeprecation opt //
          809|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          810|         inherit (res.defsFinal') highestPrio;

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: attribute 'useProfiles' missing

       at /nix/store/0g53xyh39z3y90p4d8r341wbqyjy1zhl-source/nixos/modules/hardware/video/nvidia.nix:450:62:

          449|         environment.etc = {
          450|           "nvidia/nvidia-application-profiles-rc" = lib.mkIf nvidia_x11.useProfiles {source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc";};
             |                                                              ^
          451|

Not sure, what to do with it.

I found out, I can work around the issue by disabling the dGPU and running only on AMD iGPU, but that isn’t a fix really.

Yep, that’s what I mentioned, the nvidia package has some annoying complexity to it that makes it hard to override with symlinkJoin, or just work with it in general. I ran into this issue when I was trying to play around with hardware.nvidia.open.

You could try overriding the nvidia package directly:

hardware.nvidia.package = config.boot.kernelPackages.nvidia_x11.overrideAttrs (old: {
  postInstall = ''
    cp ${./nvidia-sleep.sh} $out/bin/nvidia-sleep.sh
    chmod +x $out/bin/nvidia-sleep.sh
  '';
});

Which should persist the useProfiles attribute, I think? For reference, that attribute is used here in the nvidia module:

But it doesn’t seem to be set in the actual nvidia package, only used in the mkDerivation call, so I’m not sure how it ever makes it into the package the module uses: https://github.com/NixOS/nixpkgs/blob/428544ae95eec077c7f823b422afae5f174dee4b/pkgs/os-specific/linux/nvidia-x11/generic.nix#L124

This means that if the above doesn’t work, you might be able to work around that error with:

environment.etc."nvidia/nvidia-application-profiles-rc".source = lib.mkForce "${hardware.nvidia.package.bin}/share/nvidia/nvidia-application-profiles-rc";

Thank you!
I might try it out later. That said, I may just settle for iGPU on Nix and use GPU passthrough with my Nvidia card as I need some Windows only apps anyway. There are too many quirks with Nvidia on Linux. It’s a shame.