[systemd-devel] Stop all uninstalled units

Tim Cuthbertson tim at gfxmonk.net
Wed Jul 17 17:22:29 PDT 2013

On Thu, Jul 18, 2013 at 9:47 AM, Lennart Poettering
<lennart at poettering.net>wrote:

> On Wed, 17.07.13 22:14, Tim Cuthbertson (tim at gfxmonk.net) wrote:
> > Hi Folks,
> >
> > I've posted a serverfault question [0], but it got no answers so I
> thought
> > I'd bring it to the mailing list:
> >
> > 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?
> >
> > I do not want to have to somehow know what I've uninstalled, or for the
> > command to work only in some circumstances - I want something that I can
> > run at any point, with no additional knowledge, that will stop all units
> > not backed by a unit file.
> >
> > I've currently got a hacky script that:
> >  - Runs `list-units` to get all unit names
> >  - Then `show -p ActiveState -p UnitFileState $unit` on each
> >  - It then runs `systemctl stop` on each unit with a UnitFileState of ""
> > (empty string), and ActiveState of anything but "failed".
> >
> > This is almost certainly missing some edge case, as I couldn't really
> find
> > any documentation of these properties, it just seemed to be what occurred
> > with the examples I encountered.
> >
> > I'm hoping there's a better way, can anyone point me in the right
> direction?
> >
> > [0]:
> >
> http://serverfault.com/questions/521504/systemd-stop-all-uninstalled-units
> 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}'`
> And there you go.
> Lennart
> --
> Lennart Poettering - Red Hat, Inc.

Thanks, Lennart (and Colin), that looks like a much better approach,
although --type=not-found is rejected by old versions:

$ systemctl --all --type=not-found --type=error
Unknown unit type or load state 'not-found'.
Use -t help to see a list of allowed values.

$ systemctl --version
systemd 204

But I can probably try both, and fall back to just --error if not-found is

I am not too concerned about systemd not knowing how best to kill the units
- they don't contain any special stop actions, so it would be using the
default action to kill the service anyway. But point taken, in the general
case this is probably not advisable.

For background of why this might happen (if you or Colin are still
curious), I'm installing systemd units not as part of any package -
basically, the user has some application-specific config that they can
change at any moment. They run:

$ foo install <my-config-file>

And (regardless of any previous state), the units generated by that config
file (and no units defined by previous invocations) should be installed /
running. I put an X-Generated-By-MyApp=true in each of the generated unit
files, so I can scan the /etc/systemd/system folder for previously
installed units. This should mean that I can stop them immediately, but I
wanted a failsafe way of doing it just in case things get left in an
unknown state (because of bugs or unanticipated failure modes in my code).

I also had the notion if being able to affect a system from another with
access to its filesystem, e.g. `foo install config-file
--root=/srv/container1/etc/systemd/system` or by running the unit
generation once and rsync'ing the installed units to multiple identical
VMs, and then running a routine task in the container to "fix up" the state
to reflect the installed units. But this is probably not worth the
weirdness ;)

Cheers, and sorry for the double-post.
 - Tim Cuthbertson.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/systemd-devel/attachments/20130718/f556bb32/attachment.html>

More information about the systemd-devel mailing list