systemd – Xorg に依存するサービスを書く

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

しかし、Xorgが立ち上がる前に起動しようとするようで、その後に手動でサービスを起動しなければならない。私は間違った After= ターゲットを使っていると思います。何かヒントはありますか?

  42  mkaito  2014-05-28


ベストアンサー

これについて調べてみたのですが、grawityさんの回答は古いようです。ユーザのセッションの一部として実行されるユーザサービスを systemd で設定できるようになりました。DISPLAY と XAUTHORITY を設定することができます (現在 Arch、Debian Stretch+、Ubuntu で使用されています)

これは、システムレベルのアプリ(再起動など)と同じようにプロセス管理ができるので、デスクトップのオートスタートファイルを使用するという以前の推奨事項よりも理にかなっています

今のところ最高のドキュメントは Arch wiki; Systemd/User です

TLDR version;

  1. ~/.config/systemd/user/に目的の*.serviceファイルを作成します
  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ファイルを編集した場合

— Later…

私はアップグレードして、ほとんどのセッションデーモンをsystemd .serviceファイルに変換しました。そこで、いくつかの追加の注意点を追加します

ログイン時にサービスを実行するためのデフォルトフックがなかったので、自分でトリガーする必要があります。私は~/.xsessionファイルから実行しています

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

最初の行は環境変数をsystemdユーザセッションにインポートし、2番目の行はターゲットをキックオフします。私の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

32  John Eikenberry  2016-09-27


通常のヒントは「しないでください」です。redshift はシステム全体のサービスではありません – セッションごとに個別のインスタンスを持っていて、特定のセッションの Xorg に接続する方法を知る必要があります

(Xorgもシステムサービスではありません – ディスプレイマネージャだけがそうで、セッションごとに別のXorgを起動します。graphical.target はディスプレイマネージャの準備ができたときに教えてくれますが、DM が実際にいつ最初の – あるいはすべての – ディスプレイを開始するのかについては何も書いていません)

起動時に DISPLAY=:0 で起動するだけでは十分ではありません。いつでも正確に一つのディスプレイがあるという保証はありませんし、常に :0 であるという保証もありません (例えば、古いロックファイルを残したまま Xorg がクラッシュした場合、次のロックファイルは :0 がまだ占有されていると考えて :1 で実行されるでしょう)

では、どうやって起動すればいいのでしょうか?ほとんどの場合、デスクトップ環境には、独自のセッションサービスを起動するためのいくつかの方法があります。古い投稿を参照してください

startxを使っている場合は、~/.xinitrcを使ってそのようなものを起動することができます。スタンドアロンのウィンドウマネージャは、独自の起動/初期化スクリプトを持っていることが多いです

これらの方法に共通していることは、セッション内からプログラムが開始されるということです-上記のすべての問題を回避することができます

11  user1686  2014-05-28


以下は、私がまだ利用できないgraphical-session.targetの回避策として作成したものです(私のKubuntu 16.04システムで)

  1. グラフィカル-session.targetを上下に移動させる擬似的なsystemdユーザユニットを作成します

以下の内容で~/.config/systemd/user/xsession.targetを作成します

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

この新しいユニットのことを systemd に伝えてください

$> systemctl --user daemon-reload
  1. Ubuntu 16.04デスクトップの現在利用可能なメカニックを介してxsession.targetを制御するオートスタートとシャットダウンスクリプトを作成します

以下の内容で~/.config/autostart-scripts/xsession.target-login.shを作成します

#!/bin/bash

if ! systemctl --user is-active xsession.target &> /dev/null
then
/bin/systemctl --user import-environment DISPLAY XAUTHORITY
/bin/systemctl --user start xsession.target
fi

以下の内容で~/.config/plasma-workspace/shutdown/xsession.target-logout.shを作成します

#!/bin/bash

if systemctl --user is-active xsession.target &> /dev/null
then
/bin/systemctl --user stop xsession.target
fi

スクリプトを実行可能にする

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

注意: この二つのファイルは、自動起動とシャットダウンのために KDE が拾ってくる場所に置かれています。これらのファイルは他のデスクトップ環境 (例えば Gnome など) のために別の場所に置かれているかもしれませんが、それらの環境については私は知りません

注意: この回避策は複数のデスクトップセッションのサポートを欠いています。マシン上でアクティブなX11セッションが1つだけ実行されている限り、graphical-session.targetのみを正しく処理します(ただし、ほとんどのlinuxユーザにとってはこのケースが当てはまります)

  1. graphical-session.targetに依存する独自のsystemdユーザユニットを作成し、デスクトップ上でログインしている間にクリーンに実行させることができます

例えば、@mkaitoさんのユニットはこんな感じです

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

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

(ユニットを編集したらdaemon-reloadを忘れずに!)

  1. マシンを再起動し、ログインして、ユニットが期待通りに起動していることを確認してください
$> systemctl --user status graphical-session.target
● graphical-session.target - Current graphical user session
Loaded: loaded (/usr/lib/systemd/user/graphical-session.target; static; vendor preset: enabled)
Active: active since Don 2017-01-05 15:08:42 CET; 47min ago
Docs: man:systemd.special(7)
$> systemctl --user status your-unit...

いつかの日(Ubuntu 17.04でしょうか?)には、システムがgraphical-session.targetを正しく処理するようになるので、私の回避策は時代遅れになります。その時には、オートスタートとシャットダウンスクリプトとxsession.targetを削除してください

5  gue  2017-01-05


この解決策は、質問の筆者が質問したことを正確に実行します

Xorgが稼働するまで待つ必要があります

もっと良い方法があるかもしれませんが、すでに他のユーザーが回答しているように、これはこの問題に対する別のアプローチです

systemd の systemd-networkd-wait-online.service に似ています。このサービスに依存している他のサービスは、このサービスが正常に開始されるかタイムアウトするとすぐに起動されます

マニュアル (セクション “Files”)によると、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_server_started.serviceに依存するようにした

dependent unit:

[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_server_started.serviceが起動し、systemdがx_server_started.serviceに依存している全てのユニットの起動を進めます

3  VL-80  2018-08-22


タイトルとURLをコピーしました