40

I was reading doc and it is still unclear for me, whether the following is possible to accomplish:

service defined in ~/.config/systemd/user/task.service that depends on system sleep.target (~/.config/systemd/user/sleep.target.wants/task.service).

Now I expect task.service to start when I run $ systemctl suspend, however task.service is not started.

I'm running debian, with systemd version 208, systemd --user configured more or less as described on the ArchWiki.

I wonder whether my scenario could be implemented with systemd at all, or are --system and --user completely isolated by design so that --user unit may not be a dependency of a --system unit.

In case it is possible, what might be the problem in my case?

HalosGhost
  • 4,790

5 Answers5

27

From systemd/User - Archwiki

systemd --user runs as a separate process from the systemd --system process. User units can not reference or depend on system units.

There is a feature request in the systemd GitHub repository tracking this question.

sshow
  • 373
7

You can also create a "proxy" for all your sleep/suspend targets between service and user instances.

Create this file on /etc/systemd/system/suspend@.service:

[Unit]
Description=Call user's suspend target after system suspend
After=suspend.target

[Service] Type=oneshot ExecStart=/usr/bin/systemctl --user --machine=%i@ start --wait suspend.target

[Install] WantedBy=suspend.target

And enable it by running sudo systemctl daemon-reload && sudo systemctl enable suspend@youruser.

Now create your user suspend.target at ~/.config/systemd/user/suspend.target:

[Unit]
Description=User level suspend target
StopWhenUnneeded=yes
Wants=my-etc-service.service

Then add your services on the Wants list and make sure to run systemctl --user daemon-reload

Kepi
  • 327
  • Thanks ! I made it work with graphical.target flawlessly. Just don't forget to also enable your user service with systemctl --user enable my-etc-service.service of course ;) – Dynamite May 20 '23 at 13:02
5

systemd user session services run in a completely separate instance of systemd, and doesn’t have any way to depend on system services directly.

There are other ways to accomplish what you want though. The cleanest would probably be to make whatever you want to run when the system is going to sleep hook into logind’s inhibitors and then run it as a background daemon.

A more general solution would be to have a daemon hooks into the logind inhibitors, (see systemd-lock-handler and xss-lock,) and then when the system is going to sleep it will activate a user session target that you can order your services under.

remmy
  • 5,055
  • 1
  • 24
  • 30
4

Adding to the response from @kyrias, here's a way to create your own user level sleep.target:

~/.local/share/systemd/user/sleep.target

[Unit]
Description=User level sleep target
StopWhenUnneeded=yes

~/.local/bin/watch_sleep

#!/bin/bash

dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Manager',member=PrepareForSleep" | while read x; do
    case "$x" in
        *"boolean false"*) systemctl --user --no-block stop sleep.target;;
        *"boolean true"*) systemctl --user --no-block start sleep.target;;
    esac
done

~/.local/share/systemd/user/watch_sleep.service

[Unit]
Description=watch for sleep signal to start sleep.target

[Service]
ExecStart=%h/.local/bin/watch_sleep
Restart=on-failure

[Install]
WantedBy=default.target

See my blog post https://medium.com/@aiguofer/systemd-sleep-target-for-user-level-10eb003b3bfd

aiguofer
  • 191
0

You can do the following to achieve sleep.target (and a complementary awake.target) in userspace:

Create the following service template in /etc/systemd/system/sleep@.service

[Unit]
Description=%I sleep hook
PartOf=sleep.target

[Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/systemctl --user --machine=%i@ start sleep.target ExecStop=/usr/bin/systemctl --user --machine=%i@ start awake.target

[Install] WantedBy=sleep.target

Create an instance of it for your user (don't start it):

sudo systemctl enable sleep@$(whoami)

Now for the equivalent sleep.target for users:

[Unit]
Description=User-level Sleep Target
Conflicts=awake.target

And awake.target:

[Unit]
Description=User-level Awake Target
Conflicts=sleep.target

[Install] WantedBy=default.target

Enable with systemctl --user enable awake.target so that it starts at login

When either of these targets are reached, they stop the other target, thanks to the Conflicts directive, which makes them mutually exclusive targets.

For my use-case, I actually found the awake.target to be more useful than the sleep.target because I could make some user services use the PartOf directive to start and stop with it.

The only use-case I could think of that would benefit from the sleep target is if someone was trying to make use systemd-inhibit to do some last minute cleanup before the system goes to sleep. This would also mean delaying the actual sleep target until after the work is done.

smac89
  • 1,443