编写依赖Xorg的服务


30

我正在尝试为编写用户级服务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=目标。有什么提示吗?

Answers:


20

我一直在研究这个问题,而grawity的答案似乎已经过时了。现在,您可以使用systemd设置用户服务,该服务与用户会话一起运行。他们可以设置DISPLAY和XAUTHORITY(当前在Arch和Debian Stretch中)。

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

目前最好的文档是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 -查看所有用户单位
  • s- ystemctl --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
如果您可以提供示例单元文件,并说明如何使该单元能够使用DISPLAY和XAUTHORITY,我将很乐意切换可接受的答案。
mkaito

@mkaito,一旦Debian发行Stretch,我会调查一下。我正在运行Debian稳定版,并且一直等到以后再玩。
约翰·艾肯伯里

@mkaito在github.com/systemd/systemd/blob/v219/NEWS#L194上,它说:“现在发布了X11会话脚本,如果会话开始,它将$ DISPLAY和$ XAUTHORITY上载到systemd --user守护程序的环境中。这应该改善与作为systemd用户服务运行的启用X11的应用程序的兼容性。”
josch

我仍然想看一个示例单位文件,只是为了弄清楚是否有特殊需要。
mkaito

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试图做的事情。
simotek

5

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

  1. 创建一个伪systemd用户单元,该用户单元可上下移动图形会话.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

如果!systemctl --user是活动的xsession.target&> / dev / null
然后
  / bin / systemctl --user导入环境显示XAUTHORITY
  / bin / systemctl-用户启动xsession.target
科幻

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

#!/ bin / bash

如果systemctl --user是活动的xsession.target&> / dev / null
然后
  / bin / systemctl-用户停止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. 创建自己的系统用户单元,这些用户单元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在编辑单位后执行a !)

  1. 重新启动计算机,登录并验证设备是否按预期启动
$> systemctl-用户状态图形会话。目标
●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-您的自定义用户单元就可以保持不变,并且可以正常工作。


我知道这是一个旧注释,但是您也可以通过系统设置应用程序在工作区>启动和关闭>自动启动下添加启动/登录脚本,如果要将这些脚本放在某个地方,您会记住它们。
AmbientCyan

2

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

它需要等到Xorg启动并运行

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

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

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

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

confirm_x_started.sh

#!/bin/bash
COUNTER=0

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

  ((++COUNTER))

  if [ $COUNTER -gt 20 ]
  then
    exit 1
  fi

  sleep 0.5
done

x_server_started.service

[Unit]
Description=Monitor X server start

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

[Install]
WantedBy=example.target

现在,启用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

如果X服务器启动时没有问题,x_server_started.service它将几乎立即启动,而systemd将继续启动所有依赖的单元x_server_started.service


这很好。额外的服务很不错。您也可以只在目标服务中使用ExecStartPre。我不得不在“ exit 0”之前添加一个额外的“ sleep 1”,似乎只是尝试立即捕获X有点太快了。
TTimo '18 -10-8
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.