Làm cách nào để chạy dịch vụ người dùng systemd để kích hoạt khi ngủ (hay còn gọi là tạm dừng, ngủ đông)?


17

Dựa trên nhiều nguồn khác nhau, tôi đã cùng nhau tìm hiểu ~/.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

Tôi đã kích hoạt nó bằng cách sử dụng systemctl --user enable screenlock.service. Nhưng sau khi khởi động lại, đăng nhập, tạm dừng và tiếp tục (đã kiểm tra cả bằng systemctl suspendvà đóng nắp) màn hình không bị khóa và không có gì trong đójournalctl --user-unit screenlock.service . Tôi đang làm gì sai?

Chạy DISPLAY=:0 /usr/bin/xautolock -locknowkhóa màn hình như mong đợi.

$ 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

Nếu tôi chạy systemctl --user start screenlock.servicecác khóa màn hình ngay lập tức và tôi nhận được một thông điệp tường trình journalctl --user-unit screenlock.service, thì ExecStartrõ ràng là chính xác.

.xinitrcPhần có liên quan :

xautolock -locker slock &

Tạo một dịch vụ hệ thống với cùng một tệp hoạt động (nghĩa slocklà hoạt động khi tiếp tục lại):

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

Nhưng tôi không muốn thêm một tệp cụ thể của người dùng bên ngoài $HOMEvì một số lý do:

  • Dịch vụ người dùng nên được tách biệt rõ ràng với dịch vụ hệ thống
  • Dịch vụ người dùng nên được kiểm soát mà không cần sử dụng đặc quyền superuser
  • Cấu hình nên được kiểm soát phiên bản dễ dàng

Tôi đang sử dụng tuyệt vời như trình quản lý cửa sổ và SLiM là trình quản lý đăng nhập . Tôi không sử dụng môi trường máy tính để bàn đầy đủ theo định nghĩa của Arch và Linux / awesome là môi trường máy tính để bàn như được định nghĩa bởi Wikipedia . Dường như không có bất cứ thứ gì giống như "trình quản lý máy tính để bàn" cho Linux.
l0b0

Dịch vụ người dùng được chạy bên ngoài phiên, vì vậy dữ liệu phiên của bạn không có sẵn cho họ; bạn có thể tốt hơn khi sử dụng tệp dịch vụ tiêu chuẩn cho việc này: ít nhất là để kiểm tra bằng mọi cách ...
jasonwryan

@jasonwryan Chắc chắn tôi sẽ thấy một số thông báo lỗi trong tạp chí nếu dịch vụ đã được kích hoạt?
l0b0

Tôi không biết: systemd-uservẫn còn rất dễ vỡ; làm cho nó hoạt động như một phần của phiên thông qua cách tiếp cận tôi đã vạch ra sẽ giúp thu hẹp vấn đề; đó là tất cả những gì tôi có thể đề xuất.
jasonwryan

Mặc dù nó không phải là một giải pháp hoàn hảo (nó vẫn cần phải được quản lý bằng quyền root), bạn chỉ cần sử dụng /etc/systemd/system/hoặc $HOME/.local/systemd/systemđể tránh đưa bất cứ thứ gì vào /usrbằng tay. Như @jasonwryan đã đề cập, các phiên của người dùng vẫn chưa được coi là chất lượng sản xuất; nhưng họ đang tiến gần hơn.
HalosGhost

Câu trả lời:


20

sleep.targetlà cụ thể cho các dịch vụ hệ thống. Lý do là, sleep.targetkhông phải là một mục tiêu ma thuật tự động được kích hoạt khi đi ngủ. Đây chỉ là một mục tiêu thông thường khiến hệ thống ngủ yên - vì vậy, các trường hợp 'người dùng' tất nhiên sẽ không có tương đương. (Và thật không may, các phiên bản 'người dùng' hiện không có cách nào để phụ thuộc vào các dịch vụ toàn hệ thống.)

.

Vì vậy, có hai cách tốt để làm điều này (tôi đề nghị cách thứ 2):

Phương pháp 1

Tạo một dịch vụ hệ thống (hoặc hook systemd-ngủ (8)) làm cho systemd-logind phát tín hiệu "khóa tất cả các phiên" khi hệ thống chuyển sang chế độ ngủ:

ExecStart=/usr/bin/loginctl lock-sessions

Sau đó, trong phiên X11 của bạn (tức là từ ~ / .xinitrc), hãy chạy thứ gì đó phản ứng với tín hiệu:

systemd-lock-handler slock &
xss-lock - slore ngủ-ngủ &

(Gnome, Cinnamon, KDE, Enlightenment đã hỗ trợ điều này một cách tự nhiên.)

Phương pháp 2

Trong phiên X11 của bạn, hãy chạy thứ gì đó trực tiếp theo dõi hệ thống sẽ chuyển sang chế độ ngủ, ví dụ: bằng cách kết nối với các "chất ức chế" của systemd-logind.

Khóa xss đã nói ở trên thực sự làm chính xác điều đó, ngay cả khi không có tín hiệu "khóa tất cả" rõ ràng, do đó, nó đủ để chạy nó:

khóa xss-lock &

Nó sẽ chạy slockngay khi thấy systemd-logind chuẩn bị treo máy tính.


Bạn có thể vui lòng giải thích một chút về Khai sáng và hỗ trợ bản địa của người khác không? Không rõ chính xác những gì họ hỗ trợ tự nhiên từ câu trả lời.
Pavel imerda

@ PavelŠimerda: Tín hiệu "phiên khóa" từ systemd-logind (... toàn bộ phần nói về nó ...) Ngoài ra, tôi đã sai, e19 không thực sự hỗ trợ nó.
grawity

Cảm ơn thông tin về E19. Câu trả lời vẫn thiếu lời giải thích về chính xác những gì Gnome và những người khác hỗ trợ. Nghe tín hiệu D-Bus của systemd (thậm chí không được ghi ở đó) là một điều, hành động nào được thực hiện trong phản ứng và hành động nào và làm thế nào người dùng có thể định cấu hình để thực hiện là một hành động khác. Ngoài ra không có thông tin về những gì systemd-lock-handler làm và nguồn gốc của nó.
Pavel imerda

xss-locklà trong AUR, vì vậy không cần phải xây dựng thủ công.
l0b0

Điều này hoạt động rất đẹp trong thử nghiệm Debian. Cảm ơn vì đăng. Điều khá đáng thất vọng là systemd không cho phép dịch vụ người dùng phụ thuộc vào dịch vụ hệ thống ...
cgogolin

-1

systemd-lock-handlerlà một tập lệnh Python có thể thực hiện điều này: 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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.