Some app launchers these days run each app in a new systemd scope, which puts the app process and any child processes into their own cgroup. For example I use rofi which does this, and I noticed that fuzzel does also. That is handy for tracking and cleaning up child processes!
You can see how processes are organized by running,
$ systemctl --user status
I think that’s a quite useful way to see processes organized. Looking at it I noticed a couple of scopes that shouldn’t still be running.
Just for fun I wanted to use this to try to script a better killall. For example if I run $ killscope slack I want the script to:
- find processes with the name “slack”
- find the names of the systemd scopes that own those processes (for example, app-niri-rofi-2594858.scope)
- kill processes in each scope with a command like, systemctl --user stop app-niri-rofi-2594858.scope
Step 2 turned out to be harder than I liked. Does anyone know of an easy way to do this? Ideally I’d like a list of all scopes with information for all child processes in JSON or another machine-readable format.
systemctl --user status gives me all of the information I want, listing each scope with the command for each process under it. But it is not structured in an easily machine-readable format. Adding --output json does nothing.
systemd-cgls shows the same cgroup information that is shown in systemctl --user status. But again, I don’t see an option for machine-readable output.
systemd-cgtop is interesting, bot not relevant.
Anyway, I got something working by falling back on the classic commands. ps can show the cgroup for each process:
$  ps x --format comm=,cgroup= | grep '^slack\b'
slack           0::/user.slice/user-1000.slice/user@1000.service/app.slice/app-niri-rofi-2594858.scope
slack           0::/user.slice/user-1000.slice/user@1000.service/app.slice/app-niri-rofi-2594858.scope
slack           0::/user.slice/user-1000.slice/user@1000.service/app.slice/app-niri-rofi-2594858.scope
...
The last path element of the cgroup happens to be the scope name. That can be extracted with awk -F/ '{print $NF}' Then unique scope names can be fed to xargs. Here is a shell function that puts everything together:
function killscope() {
    local name="$1"
    ps x --format comm=,cgroup= \
        | grep "^$name\b" \
        | awk -F/ '{print $NF}' \
        | sort | uniq \
        | xargs -r systemctl --user stop
}
It could be better, and it might be a little dangerous. But it works!
- cgroup names can be read from /proc/PID/cgroup. - pgrep --exact "$1" \ | xargs --no-run-if-empty --replace cat /proc/{}/cgroup \ | sort --unique- Nice! Thanks! 
 


