How do I use ENV{SYSTEMD_USER_WANTS}= in udev rule?

Posted on

Problem :

I want to set up a in my user level systemd. The idea is to run some services to configure my external displays.

I currently have this as my rule:

SUBSYSTEM=="usb", ACTION=="add", ENV{ID_VENDOR}=="17ef", ENV{ID_MODEL}=="100a", SYMLINK+="tp_mini_dock", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}=""

The rule gets detected just fine (I can see dev-tp_mini_dock.device when I’m docked).

I then have this in ~/.config/systemd/user/ (also tried /etc/systemd/user with no luck):

Description=Docked to ThinkPad Mini Dock

But this does not start when I dock. However, if I manually start while docked, it stops as expected when I undock.

However, if I use ENV{SYSTEMD_WANTS}="" and put the file in /etc/systemd/system/, the target starts as expected when I dock. The problem then, is that my user level instance doesn’t know about system-level services/targets.

Any thoughts? I’ve seen a few other questions around the net, and one almost exactly like mine:

Solution :

You can try replacing SYSTEMD_USER_WANTS with MANAGER_USER_WANTS. I’m not 100% sure about this name change, but at least in systemd-226 there is no mention of SYSTEMD_USER_WANTS in the sources any more and it seems to be replaced by MANAGER_USER_WANTS. At least it worked for me for the similar case.

Although I still don’t know how ENV{SYSTEMD_USER_WANTS} works, I managed to get my specific problem solved after reading this blog.

It turns out that I can install targets as a dependency on devices. I changed my unit file ~/.config/systemd/user/ to:

Description=Docked to ThinkPad Mini Dock


and my udev rule to:

SUBSYSTEM=="usb", ACTION=="add", ENV{ID_VENDOR}=="17ef", ENV{ID_MODEL}=="100a", SYMLINK+="tp_mini_dock", TAG+="systemd"

and then enable it with systemctl --user enable

Now, when I dock it, the udev rule creates the systemd device, which in turn starts up the target. Then the BindsTo option makes sure that when the device disappears (gets unplugged) the target gets stopped.

I had to do some nonsensical magic to get this to work when I login with the dock already plugged in. One would imagine that simply adding to WantedBy and After would be enough… I’ll add a link to a blog after I write it.

Man… That problem made me sick as well, what a bug!

In my case, I wanted to listen to HDMI (monitor hotplug) events, and I found a trick how to work around this problem. I thought to myself, well, if this udev somehow knows that it started a service with this or that name and refuses to do it again, then let’s make it believe that it starts a new service each time. All eyes on the corresponding udev event:

UDEV  [19214.534185] change   /devices/pci0000:00/0000:00:01.0/0000:01:00.0/drm/card0 (drm)

and notice the SEQNUM. It’s changing on every new event and that’s exactly what we want:

ACTION=="change", SUBSYSTEM=="drm", ENV{HOTPLUG}=="1", ENV{SYSTEMD_USER_WANTS}+="monitor-hotplug@$env{SEQNUM}.service", TAG+="systemd"

Works like a charm even for ~/.config/systemd/user/monitor-hotplug@.service. Hopefully, your events also have SEQNUM or something similar.

Leave a Reply

Your email address will not be published. Required fields are marked *