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.