コンテンツにスキップ

「Systemd/ユーザー」の版間の差分

提供: ArchWiki
削除された内容 追加された内容
1版 をインポートしました
Kgx (トーク | 投稿記録)
序文を同期
 
(5人の利用者による、間の24版が非表示)
1行目: 1行目:
{{Lowercase title}}
{{Lowercase title}}
[[Category:デーモンとシステムサービス]]
[[Category:システム管理]]
[[Category:ブートプロセス]]
[[en:Systemd/User]]
[[en:Systemd/User]]
[[es:Systemd/User]]
[[es:Systemd/User]]
[[fr:Systemd/utilisateur]]
[[fr:Systemd/utilisateur]]
[[it:Systemd/User]]
[[it:Systemd/User]]
[[zh-CN:Systemd/User]]
[[ru:Systemd/User]]
[[zh-hans:Systemd/User]]
{{Related articles start}}
{{Related articles start}}
{{Related2|systemd|systemd}}
{{Related|systemd}}
{{Related2|Automatic login to virtual console|仮想コンソールに自動ログイン}}
{{Related|仮想コンソールに自動ログイン}}
{{Related2|Start X at Login|ログイン時に X を起動する}}
{{Related|ログイン時に X を起動}}
{{Related articles end}}
{{Related articles end}}


[[systemd|systemd]] はユーザー [[systemd|systemd]] インスタンスを実行させてサービスを管理できる機能を提供しています。これによって systemd がユーザーによって実行されている時、特定ディレクトリに入っているユニットユーザーが起動・停止有効化無効化ことが可能です。このことroot や特別なユーザーではなく普通のユーザーとして通常実行される [[Music Player Daemon|mpd]] などのデーモンサービスで重宝します。またメールの取得などの作業を自動化することも可能です。らに、多少の注意が必要ですが、ユーザーサービから xorg やウィンドウマネージャを実行することもきます。
[[systemd]] はユーザーの制御下でサービスを管理するためのユーザーごとの systemd インスタンスを提供しユーザー自身 '''user units''' 開始、停止有効化無効化できようにします。こ、[[mpd]] のよう単一ユーザー向けに一般的に実行されるデーモンサービスまたメールの取得のような自動化されたタを実行するのに便利です。


== 利用方法 ==
== 利用方法 ==


ユーザーがログインを行うと、systemd は自動的にユーザーサービスを管理する {{ic|systemd --user}} インスタンスを起動します。このプロセスは、そのユーザーにセッションが残っているかぎり生存し、ユーザーの最後のセッションが閉じられた時に終了します。[[#systemd のユーザーインスタンスを自動起動|systemd のユーザーインスタンスを自動起動]]している場合、インスタンスはブート時に起動し、終了しません。デフォルトではユーザーサービスは何も実行されません。ユーザーサービスを使うことで、ソケットアクティベーションやタイマー、システムの依存関係や cgroups によるプロセスの制限など、systemd の恩恵を最大限活用して、デーモンや自動化されたタスクを実行できます。ユーザーユニットはシステムサービスと同じように以下のディレクトリに配置されます (優先度が低い順):
ユーザーがログインを行うと、systemd は自動的にユーザーサービスを管理する {{ic|systemd --user}} インスタンスを起動します。このプロセスは、そのユーザーにセッションが残っているかぎり生存し、ユーザーの最後のセッションが閉じられた時に終了します。[[#systemd のユーザーインスタンスを自動起動|systemd のユーザーインスタンスを自動起動]]している場合、インスタンスはブート時に起動し、終了しません。ユーザーサービスを使うことで、ソケットアクティベーションやタイマー、システムの依存関係や cgroups によるプロセスの制限など、systemd の恩恵を最大限活用して、デーモンや自動化されたタスクを実行できます。

ユーザーユニットはシステムサービスと同じように以下のディレクトリに配置されます (優先度が低い順):


* {{ic|/usr/lib/systemd/user/}}: インストールしたパッケージに含まれているサービス
* {{ic|/usr/lib/systemd/user/}}: インストールしたパッケージに含まれているサービス
* {{ic|~/.local/share/systemd/user/}}: ホームディレクトリにインストールしたパッケージのユニット
* {{ic|/etc/systemd/user/}}: システムの管理者が配置する、全てのユーザーが使えるユーザーサービス
* {{ic|/etc/systemd/user/}}: システムの管理者が配置する、全てのユーザーが使えるユーザーサービス
* {{ic|~/.config/systemd/user/}}: ユーザーが配置する、そのユーザーのサービス
* {{ic|~/.config/systemd/user/}}: ユーザーが配置する、そのユーザーのサービス
25行目: 28行目:
systemd のユーザーインスタンスが起動すると、{{ic|default.target}} ターゲットが立ち上がります。その後 {{ic|systemctl --user}} を使って手動で systemd のユーザーインスタンスを制御できるようになります。
systemd のユーザーインスタンスが起動すると、{{ic|default.target}} ターゲットが立ち上がります。その後 {{ic|systemctl --user}} を使って手動で systemd のユーザーインスタンスを制御できるようになります。


{{Note|
{{Warning|{{ic|systemd --user}} インスタンスはユーザーごとのプロセスであり、セッションごとのプロセスではないので注意してください。ソケットやステートファイルなどのユーザーサービスによって扱われるリソースはセッションごとではなくユーザーごとに割り振られる (ユーザーのホームディレクトリ上に存在する) というのが原則です。つまりユーザーサービスは全てセッションとは関係なく動作します。結果として、セッションの中で実行する必要があるプログラムはユーザーサービスの中で壊れてしまう可能性があります。systemd のユーザーセッションの扱い方は流動的であり確定していません。[https://mail.gnome.org/archives/desktop-devel-list/2014-January/msg00079.html] や [http://lists.freedesktop.org/archives/systemd-devel/2014-March/017552.html] が今後どうなるかのヒントになるでしょう。}}
* バージョン206から、{{ic|systemd --user}} インスタンスはユーザーごとのプロセスであり、セッションごとのプロセスではないので注意してください。ソケットやステートファイルなどのユーザーサービスによって扱われるリソースはセッションごとではなくユーザーごとに割り振られる (ユーザーのホームディレクトリ上に存在する) というのが原則です。つまりユーザーサービスは全てセッションとは関係なく動作します。結果として、セッションの中で実行する必要があるプログラムはユーザーサービスの中で壊れてしまう可能性があります。systemd のユーザーセッションの扱い方は流動的であり確定していません。[https://mail.gnome.org/archives/desktop-devel-list/2014-January/msg00079.html] や [https://lists.freedesktop.org/archives/systemd-devel/2014-March/017552.html] が今後どうなるかのヒントになるでしょう。
* {{ic|systemd --user}} は {{ic|systemd --system}} プロセスとは別のプロセスを起動します。ユーザーユニットからシステムユニットに依存したり参照することはできません。
}}


== 基本設定 ==
== 基本設定 ==


Systemd のユーザーインスタンスはログイン時に自動で起動します。正しく起動しることを確認するには、次コマンドを使います: {{ic|systemctl --user status}}。
すべてのユーザー単位 {{ic|~/.config/systemd/user/}} に配置されます。最初のログイン時に単位を起動したい場合は、起動し任意単位に対して {{ic|systemctl --user enable ''unit''}} を実行してください


{{Tip|特定のユーザーではなく、すべてのユーザーに対して単位を有効にしたい場合は、root として {{ic|systemctl --global enable ''unit''}} を実行してください。無効化する場合も同様です {{ic|disable}} に変更}}
{{Note|systemd のユーザーインスタンスが自動で実行されない場合 {{ic|/etc/pam.d/system-login}} ファイルを確認してください。このファイルには {{ic|-session optional pam_systemd.so}} というような行が含まれていなくてはなりません。''.pacnew'' ファイルが存在していないかチェックしてください。}}


=== 環境変数 ===
ユーザーサービスは全て {{ic|~/.config/systemd/user}} に配置してください。ログイン時にサービスを実行したい場合は、自動実行したいサービスごとに {{ic|systemctl --user enable ''service''}} を実行してください。


systemd のユーザーインスタンスは {{ic|.bashrc}} などに設定された[[環境変数]]を全く継承しません。systemd インスタンスに環境変数を設定する方法は複数存在します:
{{Note|バージョン 206 から、systemd のユーザーインスタンスの仕組みは変更されています。現在、デフォルトで {{ic|pam_systemd.so}} モジュールがユーザーインスタンスを起動します。手動で起動する必要はありません。{{AUR|user-session-units}} の {{ic|user-session@.service}} は廃止されました。この変更によって {{ic|systemd --user}} はユーザーセッションの外で実行されます。}}


* {{ic|$HOME}} ディレクトリが存在するユーザーの場合、{{ic|~/.config/environment.d/}} ディレクトリに {{ic|1=NAME=VAL}} という形式で環境変数を記述した ''.conf'' ファイルを作成する。ユーザーのユニットファイルにのみ影響します。詳しくは {{man|5|environment.d}} を見てください。
=== D-Bus ===
* {{ic|/etc/systemd/user.conf}} で {{ic|DefaultEnvironment}} オプションを使う。全てのユーザーユニットに影響します。
* {{ic|/etc/systemd/system/user@.service.d/}} に設定ファイルを追加する。全てのユーザーユニットに影響します。[[#サービス例]]を参照。
* {{ic|/etc/systemd/system/user@.service.d/}} にドロップイン設定ファイルを追加する (すべてのユーザーに影響)、詳細は [[#サービス例]]を参照。
* 適宜、{{ic|systemctl --user set-environment}} や {{ic|systemctl --user import-environment}} を使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。
* [[D-Bus]] の {{ic|dbus-update-activation-environment --systemd --all}} コマンドを使う。{{ic|systemctl --user import-environment}} と同じ効果があり、D-Bus セッションに適用されます。コマンドはシェルの初期化ファイルの末尾に追加できます。
* ユーザー環境全体の環境変数は systemd のジェネレータによって読み込まれる {{ic|environment.d}} ディレクトリを使用できます。詳しくは {{man|5|environment.d}} を参照。
* ユーザーごとに異なる環境変数を生成できる {{man|7|systemd.environment-generator}} スクリプトを作成することもできます。ユーザーごとの環境が必要な場合({{ic|XDG_RUNTIME_DIR}} や {{ic|DBUS_SESSION_BUS_ADDRESS}} などが該当)、これはおそらく最適な方法です。


設定するべき変数としては {{ic|PATH}} などが考えられます。
プログラムによっては [[D-Bus|D-Bus]] ユーザーメッセージバスを必要とすることがあります。D-Bus は伝統的に {{ic|dbus-launch}} によってデスクトップ環境の起動時に実行されています。しかしながら、D-Bus に依存するプログラムを systemd のユーザーサービスとして使う場合、依存関係を解決するために D-Bus サーバーも systemd サービスとして実行する必要が出てきます。


設定後、コマンド {{ic|systemctl --user show-environment}} を使用して値が正しいことを確認できます。変更を即座に反映させるには、{{ic|systemctl --user daemon-reload}} を実行する必要があるかもしれません。
{{Note|将来 systemd から kdbus への移行がされることで、systemd はシステムとユーザーのメッセージバスのマネージャになります。}}


==== Systemd ユーザーインスタンス ====
D-Bus を systemd サービスとして設定するには、以下を行う必要があります:


上記はユーザー単位のデフォルト環境変数についてのみ説明しています。しかし、systemd ユーザーインスタンス自体もいくつかの環境変数の影響を受けます。特に、特定の指定子 ({{man|5|systemd.unit|SPECIFIERS}} を参照) は [[XDG Base Directory|XDG 変数]] の影響を受けます。
1. dbus サーバーのサービスユニットとソケットユニットを {{ic|/etc/systemd/user/}} に追加:


ただし、systemd ユーザーインスタンスは ''起動時に設定された環境変数のみ'' を使用します。特に、ファイルを解析しようとはしません ([https://github.com/systemd/systemd/issues/29414 upstream bug #29414 (closed WONTFIX)] を参照) そのため、このような環境変数が必要な場合は、ドロップイン設定ファイルで設定する必要があります ([[#サービス例]]を参照)
{{hc|/etc/systemd/user/dbus.socket|<nowiki>
[Unit]
Description=D-Bus Message Bus Socket
Before=sockets.target


systemd はこれらの値を確認するための内部ツールを提供していませんが、指定子が期待通りに展開されることを確認するために、次のようなサービスを使用できます。
[Socket]
ListenStream=%t/dbus/user_bus_socket

[Install]
WantedBy=default.target
</nowiki>}}

{{hc|/etc/systemd/user/dbus.service|<nowiki>
[Unit]
Description=D-Bus Message Bus
Requires=dbus.socket


{{hc|$XDG_CONFIG_HOME/systemd/user/test-specifiers.service|2=
[Service]
[Service]
Type=oneshot
ExecStart=/usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation
ExecStart=printf '(systemd)=(envvar)\n'
ExecReload=/usr/bin/dbus-send --print-reply --session --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
ExecStart=printf '%%s=%%s\n' %C "${XDG_CACHE_HOME}"
</nowiki>}}
ExecStart=printf '%%s=%%s\n' %E "${XDG_CONFIG_HOME}"
ExecStart=printf '%%s=%%s\n' %L "${XDG_STATE_HOME}"/log
ExecStart=printf '%%s=%%s\n' %S "${XDG_STATE_HOME}"
ExecStart=printf '%%s=%%s\n' %t "${XDG_RUNTIME_DIR}"
}}


==== サービス例 ====
2. 環境変数 {{ic|DBUS_SESSION_BUS_ADDRESS}} を設定。以下のファイルを作成して、{{ic|user@.service}} の設定ファイルを使うことで設定できます:


[[Systemd#ドロップインファイル|ドロップイン]]ディレクトリ {{ic|/etc/systemd/system/user@.service.d/}} を作成して、その中に拡張子が {{ic|.conf}} のファイルを作成します (例: {{ic|local.conf}}):
{{hc|/etc/systemd/system/user@.service.d/dbus.conf|<nowiki>
{{hc|/etc/systemd/system/user@.service.d/local.conf|2=
[Service]
[Service]
Environment="PATH=/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin"
Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%I/dbus/user_bus_socket
Environment="EDITOR=nano -c"
</nowiki>}}
Environment="BROWSER=firefox"
Environment="NO_AT_BRIDGE=1"
}}


==== DISPLAY と XAUTHORITY ====
{{Note|systemd 209 以前は {{ic|DBUS_SESSION_BUS_ADDRESS}} は上流の {{ic|user@.service}} ユニットで設定されていました。現在は異なります。kdbus への移行が完了したら、{{ic|pam_systemd.so}} によって変数が設定されるようになるから、というのが理由のようです。}}


{{ic|DISPLAY}} は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。{{ic|XAUTHORITY}} はユーザーの {{ic|.Xauthority}} ファイルのパスと、X サーバーにアクセスするのに必要な cookie を指定します。systemd ユニットから X アプリケーションを起動する場合、これらの変数を設定する必要があります。[https://github.com/systemd/systemd/blob/v219/NEWS#L194 バージョン 219] から、セッションが開始したときに {{ic|DISPLAY}} と {{ic|XAUTHORITY}} を {{ic|systemd --user}} デーモンの環境にアップロードする X11 セッションアプレット {{ic|/etc/X11/xinit/xinitrc.d/50-systemd-user.sh}} が systemd に付属するようになりました。これによって、X を標準の方法で起動しているかぎり、ユーザーサービスは {{ic|DISPLAY}} や {{ic|XAUTHORITY}} を使用することができるようになっています。
3. root で以下を実行してソケットを有効化:


==== PATH ====
# systemctl --global enable dbus.socket


{{ic|PATH}} 変数を {{ic|.bashrc}} や {{ic|.bash_profile}} で設定しても systemd では使うことができません。{{ic|PATH}} をカスタマイズしており、それを利用するアプリケーションを systemd ユニットから起動する予定があるなら、systemd 環境に {{ic|PATH}} を設定する必要があります。{{ic|PATH}} を {{ic|.bash_profile}} に設定している場合、以下を {{ic|PATH}} 変数を設定した後の {{ic|.bash_profile}} に追加するのが systemd で {{ic|PATH}} を設定する一番簡単な方法です:
=== 環境変数 ===


{{hc|~/.bash_profile|<nowiki>
systemd のユーザーインスタンスは {{ic|.bashrc}} などに設定された[[environment variables|環境変数]]を全く継承しません。systemd インスタンスに環境変数を設定する方法は3つあります:
systemctl --user import-environment PATH
</nowiki>}}


==== pam_environment ====
# {{ic|/etc/systemd/user.conf}} で {{ic|DefaultEnvironment}} オプションを使う。全てのユーザーユニットに影響します。
# {{ic|/etc/systemd/system/user@.service.d/}} に設定ファイルを追加する。てのユーザーユニットに影響します。
# 適宜、{{ic|systemctl --user set-environment}} や {{ic|systemctl --user import-environment}} を使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。
:: {{Tip|1=複数の変数を一度に設定するには、空白で区切った ''key=value'' ペアのリストを設定ファイルに書き込んで、{{ic|xargs systemctl --user set-environment < /path/to/file.conf}} をシェルのスタートアップファイルに追加してください。}}


{{ic|pam_env.so}} モジュールを利用することで環境変数を設定できます。{{ic|~/.pam_environment}} ファイルを以下のように作成してください:
設定するべき変数としては {{ic|DISPLAY}} や {{ic|PATH}} などが考えられます。


{{hc|~/.pam_environment|2=
==== DISPLAY ====
XDG_CONFIG_HOME DEFAULT=@{HOME}/.local/config
XDG_DATA_HOME DEFAULT=@{HOME}/.local/data
}}


{{ic|.pam_environment}} ファイルの構文に関する詳細は[[環境変数#pam_env を使う]]を見てください。{{ic|systemctl --user show-environment}} コマンドを実行することで設定が上手くいっているか確認できます:
DISPLAY は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。systemd ユニットから X アプリケーションを起動するつもりならば、この変数を設定しなくてはなりません。例:


{{hc|/etc/systemd/user.conf|<nowiki>
{{hc|$ systemctl --user show-environment|2=
...
...
XDG_CONFIG_HOME=/home/''user''/.local/config
DefaultEnvironment=DISPLAY=:0
XDG_DATA_HOME=/home/''user''/.local/data
...
...
}}

=== systemd のユーザーインスタンスを自動起動 ===

systemd のユーザーインスタンスはデフォルトでユーザーの最初のログイン時に実行され、ユーザーのセッションが閉じられた時に終了します。しかしながら、ブートした直後にインスタンスを起動して、セッションが閉じられてもユーザーインスタンスを実行し続ける方が、例えばセッションが開いてない時もユーザープロセスを実行したいときなどには便利です。linger を利用してこれを行います。特定のユーザーで linger を有効にするには以下のコマンドを使用:

# loginctl enable-linger ''username''

{{Warning|systemd のサービスはセッションではありません。サービスは ''logind'' の外で動作します。linger を利用して自動ログインを有効にすると[[一般的なトラブルシューティング#セッションのパーミッション|セッションが破壊]]されるので注意してください。}}

== ユーザーユニットを書く ==

普通の systemd ユニットファイルの書き方は [[systemd#ユニットファイル]]を見てください。

=== サンプル ===
以下は mpd サービスのユーザーバージョンの例です。
{{hc|~/.config/systemd/user/mpd.service|<nowiki>
[Unit]
Description=Music Player Daemon

[Service]
ExecStart=/usr/bin/mpd --no-daemon

[Install]
WantedBy=default.target
</nowiki>}}
</nowiki>}}


=== 変数を使用したサンプル ===
==== PATH ====


以下は {{ic|sickbeard.service}} のユーザーバージョンの例で、[[SickBeard]] が特定のファイルを見つけられるようホームディレクトリの変数を使っています:
{{ic|PATH}} 変数を {{ic|.bashrc}} や {{ic|.bash_profile}} で設定しても systemd では使うことができません。{{ic|PATH}} をカスタマイズしており、それを利用するアプリケーションを systemd ユニットから起動する予定があるなら、systemd 環境に {{ic|PATH}} を設定する必要があります。{{ic|PATH}} を {{ic|.bash_profile}} に設定している場合、以下を {{ic|PATH}} 変数を設定した後の {{ic|.bash_profile}} に追加するのが systemd で {{ic|PATH}} を設定する一番簡単な方法です:
{{hc|~/.config/systemd/user/sickbeard.service|<nowiki>
[Unit]
Description=SickBeard Daemon


[Service]
{{hc|~/.bash_profile|<nowiki>
ExecStart=/usr/bin/env python2 /opt/sickbeard/SickBeard.py --config %h/.sickbeard/config.ini --datadir %h/.sickbeard
systemctl --user import-environment PATH

[Install]
WantedBy=default.target
</nowiki>}}
</nowiki>}}


{{ic|man systemd.unit}} に書かれているように、{{ic|%h}} 変数はサービスを実行しているユーザーのホームディレクトリに置き換えられます。他にも [[systemd]] のマニュアルページで示されている変数が存在します。
=== systemd のユーザーインスタンスを自動起動 ===


=== ジャーナルを読み込む ===
systemd のユーザーインスタンスはデフォルトでユーザーの最初のログイン時に実行され、ユーザーのセッションが閉じられた時に終了します。しかしながら、ブートした直後にインスタンスを起動して、セッションが閉じられてもユーザーインスタンスを実行し続ける方が、例えばセッションが開いてない時もユーザープロセスを実行したいときなどには便利です。linger を利用してこれを行います。特定のユーザーで linger を有効にするには以下のコマンドを使用:


ユーザーのジャーナルも同じようなコマンドで読みことができます:
# loginctl enable-linger ''username''


$ journalctl --user
{{Warning|systemd のサービスはセッションではありません。サービスは ''logind'' の外で動作します。linger を利用して自動ログインを有効にすると[[General troubleshooting#セッションのパーミッション|セッションが破壊]]されるので注意してください。}}

ユニットを指定する場合:

$ journalctl --user -u myunit.service

ユーザーユニットを指定する場合:

$ journalctl --user --user-unit myunit.service

ときどきユーザーサービスからの出力がサービスユニットに割り当てられないというバグが存在します。{{ic|-u}} を使って出力をフィルタリングするとサービスユニットからの出力が見れなくなる可能性があります。

== 一時ファイル ==

''systemd-tmpfiles'' を使うことでシステム全体と同じように一時ファイル・ディレクトリを管理することができます ([[systemd#一時ファイル]]を参照)。ユーザー個別の設定ファイルは {{ic|~/.config/user-tmpfiles.d/}} と {{ic|~/.local/share/user-tmpfiles.d/}} からこの順番で読み込まれます。設定ファイルを使うには、必要な systemd ユーザーユニットを使用しているユーザーで有効にする必要があります:

$ systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer

設定ファイルの構文はシステムユニットと同じです。詳しくは man ページの {{man|8|systemd-tmpfiles}} や {{man|5|tmpfiles.d}} を見てください。


== Xorg と systemd ==
== Xorg と systemd ==


systemd ユニットの中で [[Xorg|Xorg]] を実行する方法は複数存在します。以下の2つは、xorg プロセスで新しいユーザーセッションを起動するというのと、systemd のユーザーサービスから xorg を起動するという方法です。
systemd ユニットの中で [[Xorg]] を実行する方法は複数存在します。以下の2つは、xorg プロセスで新しいユーザーセッションを起動するというのと、systemd のユーザーサービスから xorg を起動するという方法です。


=== ディスプレイマネージャを使わずに Xorg に自動ログイン ===
=== ディスプレイマネージャを使わずに Xorg に自動ログイン ===
129行目: 191行目:
[[#D-Bus|D-Bus]] を適切に設定して {{AUR|xlogin-git}} をインストールする必要があります。
[[#D-Bus|D-Bus]] を適切に設定して {{AUR|xlogin-git}} をインストールする必要があります。


雛形のファイルから [[xinitrc|xinitrc]] を設定して、{{ic|/etc/X11/xinit/xinitrc.d/}} のファイルが読み込まれるようにしてください。{{ic|~/.xinitrc}} は実行したときに戻ってこないようにする必要があるため、最後のコマンドとして {{ic|wait}} を記述するか、(ウィンドウマネージャなど) {{ic|exec}} を追加して戻ってこないようにしてください。
雛形のファイルから [[xinitrc]] を設定して、{{ic|/etc/X11/xinit/xinitrc.d/}} のファイルが読み込まれるようにしてください。{{ic|~/.xinitrc}} は実行したときに戻ってこないようにする必要があるため、最後のコマンドとして {{ic|wait}} を記述するか、(ウィンドウマネージャなど) {{ic|exec}} を追加して戻ってこないようにしてください。


セッションは自らの dbus デーモンを使用しますが、systemd ユーティリティは {{ic|dbus.service}} インスタンスが必要です。この問題を解決するはコマンドのエイリアスを作成します:
セッションは自らの dbus デーモンを使用しますが、systemd ユーティリティは {{ic|dbus.service}} インスタンスに自動的に接続します

{{hc|~/.bashrc|<nowiki>
for sd_cmd in systemctl systemd-analyze systemd-run; do
alias $sd_cmd='DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/dbus/user_bus_socket" '$sd_cmd
done
</nowiki>}}


最後に、(root で) ''xlogin'' を有効にして起動時に自動ログインするようにしてください:
最後に、(root で) ''xlogin'' を有効にして起動時に自動ログインするようにしてください:
147行目: 203行目:
=== systemd のユーザーサービスとしての Xorg ===
=== systemd のユーザーサービスとしての Xorg ===


また、systemd のユーザーサービスの中から [[Xorg|Xorg]] を実行することもできます。他の X 関連のユニットを Xorg などに依存させることができるという点では有利な一方、以下で説明するようにいくつか欠点が存在します。
また、systemd のユーザーサービスの中から [[Xorg]] を実行することもできます。他の X 関連のユニットを Xorg などに依存させることができるという点では有利な一方、以下で説明するようにいくつか欠点が存在します。


バージョン 1.16 から {{Pkg|xorg-server}} は systemd とのより良い統合を2つの手段で提供しています:
バージョン 1.16 から {{Pkg|xorg-server}} は systemd とのより良い統合を2つの手段で提供しています:
* デバイス管理を logind に委託することで、非特権でも実行することが可能に ([http://cgit.freedesktop.org/xorg/xserver/commit/?id=82863656ec449644cd34a86388ba40f36cea11e9 このコミット] など Hans de Goede のコミットを参照)。
* デバイス管理を logind に委託することで、非特権でも実行することが可能に ([https://cgit.freedesktop.org/xorg/xserver/commit/?id=82863656ec449644cd34a86388ba40f36cea11e9 このコミット] など Hans de Goede のコミットを参照)。
* ソケットによってサービスを有効化することが可能に ([http://cgit.freedesktop.org/xorg/xserver/commit/?id=b3d3ffd19937827bcbdb833a628f9b1814a6e189 このコミット] を参照)。これによって {{AUR|systemd-xorg-launch-helper-git}} が不要に。
* ソケットによってサービスを有効化することが可能に ([https://cgit.freedesktop.org/xorg/xserver/commit/?id=b3d3ffd19937827bcbdb833a628f9b1814a6e189 このコミット] を参照)。これによって {{AUR|systemd-xorg-launch-helper-git}} が不要に。


残念ながら、非特権モードで xorg を実行できるようにするには、セッションの中で xorg を実行する必要があります。そのため、今のところユーザーサービスとして xorg を実行するのには (1.16 以前と同じように) root 権限で実行する必要があるというハンディキャップがあり、1.16 で導入された非特権モードを活用することはできません。
残念ながら、非特権モードで xorg を実行できるようにするには、セッションの中で xorg を実行する必要があります。そのため、今のところユーザーサービスとして xorg を実行するのには (1.16 以前と同じように) root 権限で実行する必要があるというハンディキャップがあり、1.16 で導入された非特権モードを活用することはできません。


{{Note|This is not a fundamental restriction imposed by logind, but the reason seems to be that xorg needs to know which session to take over, and right now it gets this information calling [http://www.freedesktop.org/wiki/Software/systemd/logind logind]'s {{ic|GetSessionByPID}} using its own pid as argument. See [http://lists.x.org/archives/xorg-devel/2014-February/040476.html this thread] and [http://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/os-support/linux/systemd-logind.c xorg sources]. It seems likely that xorg could be modified to get the session from the tty it is attaching to, and then it could run unprivileged from a user service outside a session.}}
{{Note|上記の制約は logind によるものではなく、xorg にどのセッションを引き継ぐか知らせる必要があるのが理由です。現在の実装では自己の pid を引数として [https://www.freedesktop.org/wiki/Software/systemd/logind logind] {{ic|GetSessionByPID}} を呼び出すことで情報を取得しています。[http://lists.x.org/archives/xorg-devel/2014-February/040476.html このスレッド] [https://cgit.freedesktop.org/xorg/xserver/tree/hw/xfree86/os-support/linux/systemd-logind.c xorg のソース] を参照してください。アタッチする tty からセッションを取得するように xorg を修正すれば、セッションの外でもユーザーサービスから非特権で実行することができます。}}

{{Warning|1=xorg 1.18 ではソケットアクティベーションが壊れているようです。クライアントからアクティベーションが実行されるとデッドロックが発生します。上流のバグレポート [https://bugs.freedesktop.org/show_bug.cgi?id=93072] を参照してください。回避策としては、ソケットアクティベーションを使わないで xorg サーバーを起動することで、サーバーが完全に起動するまでクライアントの接続を待機させることができます。X サーバーの起動を通知する機構は存在しません。}}


以下がユーザーサービスから xorg を起動する方法です:
以下がユーザーサービスから xorg を起動する方法です:
190行目: 248行目:
</nowiki>}}
</nowiki>}}


{{ic|${XDG_VTNR} }} は xorg が起動する仮想ミナルで、サービスユニットでハードコードするか、以下のコマンドを使って systemd 環境で設定します:
{{ic|${XDG_VTNR} }} は xorg が起動する仮想コンソールで、サービスユニットでハードコードするか、以下のコマンドを使って systemd 環境で設定します:


$ systemctl --user set-environment XDG_VTNR=1
$ systemctl --user set-environment XDG_VTNR=1


{{Note|xorg はユーザーがログインしたのと同じ仮想ミナルで起動する必要があります。そうでないと logind はセッションがアクティブになっていないと認識します。}}
{{Note|xorg はユーザーがログインしたのと同じ仮想コンソールで起動する必要があります。そうでないと logind はセッションがアクティブになっていないと認識します。}}


3. [[#DISPLAY|上]]で説明されているように {{ic|DISPLAY}} 環境変数を設定します。
3. [[#DISPLAY と XAUTHORITY|上]]で説明されているように {{ic|DISPLAY}} 環境変数を設定します。


4. 次に、display 0 と tty 2 で xorg のソケットアクティベーションを有効化します:
4. 次に、display 0 と tty 2 で xorg のソケットアクティベーションを有効化します:
203行目: 261行目:
$ systemctl --user start xorg@0.socket # Start listening on the socket for display 0
$ systemctl --user start xorg@0.socket # Start listening on the socket for display 0


これで X アプリケーションを実行すると仮想ミナル2で自動的に xorg が起動します。
これで X アプリケーションを実行すると仮想コンソール 2 で自動的に xorg が起動します。


{{ic|XDG_VTNR}} 環境変数は {{ic|.bash_profile}} から systemd 環境に設定することができ、ウィンドウマネージャなど、あらゆる X アプリケーションを {{ic|xorg@0.socket}} に依存する systemd ユニットとして起動することが可能です。
{{ic|XDG_VTNR}} 環境変数は {{ic|.bash_profile}} から systemd 環境に設定することができ、ウィンドウマネージャなど、あらゆる X アプリケーションを {{ic|xorg@0.socket}} に依存する systemd ユニットとして起動することが可能です。


{{Warning|現在、ユーザーサービスとしてウィンドウマネージャを実行するとセッションの外でウィンドウマネージャが実行されることになり次の問題が引き起こされます: [[General troubleshooting#セッションのパーミッション|セッションの破壊]]。ただし、systemd の開発者はウィンドウマネージャの実行を可能にする何かを作る予定があるようです。[https://mail.gnome.org/archives/desktop-devel-list/2014-January/msg00079.html] や [http://lists.freedesktop.org/archives/systemd-devel/2014-March/017552.html] を見て下さい。}}
{{Warning|現在、ユーザーサービスとしてウィンドウマネージャを実行するとセッションの外でウィンドウマネージャが実行されることになり次の問題が引き起こされます: [[一般的なトラブルシューティング#セッションのパーミッション|セッションの破壊]]。ただし、systemd の開発者はウィンドウマネージャの実行を可能にする何かを作る予定があるようです。[https://mail.gnome.org/archives/desktop-devel-list/2014-January/msg00079.html] や [https://lists.freedesktop.org/archives/systemd-devel/2014-March/017552.html] を見て下さい。}}

== ユーザーユニットを書く ==
=== サンプル ===
以下は mpd サービスのユーザーバージョンの例です。
{{hc|~/.config/systemd/user/mpd.service|<nowiki>
[Unit]
Description=Music Player Daemon

[Service]
ExecStart=/usr/bin/mpd --no-daemon

[Install]
WantedBy=default.target
</nowiki>}}
=== 変数を使用したサンプル ===
以下は {{ic|sickbeard.service}} のユーザーバージョンの例で、SickBeard が特定のファイルを見つけられるようホームディレクトリの変数を使っています:
{{hc|~/.config/systemd/user/sickbeard.service|<nowiki>
[Unit]
Description=SickBeard Daemon

[Service]
ExecStart=/usr/bin/env python2 /opt/sickbeard/SickBeard.py --config %h/.sickbeard/config.ini --datadir %h/.sickbeard

[Install]
WantedBy=default.target
</nowiki>}}

{{ic|man systemd.unit}} に書かれているように、{{ic|%h}} 変数はサービスを実行しているユーザーのホームディレクトリに置き換えられます。他にも [[systemd|systemd]] のマニュアルページで示されている変数が存在します。

=== X アプリケーションについての注意 ===

ほとんどの X アプリは実行するのに {{ic|DISPLAY}} 変数を必要とします (あなたのサービスファイルが起動しない理由として第一に挙げられるでしょう)。systemd のユーザーインスタンスでこの変数を設定する方法は [[#DISPLAY]] を見て下さい。もしくは、以下のようにユニットでこの変数を設定することもできます:

{{hc|~/.config/systemd/user/parcellite.service|2=
[Unit]
Description=Parcellite clipboard manager

[Service]
ExecStart=/usr/bin/parcellite
'''Environment=DISPLAY=:0'''

[Install]
WantedBy=mystuff.target
}}


== ユースケース ==
== ユースケース ==
257行目: 271行目:
=== 永続的なターミナルマルチプレクサ ===
=== 永続的なターミナルマルチプレクサ ===


ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで [[GNU Screen]] や [[Tmux|Tmux]] などのターミナルマルチプレクサをバックグラウンドで実行したいということもあるでしょう。X ログインとログインを分割するのはディスプレイマネージャの代わりに TTY で起動したい場合にのみ有用です (その場合すべてを {{ic|myStuff.target}} で起動するように記述できます)。
ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで [[GNU Screen]] や [[Tmux]] などのターミナルマルチプレクサをバックグラウンドで実行したいということもあるでしょう。X ログインとログインを分割するのはディスプレイマネージャの代わりに TTY で起動したい場合にのみ有用です (その場合すべてを {{ic|myStuff.target}} で起動するように記述できます)。


上述のようなタイプのユーザーセッションを作成するには、{{ic|wm.target}} を作成する代わりに、{{ic|multiplexer.target}} を作成します:
上述のようなタイプのユーザーセッションを作成するには、{{ic|wm.target}} を作成する代わりに、{{ic|multiplexer.target}} を作成します:
272行目: 286行目:
}}
}}


上記の {{ic|mystuff.target}} と同じように、{{ic|cruft.target}} は tmux や screen が起動する前に実行する必要があるサービス (もしくは起動時に即座に起動させたいサービス)、例えば GnuPG デーモンのセッションなどを起動します。
{{ic|cruft.target}}, like {{ic|mystuff.target}} above, should start anything you think should run before tmux or screen starts (or which you want started at boot regardless of timing), such as a GnuPG daemon session.


次にマルチプレクサセッションのサービスを作成してください。以下は tmux を使用して {{ic|/tmp/gpg-agent-info}} に情報を書き込む gpg-agent セッションを読み込むサービスの例です。また、DISPLAY を設定することで X を起動したときに X プログラムが実行できるようにしています。
You then need to create a service for your multiplexer session. Here is a sample service, using tmux as an example and sourcing a gpg-agent session which wrote its information to {{ic|/tmp/gpg-agent-info}}. This sample session, when you start X, will also be able to run X programs, since DISPLAY is set.


{{bc|1=
{{bc|1=
[Unit]
[Unit]
Description=tmux: A terminal multiplixer Documentation=man:tmux(1)
Description=tmux: A terminal multiplixer
Documentation=man:tmux(1)
After=gpg-agent.service
After=gpg-agent.service
Wants=gpg-agent.service
Wants=gpg-agent.service
293行目: 308行目:
}}
}}


Once this is done, {{ic|systemctl --user enable}} {{ic|tmux.service}}, {{ic|multiplexer.target}} and any services you created to be run by {{ic|cruft.target}} and you should be set to go! Activated {{ic|user-session@.service}} as described above, but be sure to remove the {{ic|1=Conflicts=getty@tty1.service}} from {{ic|user-session@.service}}, since your user session will not be taking over a TTY. Congratulations! You have a running terminal multiplexer and some other useful programs ready to start at boot!
上記の設定が完了したら、{{ic|systemctl --user enable}} {{ic|tmux.service}}, {{ic|multiplexer.target}} {{ic|cruft.target}} で実行させるサービスを有効化してください。後は同じように {{ic|user-session@.service}} を有効化しますが、ユーザーセッションは TTY を引き継がないので {{ic|user-session@.service}} から {{ic|1=Conflicts=getty@tty1.service}} は削除してください。これで、起動時にターミナルマルチプレクサなどのプログラムを実行できるようになります。


=== ウィンドウマネージャ ===
=== ウィンドウマネージャ ===
314行目: 329行目:
</nowiki>}}
</nowiki>}}


{{Note|The {{ic|[Install]}} section includes a {{ic|WantedBy}} part. When using {{ic|systemctl --user enable}} it will link this as {{ic|~/.config/systemd/user/wm.target.wants/''window_manager''.service}}, allowing it to be started at login. Is recommended to enable this service, not to link it manually.}}
{{Note|{{ic|[Install]}} セクションに {{ic|WantedBy}} を記述することで、{{ic|systemctl --user enable}} を使用した際に {{ic|~/.config/systemd/user/wm.target.wants/''window_manager''.service}} としてリンクが作成され、ログイン時に起動できるようになります。リンクは手動で作成するのではなく、サービスを有効化することを推奨します。}}

== ログアウト時にユーザープロセスを終了 ==

{{pkg|systemd}} パッケージのデフォルトは {{ic|1=KillUserProcesses=no}} となっており、ユーザーが完全にログアウトしたときでもユーザープロセスは終了しません。ユーザーがログアウトしたときに全てのユーザープロセスが終了するようにしたい場合、{{ic|/etc/systemd/logind.conf}} に {{ic|1=KillUserProcesses=yes}} と設定してください。

ただし、この設定を変更すると [[tmux]] や [[screen]] などのターミナルマルチプレクサが動作しなくなります。以下のように {{ic|systemd-run}} を使ってターミナルマルチプレクサを利用してください:

$ systemd-run --scope --user ''command'' ''args''

例えば、{{ic|screen}} を実行する場合:

$ systemd-run --scope --user screen -S ''foo''

{{ic|systemd-run}} を使うと、ログアウト後も、ユーザがシステム内のどこかで少なくとも 1 回はログインしていて、{{ic|user@.service}} がまだ実行されている間だけ、プロセスが実行され続けます。

ユーザがすべてのセッションからログアウトした後、{{ic|user@.service}} は、そのユーザが「lingering」を有効にしていない限り、デフォルトで終了します [https://github.com/systemd/systemd/blob/76153ad45f09b6ae45464f2e03d3afefbb4b2afe/NEWS#L274]。ユーザーが完全にログアウトしていても、長時間のタスクを効果的に実行できるようにするには、そのユーザーに対してリンガリングを有効にする必要があります。詳しくは [[#Automatic start-up of systemd user instances]] と {{man|1|loginctl}} を参照してください。

== トラブルシューティング ==

=== ランタイムディレクトリ '/run/user/1000' は、UID1000 によって所有されていません ===

systemd[1867]: pam_systemd(systemd-user:session): Runtime directory '/run/user/1000' is not owned by UID 1000, as it should.
systemd[1867]: Trying to run as user instance, but $XDG_RUNTIME_DIR is not set

このようなエラーが表示され、ログインセッションが壊れている場合、システム上の別のシステム(ユーザーではない)サービスがこのフォルダを作成している可能性があります。例えば、{{ic|/run/user/1000}} にバインドマウントしている [[docker]] コンテナを使用している場合、このようなことが起こる可能性があります。これを解決するには、マウントを削除することでコンテナを修正するか、ドッカーサービスを無効化/遅延させるかのいずれかです。

=== "A stop job is running for User Manager for UID 1000" ===

シャットダウン中にこのメッセージが表示される場合、通常は2分のタイムアウトが設定されていることが多いですが、これはユーザーサービスの1つがタイムリーに停止しなかったことを意味します。これには、以前に一時的なサービスを生成した問題のあるアプリケーションが原因である可能性があります。タイムアウトが切れるのを待つこともできますが、これが気になる場合は、問題のあるサービスにオーバーライドを作成するか、すべてのユーザーサービスに対してグローバルタイムアウトを短縮することができます。

==== 問題のあるサービスを特定してオーバーライドする ====

この問題をトラブルシューティングするために、[[一般的なトラブルシューティング#リカバリシェル|systemd デバッグシェル]] を起動します:

systemctl start debug-shell

その後、システムを再起動するかシャットダウンします。問題が発生したときに、{{ic|Ctrl+Alt+F9}} を使用してデバッグシェルに切り替えます。シャットダウンを妨げているサービスを特定するには、次のコマンドを実行します:

systemctl --user list-jobs

ほとんどのオープンソースアプリケーションでは、この問題は該当するメンテナに報告されるべきであり、オーバーライドは必要ありません。しかし、クローズドソースアプリケーションの場合は、次のようにオーバーライドを作成できます:

{{hc|$ systemctl --user edit --force ''name''@.service |2=
[Service]
TimeoutStopSec=1s
}}

これにより、その特定のサービスのタイムアウトが1秒に短縮されます。{{ic|--force}} パラメータは、一時的なサービスでディスク上に {{ic|.service}} ファイルを作成しない場合にのみ必要です。オーバーライドはそれに関係なく機能します。タイムアウトの代わりに {{ic|1=KillSignal=SIGKILL}} を使用することもできます。これにより、ユーザーマネージャが停止したときにサービスが即座に強制終了されます。この方法は、そのサービスがそれを処理できると確信している場合にのみ使用してください。

==== タイムアウト値の変更 ====

どのサービスがシャットダウンを妨げているか気にしない場合は、次のようにしてすべてのユーザーサービスのグローバルタイムアウトを変更できます:

{{hc|# systemctl edit user@.service |2=
[Service]
TimeoutStopSec=10s
}}

このタイムアウト後、優雅に停止していないすべてのユーザーサービスは強制終了されます。これは突然の電源断と同じです。この値は特定の使用ケースに合わせて調整してください。タイムアウトを低すぎる値に設定すると、アプリケーションによってはデータ損失が発生する可能性があります。


== 参照 ==
== 参照 ==
* [https://bitbucket.org/KaiSforza/systemd-user-units/wiki/Home KaiSforza's bitbucket wiki]
* [https://bitbucket.org/KaiSforza/systemd-user-units/wiki/Home KaiSforza's bitbucket wiki]
* [https://github.com/zoqaeski/systemd-user-units Zoqaeski's units on Github]
* [https://github.com/zoqaeski/systemd-user-units Zoqaeski's units on Github]
* [https://github.com/grawity/systemd-user-units Collection of useful systemd user units]
* [https://bbs.archlinux.org/viewtopic.php?id=167115 Forum thread about changes in systemd 206 user instances]
* [https://bbs.archlinux.org/viewtopic.php?id=167115 Forum thread about changes in systemd 206 user instances]

2025年3月25日 (火) 19:45時点における最新版

systemd は、ユーザーの制御下でサービスを管理するためのユーザーごとの systemd インスタンスを提供し、ユーザー自身の user units を開始、停止、有効化、無効化できるようにします。これは、mpd のような単一ユーザー向けに一般的に実行されるデーモンやサービス、またはメールの取得のような自動化されたタスクを実行するのに便利です。

利用方法

ユーザーがログインを行うと、systemd は自動的にユーザーサービスを管理する systemd --user インスタンスを起動します。このプロセスは、そのユーザーにセッションが残っているかぎり生存し、ユーザーの最後のセッションが閉じられた時に終了します。systemd のユーザーインスタンスを自動起動している場合、インスタンスはブート時に起動し、終了しません。ユーザーサービスを使うことで、ソケットアクティベーションやタイマー、システムの依存関係や cgroups によるプロセスの制限など、systemd の恩恵を最大限活用して、デーモンや自動化されたタスクを実行できます。

ユーザーユニットはシステムサービスと同じように以下のディレクトリに配置されます (優先度が低い順):

  • /usr/lib/systemd/user/: インストールしたパッケージに含まれているサービス
  • ~/.local/share/systemd/user/: ホームディレクトリにインストールしたパッケージのユニット
  • /etc/systemd/user/: システムの管理者が配置する、全てのユーザーが使えるユーザーサービス
  • ~/.config/systemd/user/: ユーザーが配置する、そのユーザーのサービス

systemd のユーザーインスタンスが起動すると、default.target ターゲットが立ち上がります。その後 systemctl --user を使って手動で systemd のユーザーインスタンスを制御できるようになります。

ノート
  • バージョン206から、systemd --user インスタンスはユーザーごとのプロセスであり、セッションごとのプロセスではないので注意してください。ソケットやステートファイルなどのユーザーサービスによって扱われるリソースはセッションごとではなくユーザーごとに割り振られる (ユーザーのホームディレクトリ上に存在する) というのが原則です。つまりユーザーサービスは全てセッションとは関係なく動作します。結果として、セッションの中で実行する必要があるプログラムはユーザーサービスの中で壊れてしまう可能性があります。systemd のユーザーセッションの扱い方は流動的であり確定していません。[1][2] が今後どうなるかのヒントになるでしょう。
  • systemd --usersystemd --system プロセスとは別のプロセスを起動します。ユーザーユニットからシステムユニットに依存したり参照することはできません。

基本設定

すべてのユーザー単位は ~/.config/systemd/user/ に配置されます。最初のログイン時に単位を起動したい場合は、起動したい任意の単位に対して systemctl --user enable unit を実行してください。

ヒント 特定のユーザーではなく、すべてのユーザーに対して単位を有効にしたい場合は、root として systemctl --global enable unit を実行してください。無効化する場合も同様です disable に変更

環境変数

systemd のユーザーインスタンスは .bashrc などに設定された環境変数を全く継承しません。systemd インスタンスに環境変数を設定する方法は複数存在します:

  • $HOME ディレクトリが存在するユーザーの場合、~/.config/environment.d/ ディレクトリに NAME=VAL という形式で環境変数を記述した .conf ファイルを作成する。ユーザーのユニットファイルにのみ影響します。詳しくは environment.d(5) を見てください。
  • /etc/systemd/user.confDefaultEnvironment オプションを使う。全てのユーザーユニットに影響します。
  • /etc/systemd/system/user@.service.d/ に設定ファイルを追加する。全てのユーザーユニットに影響します。#サービス例を参照。
  • /etc/systemd/system/user@.service.d/ にドロップイン設定ファイルを追加する (すべてのユーザーに影響)、詳細は #サービス例を参照。
  • 適宜、systemctl --user set-environmentsystemctl --user import-environment を使う。環境変数を設定した後に起動したユーザーユニットには影響しますが、既に起動しているユニットには影響しません。
  • D-Busdbus-update-activation-environment --systemd --all コマンドを使う。systemctl --user import-environment と同じ効果があり、D-Bus セッションに適用されます。コマンドはシェルの初期化ファイルの末尾に追加できます。
  • ユーザー環境全体の環境変数は systemd のジェネレータによって読み込まれる environment.d ディレクトリを使用できます。詳しくは environment.d(5) を参照。
  • ユーザーごとに異なる環境変数を生成できる systemd.environment-generator(7) スクリプトを作成することもできます。ユーザーごとの環境が必要な場合(XDG_RUNTIME_DIRDBUS_SESSION_BUS_ADDRESS などが該当)、これはおそらく最適な方法です。

設定するべき変数としては PATH などが考えられます。

設定後、コマンド systemctl --user show-environment を使用して値が正しいことを確認できます。変更を即座に反映させるには、systemctl --user daemon-reload を実行する必要があるかもしれません。

Systemd ユーザーインスタンス

上記はユーザー単位のデフォルト環境変数についてのみ説明しています。しかし、systemd ユーザーインスタンス自体もいくつかの環境変数の影響を受けます。特に、特定の指定子 (systemd.unit(5) § SPECIFIERS を参照) は XDG 変数 の影響を受けます。

ただし、systemd ユーザーインスタンスは 起動時に設定された環境変数のみ を使用します。特に、ファイルを解析しようとはしません (upstream bug #29414 (closed WONTFIX) を参照) そのため、このような環境変数が必要な場合は、ドロップイン設定ファイルで設定する必要があります (#サービス例を参照)

systemd はこれらの値を確認するための内部ツールを提供していませんが、指定子が期待通りに展開されることを確認するために、次のようなサービスを使用できます。

$XDG_CONFIG_HOME/systemd/user/test-specifiers.service
[Service]
Type=oneshot
ExecStart=printf '(systemd)=(envvar)\n'
ExecStart=printf '%%s=%%s\n' %C "${XDG_CACHE_HOME}"
ExecStart=printf '%%s=%%s\n' %E "${XDG_CONFIG_HOME}"
ExecStart=printf '%%s=%%s\n' %L "${XDG_STATE_HOME}"/log
ExecStart=printf '%%s=%%s\n' %S "${XDG_STATE_HOME}"
ExecStart=printf '%%s=%%s\n' %t "${XDG_RUNTIME_DIR}"

サービス例

ドロップインディレクトリ /etc/systemd/system/user@.service.d/ を作成して、その中に拡張子が .conf のファイルを作成します (例: local.conf):

/etc/systemd/system/user@.service.d/local.conf
[Service]
Environment="PATH=/usr/lib/ccache/bin:/usr/local/bin:/usr/bin:/bin"
Environment="EDITOR=nano -c"
Environment="BROWSER=firefox"
Environment="NO_AT_BRIDGE=1"

DISPLAY と XAUTHORITY

DISPLAY は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。XAUTHORITY はユーザーの .Xauthority ファイルのパスと、X サーバーにアクセスするのに必要な cookie を指定します。systemd ユニットから X アプリケーションを起動する場合、これらの変数を設定する必要があります。バージョン 219 から、セッションが開始したときに DISPLAYXAUTHORITYsystemd --user デーモンの環境にアップロードする X11 セッションアプレット /etc/X11/xinit/xinitrc.d/50-systemd-user.sh が systemd に付属するようになりました。これによって、X を標準の方法で起動しているかぎり、ユーザーサービスは DISPLAYXAUTHORITY を使用することができるようになっています。

PATH

PATH 変数を .bashrc.bash_profile で設定しても systemd では使うことができません。PATH をカスタマイズしており、それを利用するアプリケーションを systemd ユニットから起動する予定があるなら、systemd 環境に PATH を設定する必要があります。PATH.bash_profile に設定している場合、以下を PATH 変数を設定した後の .bash_profile に追加するのが systemd で PATH を設定する一番簡単な方法です:

~/.bash_profile
systemctl --user import-environment PATH

pam_environment

pam_env.so モジュールを利用することで環境変数を設定できます。~/.pam_environment ファイルを以下のように作成してください:

~/.pam_environment
XDG_CONFIG_HOME DEFAULT=@{HOME}/.local/config
XDG_DATA_HOME   DEFAULT=@{HOME}/.local/data

.pam_environment ファイルの構文に関する詳細は環境変数#pam_env を使うを見てください。systemctl --user show-environment コマンドを実行することで設定が上手くいっているか確認できます:

$ systemctl --user show-environment
...
XDG_CONFIG_HOME=/home/user/.local/config
XDG_DATA_HOME=/home/user/.local/data
...

systemd のユーザーインスタンスを自動起動

systemd のユーザーインスタンスはデフォルトでユーザーの最初のログイン時に実行され、ユーザーのセッションが閉じられた時に終了します。しかしながら、ブートした直後にインスタンスを起動して、セッションが閉じられてもユーザーインスタンスを実行し続ける方が、例えばセッションが開いてない時もユーザープロセスを実行したいときなどには便利です。linger を利用してこれを行います。特定のユーザーで linger を有効にするには以下のコマンドを使用:

# loginctl enable-linger username
警告 systemd のサービスはセッションではありません。サービスは logind の外で動作します。linger を利用して自動ログインを有効にするとセッションが破壊されるので注意してください。

ユーザーユニットを書く

普通の systemd ユニットファイルの書き方は systemd#ユニットファイルを見てください。

サンプル

以下は mpd サービスのユーザーバージョンの例です。

~/.config/systemd/user/mpd.service
[Unit]
Description=Music Player Daemon

[Service]
ExecStart=/usr/bin/mpd --no-daemon

[Install]
WantedBy=default.target

変数を使用したサンプル

以下は sickbeard.service のユーザーバージョンの例で、SickBeard が特定のファイルを見つけられるようホームディレクトリの変数を使っています:

~/.config/systemd/user/sickbeard.service
[Unit]
Description=SickBeard Daemon

[Service]
ExecStart=/usr/bin/env python2 /opt/sickbeard/SickBeard.py --config %h/.sickbeard/config.ini --datadir %h/.sickbeard

[Install]
WantedBy=default.target

man systemd.unit に書かれているように、%h 変数はサービスを実行しているユーザーのホームディレクトリに置き換えられます。他にも systemd のマニュアルページで示されている変数が存在します。

ジャーナルを読み込む

ユーザーのジャーナルも同じようなコマンドで読みことができます:

$ journalctl --user

ユニットを指定する場合:

$ journalctl --user -u myunit.service

ユーザーユニットを指定する場合:

$ journalctl --user --user-unit myunit.service

ときどきユーザーサービスからの出力がサービスユニットに割り当てられないというバグが存在します。-u を使って出力をフィルタリングするとサービスユニットからの出力が見れなくなる可能性があります。

一時ファイル

systemd-tmpfiles を使うことでシステム全体と同じように一時ファイル・ディレクトリを管理することができます (systemd#一時ファイルを参照)。ユーザー個別の設定ファイルは ~/.config/user-tmpfiles.d/~/.local/share/user-tmpfiles.d/ からこの順番で読み込まれます。設定ファイルを使うには、必要な systemd ユーザーユニットを使用しているユーザーで有効にする必要があります:

$ systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer

設定ファイルの構文はシステムユニットと同じです。詳しくは man ページの systemd-tmpfiles(8)tmpfiles.d(5) を見てください。

Xorg と systemd

systemd ユニットの中で Xorg を実行する方法は複数存在します。以下の2つは、xorg プロセスで新しいユーザーセッションを起動するというのと、systemd のユーザーサービスから xorg を起動するという方法です。

ディスプレイマネージャを使わずに Xorg に自動ログイン

こちらを選択した場合、xorg サーバーでユーザーセッションを起動してその後ウィンドウマネージャなどを起動するために通常の ~/.xinitrc を実行するシステムユニットを起動します。

D-Bus を適切に設定して xlogin-gitAUR をインストールする必要があります。

雛形のファイルから xinitrc を設定して、/etc/X11/xinit/xinitrc.d/ のファイルが読み込まれるようにしてください。~/.xinitrc は実行したときに戻ってこないようにする必要があるため、最後のコマンドとして wait を記述するか、(ウィンドウマネージャなど) exec を追加して戻ってこないようにしてください。

セッションは自らの dbus デーモンを使用しますが、systemd ユーティリティは dbus.service インスタンスに自動的に接続します。

最後に、(root で) xlogin を有効にして起動時に自動ログインするようにしてください:

# systemctl enable xlogin@username

ユーザーセッションが systemd の範囲の中に収まるようになってユーザーセッションの全てが問題なく動作するはずです。

systemd のユーザーサービスとしての Xorg

また、systemd のユーザーサービスの中から Xorg を実行することもできます。他の X 関連のユニットを Xorg などに依存させることができるという点では有利な一方、以下で説明するようにいくつか欠点が存在します。

バージョン 1.16 から xorg-server は systemd とのより良い統合を2つの手段で提供しています:

  • デバイス管理を logind に委託することで、非特権でも実行することが可能に (このコミット など Hans de Goede のコミットを参照)。
  • ソケットによってサービスを有効化することが可能に (このコミット を参照)。これによって systemd-xorg-launch-helper-gitAUR が不要に。

残念ながら、非特権モードで xorg を実行できるようにするには、セッションの中で xorg を実行する必要があります。そのため、今のところユーザーサービスとして xorg を実行するのには (1.16 以前と同じように) root 権限で実行する必要があるというハンディキャップがあり、1.16 で導入された非特権モードを活用することはできません。

ノート 上記の制約は logind によるものではなく、xorg にどのセッションを引き継ぐか知らせる必要があるのが理由です。現在の実装では自己の pid を引数として logindGetSessionByPID を呼び出すことで情報を取得しています。このスレッドxorg のソース を参照してください。アタッチする tty からセッションを取得するように xorg を修正すれば、セッションの外でもユーザーサービスから非特権で実行することができます。
警告 xorg 1.18 ではソケットアクティベーションが壊れているようです。クライアントからアクティベーションが実行されるとデッドロックが発生します。上流のバグレポート [3] を参照してください。回避策としては、ソケットアクティベーションを使わないで xorg サーバーを起動することで、サーバーが完全に起動するまでクライアントの接続を待機させることができます。X サーバーの起動を通知する機構は存在しません。

以下がユーザーサービスから xorg を起動する方法です:

1. /etc/X11/Xwrapper.config を編集して、xorg が root 権限を使ってどのユーザーでも動作するようにします:

/etc/X11/Xwrapper.config
allowed_users=anybody
needs_root_rights=yes

2. 以下のユニットを ~/.config/systemd/user に追加:

~/.config/systemd/user/xorg@.socket
[Unit]
Description=Socket for xorg at display %i

[Socket]
ListenStream=/tmp/.X11-unix/X%i
~/.config/systemd/user/xorg@.service
[Unit]
Description=Xorg server at display %i

Requires=xorg@%i.socket
After=xorg@%i.socket

[Service]
Type=simple
SuccessExitStatus=0 1

ExecStart=/usr/bin/Xorg :%i -nolisten tcp -noreset -verbose 2 "vt${XDG_VTNR}"

${XDG_VTNR} は xorg が起動する仮想コンソールで、サービスユニットでハードコードするか、以下のコマンドを使って systemd 環境で設定します:

$ systemctl --user set-environment XDG_VTNR=1
ノート xorg はユーザーがログインしたのと同じ仮想コンソールで起動する必要があります。そうでないと logind はセッションがアクティブになっていないと認識します。

3. で説明されているように DISPLAY 環境変数を設定します。

4. 次に、display 0 と tty 2 で xorg のソケットアクティベーションを有効化します:

$ systemctl --user set-environment XDG_VTNR=2     # So that xorg@.service knows which vt use
$ systemctl --user start xorg@0.socket            # Start listening on the socket for display 0

これで X アプリケーションを実行すると仮想コンソール 2 で自動的に xorg が起動します。

XDG_VTNR 環境変数は .bash_profile から systemd 環境に設定することができ、ウィンドウマネージャなど、あらゆる X アプリケーションを xorg@0.socket に依存する systemd ユニットとして起動することが可能です。

警告 現在、ユーザーサービスとしてウィンドウマネージャを実行するとセッションの外でウィンドウマネージャが実行されることになり次の問題が引き起こされます: セッションの破壊。ただし、systemd の開発者はウィンドウマネージャの実行を可能にする何かを作る予定があるようです。[4][5] を見て下さい。

ユースケース

永続的なターミナルマルチプレクサ

ウィンドウマネージャのセッションにログインする代わりに、ユーザーセッションでデフォルトで GNU ScreenTmux などのターミナルマルチプレクサをバックグラウンドで実行したいということもあるでしょう。X ログインとログインを分割するのはディスプレイマネージャの代わりに TTY で起動したい場合にのみ有用です (その場合すべてを myStuff.target で起動するように記述できます)。

上述のようなタイプのユーザーセッションを作成するには、wm.target を作成する代わりに、multiplexer.target を作成します:

[Unit]
Description=Terminal multiplexer
Documentation=info:screen man:screen(1) man:tmux(1)
After=cruft.target
Wants=cruft.target

[Install]
Alias=default.target

上記の mystuff.target と同じように、cruft.target は tmux や screen が起動する前に実行する必要があるサービス (もしくは起動時に即座に起動させたいサービス)、例えば GnuPG デーモンのセッションなどを起動します。

次にマルチプレクサセッションのサービスを作成してください。以下は tmux を使用して /tmp/gpg-agent-info に情報を書き込む gpg-agent セッションを読み込むサービスの例です。また、DISPLAY を設定することで X を起動したときに X プログラムが実行できるようにしています。

[Unit]
Description=tmux: A terminal multiplixer
Documentation=man:tmux(1)
After=gpg-agent.service
Wants=gpg-agent.service

[Service]
Type=forking
ExecStart=/usr/bin/tmux start
ExecStop=/usr/bin/tmux kill-server
Environment=DISPLAY=:0
EnvironmentFile=/tmp/gpg-agent-info

[Install]
WantedBy=multiplexer.target

上記の設定が完了したら、systemctl --user enabletmux.service, multiplexer.targetcruft.target で実行させるサービスを有効化してください。後は同じように user-session@.service を有効化しますが、ユーザーセッションは TTY を引き継がないので user-session@.service から Conflicts=getty@tty1.service は削除してください。これで、起動時にターミナルマルチプレクサなどのプログラムを実行できるようになります。

ウィンドウマネージャ

systemd のサービスとしてウィンドウマネージャを実行するには、まず Xorg を systemd のユーザーサービスとして実行する必要があります。以下では awesome を例として使います:

~/.config/systemd/user/awesome.service
[Unit]
Description=Awesome window manager
After=xorg.target
Requires=xorg.target

[Service]
ExecStart=/usr/bin/awesome
Restart=always
RestartSec=10
 
[Install]
WantedBy=wm.target
ノート [Install] セクションに WantedBy を記述することで、systemctl --user enable を使用した際に ~/.config/systemd/user/wm.target.wants/window_manager.service としてリンクが作成され、ログイン時に起動できるようになります。リンクは手動で作成するのではなく、サービスを有効化することを推奨します。

ログアウト時にユーザープロセスを終了

systemd パッケージのデフォルトは KillUserProcesses=no となっており、ユーザーが完全にログアウトしたときでもユーザープロセスは終了しません。ユーザーがログアウトしたときに全てのユーザープロセスが終了するようにしたい場合、/etc/systemd/logind.confKillUserProcesses=yes と設定してください。

ただし、この設定を変更すると tmuxscreen などのターミナルマルチプレクサが動作しなくなります。以下のように systemd-run を使ってターミナルマルチプレクサを利用してください:

$ systemd-run --scope --user command args

例えば、screen を実行する場合:

$ systemd-run --scope --user screen -S foo

systemd-run を使うと、ログアウト後も、ユーザがシステム内のどこかで少なくとも 1 回はログインしていて、user@.service がまだ実行されている間だけ、プロセスが実行され続けます。

ユーザがすべてのセッションからログアウトした後、user@.service は、そのユーザが「lingering」を有効にしていない限り、デフォルトで終了します [6]。ユーザーが完全にログアウトしていても、長時間のタスクを効果的に実行できるようにするには、そのユーザーに対してリンガリングを有効にする必要があります。詳しくは #Automatic start-up of systemd user instancesloginctl(1) を参照してください。

トラブルシューティング

ランタイムディレクトリ '/run/user/1000' は、UID1000 によって所有されていません

systemd[1867]: pam_systemd(systemd-user:session): Runtime directory '/run/user/1000' is not owned by UID 1000, as it should.
systemd[1867]: Trying to run as user instance, but $XDG_RUNTIME_DIR is not set

このようなエラーが表示され、ログインセッションが壊れている場合、システム上の別のシステム(ユーザーではない)サービスがこのフォルダを作成している可能性があります。例えば、/run/user/1000 にバインドマウントしている docker コンテナを使用している場合、このようなことが起こる可能性があります。これを解決するには、マウントを削除することでコンテナを修正するか、ドッカーサービスを無効化/遅延させるかのいずれかです。

"A stop job is running for User Manager for UID 1000"

シャットダウン中にこのメッセージが表示される場合、通常は2分のタイムアウトが設定されていることが多いですが、これはユーザーサービスの1つがタイムリーに停止しなかったことを意味します。これには、以前に一時的なサービスを生成した問題のあるアプリケーションが原因である可能性があります。タイムアウトが切れるのを待つこともできますが、これが気になる場合は、問題のあるサービスにオーバーライドを作成するか、すべてのユーザーサービスに対してグローバルタイムアウトを短縮することができます。

問題のあるサービスを特定してオーバーライドする

この問題をトラブルシューティングするために、systemd デバッグシェル を起動します:

systemctl start debug-shell

その後、システムを再起動するかシャットダウンします。問題が発生したときに、Ctrl+Alt+F9 を使用してデバッグシェルに切り替えます。シャットダウンを妨げているサービスを特定するには、次のコマンドを実行します:

systemctl --user list-jobs

ほとんどのオープンソースアプリケーションでは、この問題は該当するメンテナに報告されるべきであり、オーバーライドは必要ありません。しかし、クローズドソースアプリケーションの場合は、次のようにオーバーライドを作成できます:

$ systemctl --user edit --force name@.service 
[Service]
TimeoutStopSec=1s

これにより、その特定のサービスのタイムアウトが1秒に短縮されます。--force パラメータは、一時的なサービスでディスク上に .service ファイルを作成しない場合にのみ必要です。オーバーライドはそれに関係なく機能します。タイムアウトの代わりに KillSignal=SIGKILL を使用することもできます。これにより、ユーザーマネージャが停止したときにサービスが即座に強制終了されます。この方法は、そのサービスがそれを処理できると確信している場合にのみ使用してください。

タイムアウト値の変更

どのサービスがシャットダウンを妨げているか気にしない場合は、次のようにしてすべてのユーザーサービスのグローバルタイムアウトを変更できます:

# systemctl edit user@.service 
[Service]
TimeoutStopSec=10s

このタイムアウト後、優雅に停止していないすべてのユーザーサービスは強制終了されます。これは突然の電源断と同じです。この値は特定の使用ケースに合わせて調整してください。タイムアウトを低すぎる値に設定すると、アプリケーションによってはデータ損失が発生する可能性があります。

参照