Jak uruchomić usystematyzowaną usługę użytkownika w celu wyzwolenia w trybie uśpienia (aka. Zawieszenia, hibernacji)?


17

Na podstawie różnych źródeł zebrałem razem ~/.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

Włączyłem to za pomocą systemctl --user enable screenlock.service. Ale po ponownym uruchomieniu komputera, zalogowaniu się, zawieszeniu i wznowieniu (testowane zarówno z systemctl suspendzamknięciem pokrywy, jak i przez nią) ekran nie jest zablokowany i nic w nim nie majournalctl --user-unit screenlock.service . Co ja robię źle?

Uruchomienie DISPLAY=:0 /usr/bin/xautolock -locknowblokuje ekran zgodnie z oczekiwaniami.

$ 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

Jeśli uruchomię systemctl --user start screenlock.serviceekran, blokuje się natychmiast i pojawia się komunikat logowania journalctl --user-unit screenlock.service, więc ExecStartjest to oczywiście poprawne.

Odpowiednia .xinitrcsekcja :

xautolock -locker slock &

Utworzenie usługi systemowej z tymi samymi plikami działa (to znaczy slockjest aktywne podczas wznawiania):

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

Ale nie chcę dodawać pliku specyficznego $HOMEdla użytkownika na zewnątrz z kilku powodów:

  • Usługi użytkownika powinny być wyraźnie oddzielone od usług systemowych
  • Usługi użytkowników powinny być kontrolowane bez korzystania z uprawnień administratora
  • Konfiguracja powinna być łatwa do kontrolowania wersji

Używam niesamowite jako menedżera okien , a SLiM jako menedżera logowania . Nie używam pełnego środowiska graficznego zdefiniowanego przez Arch , a Linux / awesome jako środowiska graficznego zdefiniowanego przez Wikipedię . Wydaje się, że nie ma czegoś takiego jak „menedżer pulpitu” dla Linuksa.
l0b0

Usługi użytkownika są uruchamiane poza sesją, więc dane sesji nie są dla nich dostępne; lepiej byłoby użyć do tego standardowego pliku usługi: przynajmniej przetestować mimo wszystko ...
jasonwryan

@ jasonwryan Na pewno zobaczyłbym jakiś komunikat o błędzie w dzienniku, gdyby usługa została uruchomiona?
l0b0

Nie wiem: systemd-userwciąż jest bardzo łuszcząca; sprawienie, by działało w ramach sesji za pomocą podejścia, które przedstawiłem, pomogłoby zawęzić problem; to wszystko, co mogę zasugerować.
jasonwryan

Chociaż nie jest to idealne rozwiązanie (nadal musiałoby być zarządzane z uprawnieniami administratora), możesz po prostu użyć /etc/systemd/system/lub $HOME/.local/systemd/systemuniknąć /usrręcznego wprowadzania czegokolwiek . Jak wspomniano w @jasonwryan, sesje użytkowników nadal nie są uważane za jakość produkcyjną; ale zbliżają się.
HalosGhost

Odpowiedzi:


20

sleep.targetjest specyficzny dla usług systemowych. Powodem jest to, że sleep.targetnie jest magicznym celem, który aktywuje się automatycznie po zaśnięciu. Jest to zwykły cel, który uśpia system - więc wystąpienia użytkownika nie będą miały odpowiednika. (I niestety obecnie instancje „użytkownika” nie mają możliwości polegania na usługach ogólnosystemowych).

(I jest cała ta sprawa „hardcoding $ DISPLAY”. Za każdym razem, gdy kodujesz parametry sesji w systemie operacyjnym opartym na uniksowym systemie z wieloma użytkownikami / wieloma użytkownikami, root zabija kotka.)

Są dwa dobre sposoby na zrobienie tego (sugeruję drugi):

Metoda 1

Utwórz usługę systemową (lub hak systemd-sleep (8)), który powoduje, że systemd-logind rozgłasza sygnał „zablokuj wszystkie sesje”, gdy system przejdzie w tryb uśpienia:

ExecStart=/usr/bin/loginctl lock-sessions

Następnie w ramach sesji X11 (tj. Z ~ / .xinitrc) uruchom coś, co reaguje na sygnał:

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

(GNOME, Cynamon, KDE, Oświecenie już to obsługują natywnie).

Metoda 2

W trakcie sesji X11 uruchom coś, co bezpośrednio obserwuje, czy system przechodzi w tryb uśpienia, np. Podłączając się do „inhibitorów” systemd-logind.

Wspomniana blokada xss faktycznie robi dokładnie to, nawet bez wyraźnego sygnału „zablokuj wszystko”, więc wystarczy, aby działała:

blokada xss-lock &

Uruchomi się, slockgdy tylko zobaczy, że systemd-logind przygotowuje się do zawieszenia komputera.


Czy mógłbyś opisać trochę Oświecenia i natywnego wsparcia innych? Nie jest jasne, co dokładnie wspierają natywnie w odpowiedzi.
Pavel Šimerda

@ PavelŠimerda: Sygnał „lock session” z systemd-logind (... cała sekcja jest na ten temat ...) Również się myliłem, e19 tak naprawdę go nie obsługuje.
user1686,

Dzięki za informację o E19. W odpowiedzi wciąż brakuje wyjaśnienia, co dokładnie wspierają Gnome i inni. Odsłuchanie sygnału systemd D-Bus (nawet tego tam nie zapisano) to jedno, jakie akcje są wykonywane w reakcji i jakie akcje i jak użytkownik może skonfigurować, aby były wykonane. Nie ma również informacji o tym, co robi programd-lock-handler i skąd pochodzi.
Pavel Šimerda

xss-lockznajduje się w AUR, więc nie trzeba go budować ręcznie.
l0b0

Działa to pięknie podczas testowania Debiana. Dzięki za wysłanie. Bardzo rozczarowujące jest to, że systemd nie pozwala usługom użytkowników zależeć od usług systemowych ...
cgogolin

-1

systemd-lock-handlerto skrypt w języku Python, który może to osiągnąć: 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()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.