如何运行systemd用户服务以在睡眠(又称为挂起,休眠)时触发?


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由于某些原因,我不想在外部添加用户特定的文件:

  • 用户服务应与系统服务明确分开
  • 应该在不使用超级用户特权的情况下控制用户服务
  • 配置应易于版本控制

我使用awesome作为窗口管理器,并使用SLiM作为登录管理器。我没有使用Arch定义的完整桌面环境,而Linux / awesome 没有使用Wikipedia定义桌面环境。似乎没有像Linux那样的“桌面管理器”。
2014年

用户服务在会话之外运行,因此您的会话数据不可用。您可能最好使用标准服务文件:至少进行测试……
jasonwryan 2014年

@jasonwryan如果服务已被触发,我当然会在日志中看到某种错误消息吗?
l0b0

我不知道:systemd-user还是酥脆的。通过我概述的方法使其成为会议的一部分,将有助于缩小问题的范围;这就是我所建议的。
jasonwryan

尽管这不是一个完美的解决方案(仍然需要使用root权限进行管理),但是您可以使用/etc/systemd/system/$HOME/.local/systemd/system避免/usr手动放置任何内容。正如@jasonwryan所提到的,用户会话仍然不被认为是生产质量的;但是他们越来越近了。
HalosGhost 2014年

Answers:


20

sleep.target特定于系统服务。原因是,sleep.target不是一个神奇的目标,它会在睡眠时自动激活。这只是使系统进入睡眠状态的常规目标–因此,“用户”实例当然不会具有等效对象。(不幸的是,“用户”实例当前无法依赖系统范围的服务。)

(那就是整个“硬编码$ DISPLAY”业务。每次在基于多用户/多座位Unix的操作系统中硬编码会话参数时,root会杀死一只小猫。)

因此,有两种方法可以做到这一点(我建议第二种方法):

方法1

创建一个系统服务(或systemd-sleep(8)挂钩),该服务使systemd-logind在系统进入睡眠状态时广播“锁定所有会话”信号:

ExecStart=/usr/bin/loginctl lock-sessions

然后,在您的X11会话中(即,从〜/ .xinitrc开始),运行一些对信号做出反应的东西:

系统锁处理程序锁
xss- lock-忽略睡眠

(GNOME,Cinnamon,KDE,Enlightenment已经本地支持此功能。)

方法2

在您的X11会话中,运行可以直接监视系统进入睡眠状态的操作,例如,通过挂接到systemd-logind的“抑制剂”来进行监视。

即使没有显式的“全部锁定”信号,上述xss-lock实际上也确实可以做到这一点,因此足以使其运行:

XSS锁锁

slock一旦看到systemd-logind准备挂起计算机,它将立即运行。


您能否详细说明一下启蒙运动和其他人的本地支持?目前尚不清楚他们从答案中究竟得到了什么支持。
2014年

@PavelŠimerda:来自systemd-logind的“锁定会话”信号(...整个部分都关于它...)另外,我错了,e19实际上并不支持它。
user1686 2014年

感谢您提供有关E19的信息。答案仍然缺少对Gnome和其他人到底支持什么的解释。聆听systemd的D-Bus信号(即使那里没有写)是一回事,响应中将执行哪些操作,用户将如何配置要执行的操作是另一回事。也没有关于systemd-lock-handler做什么以及它来自何处的信息。
PavelŠimerda2014年

xss-lock位于AUR中,因此无需手动进行构建。
l0b0

在Debian测试中,这可以很好地工作。感谢您的发布。令人失望的是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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.