Problem :
I want to set up a docked.target
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}="docked.target"
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/docked.target
(also tried /etc/systemd/user
with no luck):
[Unit]
Description=Docked to ThinkPad Mini Dock
BindTo=dev-tp_mini_dock.device
But this does not start when I dock. However, if I manually start docked.target
while docked, it stops as expected when I undock.
However, if I use ENV{SYSTEMD_WANTS}="docked.target"
and put the file in /etc/systemd/system/docked.target
, 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: https://bbs.archlinux.org/viewtopic.php?pid=1600019
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/docked.target
to:
[Unit]
Description=Docked to ThinkPad Mini Dock
BindsTo=dev-tp_mini_dock.device
After=dev-tp_mini_dock.device
[Install]
WantedBy=dev-tp_mini_dock.device
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 docked.target
.
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 default.target
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)
ACTION=change
DEVLINKS=/dev/dri/by-path/pci-0000:01:00.0-card
DEVNAME=/dev/dri/card0
DEVPATH=/devices/pci0000:00/0000:00:01.0/0000:01:00.0/drm/card0
DEVTYPE=drm_minor
HOTPLUG=1
ID_FOR_SEAT=drm-pci-0000_01_00_0
ID_PATH=pci-0000:01:00.0
ID_PATH_TAG=pci-0000_01_00_0
MAJOR=226
MINOR=0
SEQNUM=3364
SUBSYSTEM=drm
USEC_INITIALIZED=3280572
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.