Systemd: stop all uninstalled units

systemd

I have some systemd units installed and running. Let's say I manually uninstall foo.service by

  • removing its .service (and .socket) files
  • removing all symlinks (e.g from default.target.wants/)

I can run systemctl daemon-reload, and then I see:

# systemctl status foo.service
foo.service
   Loaded: error (Reason: No such file or directory)
   Active: active (running) since Mon 2013-07-08 13:50:29 EST; 48s ago
 Main PID: 1642 (node)

So systemd knows that it's not installed, and that it is running. Is there some command I can use to stop all running services which no longer have a unit file?


Things I've already considered:

  • systemctl isolate <current-target>

    This would have the side effect of stopping other manually-started services that aren't required by the current target.

  • Use systemctl disable instead of manually removing files

    I'd like to, but this script may be run from a host machine with access to the file system of a running container – it can't call systemd directly.

  • Use systemctl stop foo.service

    This implies I know which services have been uninstalled. I don't want to have to figure this out (or remember it), I want a general command that can be run at any time to stop any lingering services.

Best Answer

I asked the mailing list, and Lennart Poettering responded with the following advice:

http://lists.freedesktop.org/archives/systemd-devel/2013-July/012083.html

Quoting here for posterity:


So, the correct way to handle this is to make sure the packages in question contain the right scriplets that terminate all units they include before deinstallation. Of course, there'll always be broken packages like this I fear, hence I can totally see your usecase.

There's currently no nice way to handle this, but what you can do is this:

$ systemctl --all --type=not-found --type=error

This will list you all units where the load state is either "error" or "not-found" (note that 'not-found' is available only in very recent versions, and in older systemd versions was just a special case of 'error'. The command line above works for all versions). The --type= switch is used to filter unit types, but actually also can be used to filter for the load state.

Then filter out the first column:

$ systemctl --no-legend --all --type=not-found --type=error | awk '{ print $1 }'

This will give you a list of unit files which got referenced or started but have no unit file installed. Then use this to stop the units:

$ systemctl stop `systemctl --no-legend -all --type=not-found --type=error | awk '{ print $1}'`