OrangePi-PCを使ってみる

Shutdown時に起動するスクリプト

Debiun-Stretchでは電源ジャックの隣の黒いPowerボタンを押すと、Shutdownするようになりました。
そこで、Shutdown時に特定のスクリプトを実行する手順を紹介します。

以下のページを参考にさせていただきました。
http://enakai00.hatenablog.com/entry/20130917/1379374797
https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff

まず最初にShutdown時に実行するスクリプトを作成します。
私はこちらのツールを利用してShutdown時に「ByeBye!!」 をOLEDに表示するスクリプトを作りました。
スクリプトの名前はbye.shとしました。
注意点としてスクリプトの中でsudoを使うときは絶対パス(/usr/bin/sudo)で指定する必要が有ります。
以下のコマンドでスクリプトが存在している絶対パスを取り出しています。
scriptDir=$(cd $(dirname $0) && pwd)
またスクリプトの1行目(シバン)が正しくないと、スクリプトの実行に失敗します。
#!/bin/bash
#set -x

scriptDir=$(cd $(dirname $0) && pwd)
appDir=${scriptDir}/Raspberry-ssd1306
cd ${appDir}
#cd /home/orangepi/Raspberry-ssd1306

./oled r
./oled +2 "ByeBye!!"
./oled P2 5
./oled +R 2

/usr/bin/sudo ./oled s

次に「/etc/systemd/system/bye.service」を以下の内容で作ります。
[Unit]
Description=Clear OLED going to be shutdown
Before=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/home/orangepi/bye.sh
RemainAfterExit=true

[Install]
WantedBy=shutdown.target

このサービスを有効にします。
# サービスの確認
$ sudo systemctl list-unit-files --type=service | grep bye
bye.service                                disabled        enabled

# サービスの有効化
$ sudo systemctl enable bye
Created symlink from /etc/systemd/system/shutdown.target.wants/bye.service to /etc/systemd/system/bye.service.

# サービスの開始
$ sudo systemctl start bye

# サービスの確認
$ sudo systemctl list-unit-files --type=service | grep bye
bye.service                                enabled         enabled

$ sudo systemctl -l --no-pager status bye
● bye.service - Clear OLED going to be shutdown
     Loaded: loaded (/etc/systemd/system/bye.service; enabled; vendor preset: enabled)
     Active: inactive (dead)

電源ジャックの隣の黒いPowerボタンを押すと、OLEDに「ByeBye!!」を表示します。



起動時にデーモンとして開始するスクリプトの登録方法は、色々なところで公開されていますが、
スクリプトの中で自分のIPアドレスを求める場合は、以下の様にする必要が有ります。
「/etc/systemd/system/hello.service」を以下の内容で作ります。
ポイントは「NetworkManager-wait-online.service」を起動の条件とすることです。
これを指定しないと、ネットワークが有効になる前に、スクリプトが起動されてしまいます。
時々、「NetworkManager.service」を起動の条件としている記事を見かけますが、これを起動条件にすると
ネットワーク確立前にサービスが起動してしまい、IPアドレスが取得できません。
このあたりのことは、こちらこち らに詳しい解説が有ります。
[Unit]
Description=Show OLED going to be boot
After=NetworkManager-wait-online.service

[Service]
Type=oneshot
ExecStart=/home/orangepi/me.sh
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

このサービスを有効にします。
# サービスの確認
$ sudo systemctl list-unit-files --type=service | grep hello
hello.service                              disabled        enabled

# サービスの有効化
$ sudo systemctl enable hello
Created symlink from /etc/systemd/system/shutdown.target.wants/hello.service to /etc/systemd/system/hello.service.

# サービスの開始
$ sudo systemctl start hello

# サービスの確認
$ sudo systemctl list-unit-files --type=service | grep hello
hello.service                              enabled         enabled

$ sudo systemctl -l --no-pager status hello
● hello.service - Show OLED going to be boot
   Loaded: loaded (/etc/systemd/system/hello.service; enabled; vendor preset: enabled)
   Active: inactive (dead)

NetworkManager-wait-online.serviceが無効になっているときは、以下の手順で起動しておきます。
$ sudo systemctl list-unit-files --type=service | grep NetworkManager-wait-online.service
NetworkManager-wait-online.service         disabled        enabled

$ sudo systemctl enable NetworkManager-wait-online.service
Created symlink /etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service → /lib/systemd/system/NetworkManager-wait-online.service.

$ sudo systemctl list-unit-files --type=service | grep NetworkManager-wait-online.service
NetworkManager-wait-online.service         enabled         enabled

$ sudo systemctl restart NetworkManager-wait-online.service

$ sudo systemctl -l --no-pager status NetworkManager-wait-online.service
● NetworkManager-wait-online.service - Network Manager Wait Online
   Loaded: loaded (/lib/systemd/system/NetworkManager-wait-online.service; enabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:nm-online(1)

bootメッセージを見てみると、NetworkManager-wait-online.serviceは最後の方で起動していることが分かり ます。
そして、これを起動条件としてhello.servicesが起動していることが分かります。
[  OK  ] Finished Network Manager Wait Online.
[  OK  ] Reached target Network is Online.
         Starting Show OLED going to be boot...
         Starting /etc/rc.local Compatibility...
[  OK  ] Started /etc/rc.local Compatibility.
         Starting Hold until boot process finishes up...
         Starting Terminate Plymouth Boot Screen...

Armbian 23.02.2 Bullseye ttyS0

orangepipc login:

また、以下のコマンドで、起動順番と起動に要した時間を可視化する事ができます。
$ sudo systemd-analyze plot > unitstart.html

結果を見るとNetworkManager-wait-onlineがずっとネットワークの確立を待っていることが分かります。
NetworkManager-wait-onlineの起動完了を待って、幾つかのサービスの起動が始まります。




サービスの起動条件にAfterとRequiresが有ります。
これらは、何が違うのか分かりずらいです。
AfterとRequiresを両方とも指定している例も見受けられます。
こ ちらにずばりの回答が有りました。

After は、ユニットがすでにアクティブ化されているかどうかを確認するだけであり、指定されたユニットを明示的にアクティブ化することはありません。
Requires にリストされているユニットは、ユニットと同時にアクティブ化されます。必要なユニットのいずれかが起動に失敗した場合、そのユニットはアクティブ化され ません。

以下の様に定義すると、test-app は、network-online.target がアクティブになった後にのみ開始されます。
network-online.target が開始されていない場合は、test-app は待機します。
[Unit]
Description=test-app
After=network-online.target

以下の様に定義すると、network-online.target と test-app は一緒にアクティブ化されます
network-online.target の起動に失敗すると、test-app はアクティブ化されません。
[Unit]
Description=test-app
Requires=network-online.target



サービスの登録方法は、色々なところで公開されています。
ほとんどのサンプルがExecStartにシェルスクリプトを登録していますが、簡単なスクリプトであれば、ExecStartPreを使うこと ができま す。
こ ちらにサンプルが公開されていますが、ExecStartPreは複数定義することが出来て、上から順番に実行されます。

また、ExecStartPreやExecStartで実行するコマンドの中で、リダイレクトやファイルのワイルドカードを使うときは、
シェル経由でコマンドを実行する必要が有ります。
リダイレクトやファイルのワイルドカードの展開はシェルの機能です。
以下は、シャットダウン時にrosノードの最新ログを退避するサービスで、リダイレクトとファイルのワイルドカードを使っています。
[Unit]
Description=Save latest node logging
Before=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStartPre=mkdir -p /home/nop/latest_node_log
ExecStartPre=/bin/bash -c 'rm /home/nop/latest_node_log/*'
ExecStartPre=/bin/bash -c 'cp /home/nop/.ros/log/latest/* /home/nop/latest_node_log/'
ExecStart=/bin/bash -c 'date > /home/nop/latest_node_log/date.txt'
RemainAfterExit=true

[Install]
WantedBy=shutdown.target



サービスのUnitファイルを変更した時に、reloadを行うように書かれているサイトと、restartを行うように書かれているサイトが有 ります。
こ ちらにその違いが公開されています。
結論だけを引用させて頂きます。
reloadは設定ファイルの再読み込みがだめでもactiveのままだが、
restartは設定ファイルの再読み込みが正しく出来なかったら起動しない。
restartを使うのが正解みたいです。

systemctlのオプションは色々なところで紹介されていますが、こ こが一番詳しいように思います。
catオプションやlist-dependenciesオプションは、なかなか見つからないオプションです。

次回はUSB-Wifiのセットアップを紹介します。