NetworkManager-dispatcher does not find binary

Script:

#!/bin/sh

if [ "$1" = "wg0-mullvad" ]; then
  pkill -SIGRTMIN+10 i3blocks
fi

Config snippet:

  environment.systemPackages = with pkgs; [
    procps
  ];
  systemd.services.NetworkManager-dispatcher.enable = lib.mkForce true;
  networking.networkmanager.dispatcherScripts = [
    {
      source = ./scripts/vpn_swaybar_toggle.sh;
      type = "basic";
    }
  ];

Log output:

Apr 19 15:35:03 desktop nm-dispatcher[15226]: /etc/NetworkManager/dispatcher.d/03userscript0001: line 7: pkill: command not found
Apr 19 15:35:03 desktop nm-dispatcher[15217]: req:1 'down' [wg0-mullvad], "/etc/NetworkManager/dispatcher.d/03userscript0001": complete: process failed with Script '/etc/NetworkManager/dispatcher.d/03userscript0001' exited with status 127

I have also tried to use the full path /run/current-system/sw/bin/pkill which results in the same error.

Running echo $PATH within the dispatcher script gives:

Apr 19 15:43:06 desktop nm-dispatcher[30278]:
/nix/store/i1krbdqcy6xd1587c57j9v5asigy9w1b-iproute2-6.8.0/bin:
/nix/store/vfj3g5b4rylggcva7ri05pcf9x85ybhd-util-linux-2.39.3-bin/bin:
/nix/store/ifzwv2xqwdnv1gz87rxkizi67py5p3vj-coreutils-9.4/bin:
/nix/store/ifzwv2xqwdnv1gz87rxkizi67py5p3vj-coreutils-9.4/bin:
/nix/store/jg2i1qj5js5ckzvfq5b9p9j1gcv69750-findutils-4.9.0/bin:
/nix/store/avqi5nnx7qydr078ssgifc2hgzqipqgx-gnugrep-3.11/bin:
/nix/store/237dff1igc3v09p9r23a37yw8dr04bv6-gnused-4.9/bin:
/nix/store/4npvfi1zh3igsgglxqzwg0w7m2h7sr9b-systemd-255.4/bin:
/nix/store/i1krbdqcy6xd1587c57j9v5asigy9w1b-iproute2-6.8.0/sbin:
/nix/store/vfj3g5b4rylggcva7ri05pcf9x85ybhd-util-linux-2.39.3-bin/sbin:
/nix/store/ifzwv2xqwdnv1gz87rxkizi67py5p3vj-coreutils-9.4/sbin:
/nix/store/ifzwv2xqwdnv1gz87rxkizi67py5p3vj-coreutils-9.4/sbin:
/nix/store/jg2i1qj5js5ckzvfq5b9p9j1gcv69750-findutils-4.9.0/sbin:
/nix/store/avqi5nnx7qydr078ssgifc2hgzqipqgx-gnugrep-3.11/sbin:
/nix/store/237dff1igc3v09p9r23a37yw8dr04bv6-gnused-4.9/sbin:
/nix/store/4npvfi1zh3igsgglxqzwg0w7m2h7sr9b-systemd-255.4/sbin

This would explain why the command pkill is not found, but why is the binary also not accessible with the full path?

Is this NixOS related, or am I missing something about NetworkManager?

Thanks in advance for any help.

Things in your user’s path are not necessarily in the path of the systemd unit executing your script. Generally, what is and what is not available in a specific shell on NixOS is very specific to the exact context to ensure that random installation/deinstallation/updates don’t break things.

You’d need to explicitly add the package to the path of that systemd unit:

systemd.services.NetworkManager-dispatcher = {
  enable = lib.mkForce true;
  path = [
    pkgs.procps # I think
  ];
};

Alternatively, you could write the script with .text and use ${pkgs.procps}/bin/pkill to get the absolute path of the binary in the nix store.

That script is not particularly robust, by the way. I think you could make it much cleaner with a user unit that uses the sway socket or some kind of PID file (which swaybar almost certainly creates if it can’t be managed via the socket).

Thank you very much, I did not know about systemd.services.<name>.path, but it sounds like it should do the trick, will try as soon as I am back home.

As for your different suggestions, I don’t quite understand what you mean (I was following the examples from GitHub - vivien/i3blocks: The hacker-friendly status_command for Sway and i3).

Do you mean that just calling pkilll with a name instead of searching for a specific process is the weak part?

And “using the sway socket” means communicating through swaymsg, right?

I think using pkill at all is a bit ugly here. There’s no guarantee it refers to the right process - you want the one that’s tied to your running sway.

In practice on a single-user system it will probably be fine, but e.g. on a multi-user system you could end up killing some random other users’ process. Doesn’t account for other things like changed process names or anything either.

This feels like a waste when you have both systemd (which keeps track of PIDs) and sway’s socket (yep, used by swaymsg, among other things) to do more clean things if you put in more effort.

It probably ultimately doesn’t matter and wastes your time learning unrelated stuff, just looks ugly to me and I can’t help myself trying to review code. Let’s call it an occupational hazard.