编写依赖于 Xorg 的服务

编写依赖于 Xorg 的服务

我正在尝试为 编写一个用户级服务redshift,它需要等到 Xorg 启动并运行。我当前的服务文件如下所示:

[Unit]
Description=Redshift
After=graphical.target

[Service]
Environment=DISPLAY=:0
ExecStart=/bin/redshift -l 28:-13 -t 5300:3300 -b 0.80:0.91 -m randr
Restart=always

[Install]
WantedBy=default.target

但是,它似乎试图在 Xorg 启动之前启动,之后我必须手动启动该服务。我想我使用了错误的After=目标。有什么提示吗?

答案1

我一直在研究这个问题,grawity 的答案似乎已经过时了。现在,您可以使用 systemd 设置用户服务,这些服务作为用户会话的一部分运行。他们可以设置 DISPLAY 和 XAUTHORITY(目前在 Arch、Debian Stretch+ 和 Ubuntu 中)。

这比以前使用桌面自动启动文件的建议更有意义,因为您可以像系统级应用程序(重新启动等)一样进行进程管理。

目前最好的文档是 Arch wiki;Systemd/用户

TLDR 版本;

  1. 在中创建所需的 *.service 文件~/.config/systemd/user/
  2. 运行systemctl --user enable [service](不包括.service后缀)
  3. 可选择立即systemctl --user start [service]运行
  4. 用于systemctl --user status [service]检查其运行情况

一些其他有用的命令。

  • systemctl --user list-unit-files- 查看所有用户单位
  • systemctl --user daemon-reload- 如果你编辑 .service 文件

- 之后...

我升级并将大多数会话守护进程转换为 systemd .service 文件。因此我可以添加一些额外的注释。

没有默认钩子可以在登录时运行服务,因此您必须自己触发它。我从我的~/.xsession文件中执行此操作。

systemctl --user import-environment PATH DBUS_SESSION_BUS_ADDRESS
systemctl --no-block --user start xsession.target

第一行将一些环境变量导入到 systemd 用户会话中,第二行启动目标。我的xsession.target文件;

[Unit]
Description=Xsession running
BindsTo=graphical-session.target

以我的xbindkeys.service为例。

[Unit]
Description=xbindkeys
PartOf=graphical-session.target

[Service]
ExecStart=/usr/bin/xbindkeys -n -f ${HOME}/projects/dotfiles/.xbindkeysrc
Restart=always

[Install]
WantedBy=xsession.target

答案2

通常的提示是“不要”。 redshift不是系统范围的服务——它有一个单独的实例每次会议,并且它需要知道如何连接到该特定会话的 Xorg。

(Xorg 也不是系统服务——只有显示管理器是的,它还为每个会话启动一个单独的 Xorg。//graphical.target会告诉您显示管理器何时准备就绪,但它并未说明 DM 何时实际启动第一个或所有显示器。)

仅在启动时启动它DISPLAY=:0是不够的,因为无法保证在任何给定时间都只有一个显示器,也无法保证它总是存在:0(例如,如果 Xorg 崩溃并留下一个过时的锁文件,则下一个会运行,:1因为它会认为:0仍然被占用);您还需要设置文件的路径,XAUTHORITY因为 X11 需要身份验证;并确保redshift在您注销并再次登录时重新启动。

那么如何开始呢?桌面环境几乎总是有几种启动自己的方法会议服务。查看旧帖子其中已经描述了两个常见的因素:~/.xprofile剧本和~/.config/autostart/*.desktop地点。

如果你使用启动,您可以使用它~/.xinitrc来启动这些程序。独立窗口管理器通常有自己的启动/初始化脚本;例如~/.config/openbox/autostartOpenbox。

所有这些方法的共同点是程序都是从之内会议——避免上面列出的所有问题。

答案3

这是我刚刚创建的解决方法,目前还不可用graphical-session.target(在我的 Kubuntu 16.04 系统上):

  1. 创建一个伪 systemd 用户单元它使 graphic-session.target 上升和下降。

使用下列内容创建~/.config/systemd/user/xsession.target

[单元]
描述 = Xsession 已启动并正在运行
BindsTo=graphical-session.target

告诉 systemd 有关这个新单元的信息:

$> systemctl --user daemon-reload
  1. 创造自动启动和关闭脚本xsession.target通过 Ubuntu 16.04 桌面当前可用的机制进行控制。

使用下列内容创建~/.config/autostart-scripts/xsession.target-login.sh

/bin/bash #!/bin/bash

如果 !systemctl --user is-active xsession.target &> /dev/null
然后
  /bin/systemctl --user import-environment 显示 XAUTHORITY
  /bin/systemctl --user 启动 xsession.target

使用下列内容创建~/.config/plasma-workspace/shutdown/xsession.target-logout.sh

/bin/bash #!/bin/bash

如果 systemctl --user is-active xsession.target &> /dev/null
然后
  /bin/systemctl --user 停止 xsession.target

使脚本可执行:

$> chmod + x ~/.config/autostart-scripts/xsession.target-login.sh
$> chmod + x ~/.config/plasma-workspace/shutdown/xsession.target-logout.sh

笔记:这两个文件被放置在 KDE 会选择它们进行自动启动和关闭的位置。对于其他桌面环境(例如 Gnome),这些文件可能被放置在其他地方 - 但我不知道这些环境。

笔记:此解决方法不支持多桌面会话。它只能graphical-session.target在一台机器上只运行一个活动的 X11 会话时才能正确处理(但对于我们大多数 Linux 用户来说,情况就是这样)。

  1. 创造您自己的 systemd 用户单元哪些依赖于graphical-session.target并让它们在您的桌面上登录时干净地运行。

例如@mkaito 的单位应该是这样的:

[单元]
描述=Redshift
PartOf=图形会话.target

[服务]
ExecStart=/bin/redshift -l 28:-13 -t 5300:3300 -b 0.80:0.91 -m randr
重启=总是

daemon-reload(编辑单位后不要忘记做一个!)

  1. 重启机器,登录并验证设备是否按预期启动
$> systemctl --用户状态图形会话.target
● graphic-session.target - 当前图形用户会话
   已加载:已加载(/usr/lib/systemd/user/graphical-session.target;静态;供应商预设:已启用)
   活跃:自 Don 2017-01-05 15:08:42 CET;47 分钟前开始活跃
     文档:man:systemd.special(7)
$> systemctl --用户状态你的单位...

在未来的某一天(会是 Ubuntu 17.04 吗?),我的解决方法将变得过时,因为系统graphical-session.target本身将正确处理。到那时,只需删除自动启动和关闭脚本,xsession.target您的自定义用户单元可能保持不变并正常工作。

答案4

很多答案都暗示需要一些解决方法或脚本。至少在最近的 GNOME 会话中,我不再需要这样的解决方法。

如果我添加WantedBy=graphical-session.target,那么必要的 X11 环境变量(即DISPLAYXAUTHORITY)可供服务使用,并且我可以在我的用户服务文件中执行 X11 程序:

[Unit]
...
PartOf=graphical-session.target

[Service]
...

[Install]
WantedBy=graphical-session.target

据我所知,graphical-session.target是一个被动目标。使用它意味着正在启动的实际会话通过绑定到此目标BindsTo=graphical-session.target。对于gnome-session.target这似乎是这种情况,但对于较旧或不太流行的桌面环境可能并非如此。

我发现检查用户日志很有帮助journalctl --user -b,它打印出按什么顺序达到了哪些目标:

5 月 08 日 21:28:10 earth systemd[2481]: 已达到目标 GNOME 打印机通知目标。5
月 08 日 21:28:10 earth systemd[2481]: 已达到目标 GNOME 会话。5
月 08 日 21:28:10 earth systemd[2481]: 已达到目标 GNOME X11 会话 (会话:gnome-flashback-metacity)。5
月 08 日 21:28:10 earth systemd[2481]: 已达到目标当前图形用户会话。

日志输出目标的描述,我们可以使用以下命令来识别实际的目标名称:

systemctl --user list-units --type target

也可以看看:https://www.freedesktop.org/software/systemd/man/systemd.special.html#Special%20Passive%20User%20Units

相关内容