วิธีการเรียกใช้บริการผู้ใช้ systemd เพื่อทริกเกอร์ในโหมดสลีป (aka. suspend, hibernate)


17

จากแหล่งข้อมูลต่าง ๆ ที่ฉันได้เรียนด้วยกัน~/.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

systemctl --user enable screenlock.serviceผมได้เปิดใช้งานได้โดยใช้ แต่หลังจากรีบูตเครื่องเข้าสู่ระบบระงับและดำเนินการต่อ (ทดสอบทั้งกับsystemctl suspendและโดยการปิดฝา) หน้าจอจะไม่ถูกล็อคและไม่มีอะไรjournalctl --user-unit screenlock.serviceมา ผมทำอะไรผิดหรือเปล่า?

กำลังDISPLAY=:0 /usr/bin/xautolock -locknowล็อคหน้าจอตามที่คาดไว้

$ 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

หากฉันรันsystemctl --user start screenlock.serviceการล็อกหน้าจอทันทีและฉันได้รับข้อความบันทึกjournalctl --user-unit screenlock.serviceดังนั้นExecStartชัดเจนว่าถูกต้อง

.xinitrcส่วนที่เกี่ยวข้อง :

xautolock -locker slock &

การสร้างบริการระบบโดยใช้ไฟล์เดียวกันทำงาน (นั่นslockคือใช้งานได้เมื่อทำงานต่อ):

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

แต่ฉันไม่ต้องการเพิ่มไฟล์เฉพาะผู้ใช้ภายนอก$HOMEด้วยเหตุผลหลายประการ:

  • บริการผู้ใช้ควรแยกออกจากบริการระบบอย่างชัดเจน
  • บริการผู้ใช้ควรได้รับการควบคุมโดยไม่ต้องใช้สิทธิ์ superuser
  • การกำหนดค่าควรเป็นเวอร์ชั่นที่ควบคุมได้ง่าย

ฉันใช้เจ๋ง ๆ ในฐานะผู้จัดการหน้าต่างและ SLiM เป็นผู้จัดการการเข้าสู่ระบบ ฉันไม่ได้ใช้เต็มรูปแบบสภาพแวดล้อมเดสก์ทอปตามที่กำหนดโดย Archและ Linux / น่ากลัวในขณะที่สภาพแวดล้อมเดสก์ทอปตามที่กำหนดโดยวิกิพีเดีย ดูเหมือนจะไม่มีอะไรเหมือน "ผู้จัดการเดสก์ท็อป" สำหรับ Linux
l0b0

บริการผู้ใช้ทำงานนอกเซสชันดังนั้นข้อมูลเซสชันของคุณจะไม่สามารถใช้ได้ คุณอาจจะดีกว่าด้วยการใช้ไฟล์บริการมาตรฐานสำหรับสิ่งนี้: อย่างน้อยก็เพื่อทดสอบต่อไป ...
jasonwryan

@ jasonwryan แน่นอนฉันจะเห็นข้อความแสดงข้อผิดพลาดบางอย่างในวารสารหากมีการเรียกใช้บริการหรือไม่
l0b0

ฉันไม่รู้: systemd-userยังเป็นขุยมาก ทำให้การทำงานเป็นส่วนหนึ่งของเซสชั่นผ่านวิธีการที่ฉันระบุไว้จะช่วยให้ปัญหาแคบลง นั่นคือทั้งหมดที่ฉันสามารถแนะนำ
jasonwryan

แม้ว่ามันจะไม่ใช่โซลูชันที่สมบูรณ์แบบ (แต่ก็ยังจำเป็นต้องได้รับการจัดการด้วยการอนุญาตรูท) แต่คุณสามารถใช้/etc/systemd/system/หรือ$HOME/.local/systemd/systemเพื่อหลีกเลี่ยงการใส่อะไรลงไป/usrด้วยตนเอง ตามที่ @ jasonwryan พูดถึงเซสชันของผู้ใช้ยังไม่ถือว่าเป็นคุณภาพการผลิต แต่พวกเขาใกล้ชิดกันมากขึ้น
HalosGhost

คำตอบ:


20

sleep.targetเป็นบริการเฉพาะของระบบ เหตุผลก็sleep.targetคือไม่ใช่เป้าหมายเวทมนต์ที่ถูกเปิดใช้งานโดยอัตโนมัติเมื่อเข้าสู่โหมดสลีป เป็นเพียงเป้าหมายปกติที่ทำให้ระบบเข้าสู่โหมดสลีปดังนั้นแน่นอน 'ผู้ใช้' อินสแตนซ์จะไม่เทียบเท่า (และน่าเสียดายที่อินสแตนซ์ 'ผู้ใช้' ในปัจจุบันไม่มีวิธีที่จะขึ้นอยู่กับบริการของทั้งระบบ)

(นั่นคือและมีธุรกิจ "hardcoding $ DISPLAY" ทั้งหมดทุกครั้งที่คุณ hardcode พารามิเตอร์เซสชั่นในระบบปฏิบัติการที่ใช้ Unix ที่มีผู้ใช้หลายคน / หลายที่นั่งรูตจะฆ่าลูกแมว)

ดังนั้นจึงมีสองวิธีที่ดีในการทำเช่นนี้ (ฉันแนะนำวิธีที่สอง):

วิธีที่ 1

สร้างบริการระบบ (หรือ systemd-sleep (8) hook) ที่ทำให้ systemd-logind ออกอากาศสัญญาณ "ล็อคเซสชันทั้งหมด" เมื่อระบบเข้าสู่โหมดสลีป:

ExecStart=/usr/bin/loginctl lock-sessions

จากนั้นภายในเซสชัน X11 ของคุณ (เช่นจาก ~ / .xinitrc) ให้เรียกใช้สิ่งที่ตอบสนองต่อสัญญาณ:

ล็อค &
 ตัวจัดการ systemd-lock-handler
xss-lock signore-sleep &

(GNOME, Cinnamon, KDE, การรู้แจ้งสนับสนุนสิ่งนี้อยู่แล้ว)

วิธีที่ 2

ภายในเซสชัน X11 ของคุณทำงานบางอย่างที่โดยตรงนาฬิกาสำหรับระบบจะนอนหลับเช่นโดย hooking เข้า systemd-logind ของ "ยับยั้ง"

xss-lock ดังกล่าวจริง ๆ แล้วทำสิ่งนั้นแม้ว่าจะไม่มีสัญญาณ "ล็อคทั้งหมด" อย่างชัดเจนดังนั้นจึงเพียงพอที่จะให้มันทำงาน:

XSS ล็อค &

มันจะทำงานslockทันทีที่เห็น systemd-logind เตรียมที่จะระงับคอมพิวเตอร์


คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับการตรัสรู้และการสนับสนุนของคนอื่นได้ไหม? ยังไม่ชัดเจนว่าพวกเขาสนับสนุนอะไรจากคำตอบ
Pavel Šimerda

@ PavelŠimerda: สัญญาณ "ล็อคเซสชั่น" จาก systemd-logind (... ทั้งส่วนเป็นเรื่องเกี่ยวกับมัน ... )นอกจากนี้ฉันผิด E19 ไม่สนับสนุนจริง ๆ
user1686

ขอบคุณสำหรับข้อมูลเกี่ยวกับ E19 คำตอบยังขาดคำอธิบายว่า Gnome และผู้อื่นสนับสนุนอะไรอย่างแน่นอน การฟังสัญญาณ D-Bus ของ systemd (แม้จะไม่ได้เขียนไว้ที่นั่น) เป็นสิ่งหนึ่งสิ่งที่กระทำในปฏิกิริยาและการกระทำใดและผู้ใช้สามารถกำหนดค่าให้ทำได้อย่างไร ยังไม่มีข้อมูลว่า systemd-lock-handler ทำอะไรและมาจากไหน
Pavel Šimerda

xss-lockอยู่ใน AUR ดังนั้นจึงไม่จำเป็นต้องสร้างด้วยตนเอง
l0b0

มันทำงานได้อย่างสวยงามภายใต้การทดสอบของเดเบียน ขอบคุณสำหรับการโพสต์ มันค่อนข้างน่าผิดหวังที่ systemd ไม่อนุญาตให้ผู้ใช้บริการขึ้นอยู่กับบริการของระบบ ...
cgogolin

-1

systemd-lock-handlerเป็นสคริปต์ Python ซึ่งสามารถบรรลุนี้: 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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.