Running nvidia-settings as a systemd unit

I’m new to NixOS. On my previous Linux install (which was Arch) I had a user systemd unit that executed nvidia-settings -l to set the correct color space for my monitor (really a TV) on each graphical session startup. I forgot to back it up during migration, so I tried to recreate the unit and arrived at this configuration:

[Unit]
Description=nvidia-settings apply
Requires=graphical-session.target
After=graphical-session.target

[Service]
User=user
Type=oneshot
ExecStart="nvidia-settings -l"

[Install]
WantedBy=multi-user.target

I placed the unit into the user units directory and enabled it. The unit fails to start. Its status log is this:

Starting nvidia-settings apply...
novideo.service: Main process exited, code=exited, status=216/GROUP
novideo.service: Failed with result 'exit-code'.
Failed to start nvidia-settings apply.

I’ve played with Group= setting, setting it to users and wheel, to no avail.
Moreover, if I launch nvidia-settings -l myself, I’m treated with the following errors, but it does the deed and applies the configuration nevertheless.

[user@nixos:~]$ nvidia-settings -l
ERROR: libGL setup error : libGL.so.1: cannot open shared object file: No such file or directory
ERROR: libEGL setup error : libEGL.so.1: cannot open shared object file: No such file or directory
ERROR: libEGL setup error : libEGL.so.1: cannot open shared object file: No such file or directory

How can I get rid of these errors and, more importantly, create a proper systemd unit for my task? Once I get a working unit file, I can hopefully “move” it into the system configuration.

Running NixOS 24.05, Linux nixos 6.10.4 #1-NixOS SMP PREEMPT_DYNAMIC Sun Aug 11 10:58:04 UTC 2024 x86_64 GNU/Linux

I believe systemd user units cannot do user manipulation without some additional config. Since this is a user unit, simply omit that setting, it will run as your user.

The error means that systemd failed to set the process group, which I’m going to guess is related to that setting, even if it looks like it should technically be a noop. Edit: Reading through the docs, I think systemd might be trying to change the user’s group to a subset of the full groups, and that fails because it isn’t allowed to do that in a user service.

ExecStart also doesn’t need quotes, perhaps it’s treating the whole thing as arg0, which would definitely cause issues. Edit: No, explicitly unquoted.

Even then, systemd units don’t normally share your system PATH, so I’d expect nvidia-settings to be unavailable in the unit, unless your config does an environment import somewhere. And after that we’ll need to talk about the details of wayland/x11 startup, depending on what you use. Let’s see what systemd says after you remove the user setting.

After removing User and the quotes in ExecStart, the exit code in unit status has changed to 203/EXEC. If I remember correctly, this is something of a permission error, and this is why I introduced the User parameter into the unit.
I use X11, totally forgot to include that. The tool doesn’t apply the color space when using Wayland.

I’ve made a couple fixes. The current iteration looks like this:

[Unit]
Description=nvidia-settings apply
After=plasma-workspace.target

[Service]
Type=oneshot
Environment=DISPLAY=:0
ExecStart=/run/current-system/sw/bin/nvidia-settings -l

[Install]
WantedBy=plasma-workspace.target

It now works as designed if the unit is started manually, however it fails when autostarting:

Starting nvidia-settings apply...
ERROR: The control display is undefined; please run `/run/current[/sw/bin/nvidia-settings --help...]
novideo.service: Main process exited, code=exited, status=1/FAILURE

Replacing the After target with plasma-plasmashell.service made it start after the display(s) and whatever is fully initialized and therefore fixed the error. The unit fully works now. I will attempt to integrate this into my system configuration now.

2 Likes

So I’ve removed the manual unit, and added this to my system configuration:

systemd.user.services.novideo = {
  name = "novideo";
  description = "nvidia-settings apply";
  enable = true;
  serviceConfig = { Type = "oneshot"; };
  script = "/run/current-system/sw/bin/nvidia-settings -l";
  environment = { DISPLAY = ":0"; };
  after = [ "plasma-plasmashell.service" ];
  wantedBy = [ "default.target" ];
};

It results in Main process exited, code=exited, status=1/FAILURE on startup. Manual start works fine.

That’s a different target than what you had before.

While we’re at it, might as well replace that with the proper nix-store path:

script = "${config.hardware.nvidia.package.settings}/bin/nvidia-settings -l";
1 Like

Yeah, I made a typo while translating the unit file. The following configuration works as intended:

  systemd.user.services.novideo = {
    name = "novideo";
    description = "nvidia-settings apply";
    enable = true;
    serviceConfig = { Type = "oneshot"; };
    script = "${config.hardware.nvidia.package.settings}/bin/nvidia-settings -l";
    environment = { DISPLAY = ":0"; };
    after = [ "plasma-plasmashell.service" ];
    wantedBy = [ "plasma-workspace.target" ];
  };

It works, yes, so I’ll mark this post as the solution. Thanks for your input! But still complains about missing libGL.so.1 and such. Is there anything that can be done in that regard?