编写一个依赖 Xorg 的服务

mka*_*ito 47 systemd

我正在尝试为 编写用户级服务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
Run Code Online (Sandbox Code Playgroud)

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

小智 38

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

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

现在最好的文档是 Arch wiki;系统/用户

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
Run Code Online (Sandbox Code Playgroud)

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

[Unit]
Description=Xsession running
BindsTo=graphical-session.target
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 如果您可以提供示例单元文件,并解释如何让单元能够使用 DISPLAY 和 XAUTHORITY,我将很乐意切换已接受的答案。 (2认同)

use*_*686 11

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

(Xorg 也不是系统服务——只有显示管理器是,它还会为每个会话启动一个单独的 Xorg。//graphical.target会告诉您显示管理器何时准备就绪,但它没有说明 DM 何时真正启动首先 - 或全部 - 显示。)

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

那么如何开始呢?几乎总是,桌面环境有几种方法来启动它自己的会话服务。请参阅一篇较旧的帖子,该帖子已经描述了两个常见的帖子;该~/.xprofile脚本和~/.config/autostart/*.desktop位置。

如果你使用startx,你可以~/.xinitrc用来启动这样的事情。独立的窗口管理器通常有自己的启动/初始化脚本;例如~/.config/openbox/autostart对于 Openbox。

什么是共同所有这些方法是程序从启动内部会议-避免上面列出的所有问题。

  • 虽然在许多情况下 redshift 不是系统范围的服务,但成为用户服务是有意义的,这正是 OP 试图做的。 (3认同)

VL-*_*-80 6

该解决方案完全符合问题作者的要求:

它需要等到 Xorg 启动并运行

虽然可能有更好的方法来做到这一点,正如其他用户已经回答的那样,但这是解决此问题的另一种方法。

它类似于 systemd 的systemd-networkd-wait-online.service,它会阻塞直到满足某些条件。一旦该服务启动成功或者超时,依赖它的其他服务就会启动。

根据手册(“文件”部分),X 服务器将创建一个 UNIX 套接字/tmp/.X11-unix/Xn(其中n是显示编号)。

通过监视此套接字的存在,我们可以确定特定显示的服务器已启动。

confirm_x_started.sh:

#!/bin/bash

while [ 1 ]
do
  # Check whether or not socket exists
  if [ -S /tmp/.X11-unix/X0 ]
  then
    exit 0
  fi

  # Adjust timeout according to your needs
  if [ $SECONDS -gt 15 ]
  then
    exit 1
  fi

  sleep 0.5
done
Run Code Online (Sandbox Code Playgroud)

x_server_started.service:

[Unit]
Description=Monitor X server start

[Service]
Type=oneshot
ExecStart=/path/to/confirm_x_started.sh

[Install]
WantedBy=example.target
Run Code Online (Sandbox Code Playgroud)

现在,启用x_server_started.service与 X 服务器同时启动。

使其他服务(需要启动X服务器)依赖x_server_started.service

附属单位:

[Unit]
Description=Service that needs to have the X server started
Requires=x_server_started.service
After=x_server_started.service

[Service]
ExecStart=/path/to/binary

[Install]
WantedBy=example.target
Run Code Online (Sandbox Code Playgroud)

如果 X 服务器启动没有问题,则x_server_started.service几乎会立即启动,并且 systemd 将继续启动所有依赖于x_server_started.service.


小智 5

这是我刚刚创建的解决方法,以解决尚未可用的问题graphical-session.target(在我的 Kubuntu 16.04 系统上):

  1. 创建一个伪 systemd 用户单元,用于启动和关闭 graphics-session.target。

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

[单元]
说明 = Xsession 启动并运行
BindsTo=graphical-session.target

告诉 systemd 这个新单元:

$> systemctl --user daemon-reload
Run Code Online (Sandbox Code Playgroud)
  1. 创建自动启动和关闭脚本xsession.target通过 Ubuntu 16.04 桌面的当前可用机制来控制。

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

#!/bin/bash

如果 !systemctl --user is-active xsession.target &> /dev/null
然后
  /bin/systemctl --user 导入环境显示 XAUTHORITY
  /bin/systemctl --user start xsession.target
菲

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

#!/bin/bash

如果 systemctl --user 处于活动状态 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 的单位应该是这样的:

[单元]
说明=红移
PartOf=graphical-session.target

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

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

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

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