Comment exécuter le service utilisateur systemd pour qu'il se déclenche en veille (aka. Suspend, hibernate)?

17

Sur la base de diverses sources, j'ai bricolé ensemble ~/.config/systemd/user/screenlock.service:

[Unit]
Description=Lock X session
Before=sleep.target

[Service]
Environment=DISPLAY=:0
ExecStart=/usr/bin/xautolock -locknow

[Install]
WantedBy=sleep.target

Je l'ai activé en utilisant systemctl --user enable screenlock.service. Mais après le redémarrage, la connexion, la suspension et la reprise (testé à la fois avec systemctl suspendet en fermant le couvercle), l'écran n'est pas verrouillé et il n'y a rienjournalctl --user-unit screenlock.service . Qu'est-ce que je fais mal?

L'exécution DISPLAY=:0 /usr/bin/xautolock -locknowverrouille l'écran comme prévu.

$ systemctl --version
systemd 215
+PAM -AUDIT -SELINUX -IMA -SYSVINIT +LIBCRYPTSETUP +GCRYPT +ACL +XZ +SECCOMP -APPARMOR
$ awesome --version
awesome v3.5.5 (Kansas City Shuffle)
 • Build: Apr 11 2014 09:36:33 for x86_64 by gcc version 4.8.2 (nobody@)
 • Compiled against Lua 5.2.3 (running with Lua 5.2)
 • D-Bus support: ✔
$ slim -v
slim version 1.3.6

Si j'exécute systemctl --user start screenlock.serviceles verrous d'écran immédiatement et que je reçois un message de connexion journalctl --user-unit screenlock.service, c'est donc ExecStartclairement correct.

.xinitrcSection pertinente :

xautolock -locker slock &

La création d'un service système avec le même fichier fonctionne (c'est-à-dire slockest active lors de la reprise):

# ln -s "${HOME}/.config/systemd/user/screenlock.service" /usr/lib/systemd/system/screenlock.service
# systemctl enable screenlock.service
$ systemctl suspend

Mais je ne veux pas ajouter un fichier spécifique à l'utilisateur à l'extérieur $HOMEpour plusieurs raisons:

  • Les services utilisateurs doivent être clairement séparés des services système
  • Les services utilisateur doivent être contrôlés sans utiliser les privilèges de superutilisateur
  • La configuration doit être facilement contrôlée par la version
l0b0
la source
J'utilise awesome comme gestionnaire de fenêtres et SLiM comme gestionnaire de connexion . Je n'utilise pas un environnement de bureau complet tel que défini par Arch , et Linux / awesome comme environnement de bureau tel que défini par Wikipedia . Il ne semble pas exister de "gestionnaire de bureau" pour Linux.
l0b0
Les services utilisateur sont exécutés en dehors de la session, vos données de session ne sont donc pas disponibles pour eux; vous feriez mieux d'utiliser un fichier de service standard pour cela: au moins pour tester de toute façon ...
jasonwryan
@jasonwryan Je verrais sûrement une sorte de message d'erreur dans le journal si le service avait été déclenché?
l0b0
Je ne sais pas: systemd-userest encore très feuilletée; le faire fonctionner dans le cadre de la session via l'approche que j'ai décrite aiderait à affiner le problème; c'est tout ce que je peux suggérer.
jasonwryan
Bien que ce ne soit pas une solution parfaite (il faudrait tout de même la gérer avec les autorisations root), vous pouvez simplement utiliser /etc/systemd/system/ou $HOME/.local/systemd/systeméviter de mettre quoi que ce soit /usrmanuellement. Comme l'a mentionné @jasonwryan, les sessions utilisateur ne sont toujours pas considérées comme une qualité de production; mais ils se rapprochent.
HalosGhost

Réponses:

20

sleep.targetest spécifique aux services système. La raison en est que ce sleep.targetn'est pas une cible magique qui s'active automatiquement en s'endormant. C'est juste une cible régulière qui met le système en veille - donc les instances «utilisateur» n'auront bien sûr pas d'équivalent. (Et malheureusement, les instances «utilisateur» n'ont actuellement aucun moyen de dépendre des services à l'échelle du système.)

(Cela, et il y a toute l'activité "hardcoding $ DISPLAY". Chaque fois que vous codez en dur des paramètres de session dans un système d'exploitation basé sur Unix fortement multi-utilisateurs / multi-postes, root tue un chaton.)

Il y a donc deux bonnes façons de le faire (je suggère le 2ème):

Méthode 1

Créez un service système (ou un hook systemd-sleep (8)) qui fait que systemd-logind diffuse le signal "verrouiller toutes les sessions" lorsque le système se met en veille:

ExecStart=/usr/bin/loginctl lock-sessions

Ensuite, dans votre session X11 (c'est-à-dire à partir de ~ / .xinitrc), exécutez quelque chose qui réagit au signal:

systemd-lock-handler slock &
xss-lock --ignore-sleep slock &

(GNOME, Cinnamon, KDE, Enlightenment le supportent déjà nativement.)

Méthode 2

Dans votre session X11, exécutez quelque chose qui surveille directement le système qui va se mettre en veille, par exemple en vous connectant aux "inhibiteurs" de systemd-logind.

Le xss-lock susmentionné fait exactement cela, même sans le signal explicite de «verrouiller tout», il suffit donc de le faire fonctionner:

xss-lock slock &

Il s'exécutera slockdès qu'il verra systemd-logind se préparer à suspendre l'ordinateur.

user1686
la source
Pourriez-vous développer un peu le support natif des Lumières et des autres? On ne sait pas exactement ce qu'ils soutiennent nativement dans la réponse.
Pavel Šimerda
@ PavelŠimerda: Le signal de "verrouillage de session" de systemd-logind (... toute la section en parle ...) De plus, j'avais tort, e19 ne le supporte pas réellement.
user1686
Merci pour l'info sur E19. La réponse manque encore d'explication sur ce que Gnome et d'autres soutiennent exactement. Écouter le signal D-Bus de systemd (même si ce n'est pas écrit ici) est une chose, quelles actions sont effectuées en réaction et quelles actions et comment l'utilisateur peut-il configurer pour être fait en est une autre. De plus, il n'y a aucune information sur ce que fait systemd-lock-handler et d'où il vient.
Pavel Šimerda
xss-lockest dans l'AUR, il n'est donc pas nécessaire de le construire manuellement.
l0b0
Cela fonctionne parfaitement sous les tests Debian. Merci d'avoir posté. Il est assez décevant que systemd ne permette pas aux services utilisateurs de dépendre des services systèmes ...
cgogolin
-1

systemd-lock-handlerest un script Python qui peut accomplir cela: https://github.com/grawity/code/blob/master/desktop/systemd-lock-handler .

#!/usr/bin/env python
# systemd-lock-handler -- proxy between systemd-logind's "Lock" signal and your
#   favourite screen lock command

from __future__ import print_function
import os, sys, dbus, dbus.mainloop.glib
from gi.repository import GLib

def trace(*args):
    global arg0
    print("%s:" % arg0, *args)

def setup_signal(signal_handler):
    global session_id
    bus = dbus.SystemBus()
    manager = bus.get_object("org.freedesktop.login1", "/org/freedesktop/login1")
    # yecch
    manager = dbus.Interface(manager, "org.freedesktop.login1.Manager")
    session_path = manager.GetSession(session_id)
    session = bus.get_object("org.freedesktop.login1", session_path)
    session.connect_to_signal("Lock", signal_handler)

def handler_dbus_fdo():
    trace("locking session using DBus")
    bus = dbus.SessionBus()
    screensaver = bus.get_object("org.freedesktop.ScreenSaver", "/ScreenSaver")
    screensaver.Lock()

def handler_external():
    global lock_command
    trace("locking session using %r" % lock_command[0])
    os.spawnvp(os.P_NOWAIT, lock_command[0], lock_command)

def main():
    global arg0, lock_command, session_id
    arg0 = sys.argv[0].split("/")[-1]
    lock_command = sys.argv[1:] or ["--dbus"]
    try:
        session_id = os.environ["XDG_SESSION_ID"]
    except KeyError:
        print("error: $XDG_SESSION_ID not set; are you using pam_systemd?",
            file=sys.stderr)
        sys.exit(1)
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
    if lock_command == ["--dbus"]:
        trace("using freedesktop.org DBus API")
        setup_signal(handler_dbus_fdo)
    else:
        trace("using external command %r" % lock_command[0])
        setup_signal(handler_external)
    trace("waiting for lock signals on session %s" % session_id)
    try:
        loop = GLib.MainLoop()
        loop.run()
    except KeyboardInterrupt:
        sys.exit(0)

main()
yaerotugh
la source