Systemd: シャットダウン時にのみスクリプトを実行する方法(再起動時には実行しない)

Systemd: シャットダウン時にのみスクリプトを実行する方法(再起動時には実行しない)

シャットダウン/再起動時にスクリプトを実行するための解決策はたくさんありますが、私はスクリプトをシャットダウン時にのみ実行したいのです。

私はスクリプトを/usr/lib/systemd/systemd-shutdownに配置し、$1パラメータをチェックしてみました。ここですが、動作しません。

何か案は ?

システム: archlinux と gnome-shell

$systemctl --version                                                                                                                                                                                 
systemd 229
+PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN

答え1

ついにそのやり方を見つけました。

ちょっとハックっぽい考えですが、機能します。

このスレッドの一部を使用しました:https://stackoverflow.com/questions/25166085/how-can-a-systemd-controlled-service-distinguish-between-shutdown-and-reboot

そしてこのスレッド: シャットダウン直前に systemd でスクリプトを実行するにはどうすればいいですか?

私はこのサービスを作りました/etc/systemd/system/shutdown_screen.service

[Unit]
Description=runs only upon shutdown
Conflicts=reboot.target
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/bin/bash /usr/local/bin/shutdown_screen
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

これは、シャットダウン/再起動/停止/その他あらゆる場合に実行されます。(有効にすることを忘れないでください)

そして私のスクリプトには/usr/local/bin/shutdown_screen 次の内容を入れました:

#!/bin/bash
# send a shutdown message only at shutdown (not at reboot)    
/usr/bin/systemctl list-jobs | egrep -q 'reboot.target.*start' || echo "shutdown" | nc 192.168.0.180 4243 -w 1

これにより、Arduino にシャットダウン メッセージが送信され、Arduino が画面をシャットダウンします。

答え2

man ページによればsystemd.special、 を使用する必要がありますBefore=poweroff.target

電源オフターゲット

A special target unit for shutting down and powering off the system.

Applications wanting to power off the system should start this unit.

runlevel0.target is an alias for this target unit, for compatibility with SysV.

さらに、コメントで述べたように、カスタム スクリプトは に配置する必要があります/etc/systemd/system/。この/usr/lib/systemd/system/ディレクトリは、システム提供のスクリプト用に使用することを目的としています。

つまり、次のような感じでしょうか:

[Unit]
Description=runs only upon shutdown
DefaultDependencies=no
Conflicts=reboot.target
Before=shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/usr/local/bin/yourscript
RemainAfterExit=yes

答え3

ここでの回答を読むと、systemd の動作について多くの誤解があるようです。まず、ターゲットを除外するために競合を使用しないでください。競合するサービスが同時に実行されないようにするためのものです。

あるユニットに別のユニットの Conflicts= 設定がある場合、前者を起動すると後者は停止し、その逆も同様です。

ユニットとは、到達すべきターゲットではなく、特定のサービスを起動するための .service ファイルを意味します。言い換えると、Conflicts=reboot.target良くても意味がなく、最悪の場合、再起動を妨げることになります。これを行わないでください。再起動時にこれを実行しないという意味ではありません。タイミングと、systemd がこの誤った競合の使用をどのように解釈するかに応じて、このサービスまたは reboot.target のいずれかを中止することを意味します。

以下は、再起動時ではなくシャットダウン時にのみ実行される、現在設定されているユニット (別名 .service ファイル) の例です。

[Unit]
Description=Play sound
DefaultDependencies=no
Before=poweroff.target halt.target

[Service]
ExecStart=/usr/local/bin/playsound.sh
ExecStop=/usr/local/bin/playsound.sh
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=poweroff.target halt.target 

poweroff.target は、シャットダウン時にのみ到達する古い systemv 実行レベル 0 に相当します。halt.target は、systemd によって使用される代替シャットダウン パスであり、これも再起動では到達できません。install セクションは、systemd に、このサービスを、完了する必要があるpoweroff.targetか、halt.target到達したと見なされるリストに追加するよう指示します。

このサービスは私のシステムにインストールされ、実行されています。

答え4

私はここやさまざまなサイトでほとんどの投稿をテストしました。実際に再起動時にのみ実行できた唯一の投稿は、@benoit2600 の投稿です (再起動時には実行されませんが、シャットダウン、停止、電源オフのときに実際に失敗しました)。彼の 2 番目の/解決策の投稿です。

しかし、テストした後、ユニットで 4 つのターゲットすべてを使用でき、そのうちの 1 つが実際に使用された場合にのみ実行されることがわかりました。残りは必要に応じて変更します。「ExecStop=mycommand」では、直接コマンドを入力しました (完全な bash は必要なかったため)

[Unit]
Conflicts=reboot.target poweroff.target halt.target shutdown.target

関連情報