Raspberry Pi 3 のshutdown時に自動で外付けHDDを停止させる


目的

Raspberry Pi 3 ModelB で外付けHDDを停止してから終了(shutdownなど)させるようにしたい1
(そうしないとキュイーン?みたいな異音が鳴りつつ終了してしまうので・・)

環境

Raspberry Pi 3 ModelB

作業メモ

外付けHDDの動作を止める

ちなみに外付けHDDのマウント方法については、こちらの投稿を参照

参考サイト
https://linux.die.net/man/8/sdparm

  • コマンドのインストール
$ sudo apt-get install sdparm
  • 外付けHDDを動作停止

fdiskコマンドなどでHDDのブロックデバイスを調べて停止させてみる

$ sudo fdisk -l
(略)
Device     Boot Start        End    Sectors   Size Id Type
/dev/sda1        2048 1953520064 1953518017 931.5G  7 HPFS/NTFS/exFAT
$ sudo sdparm --command=stop /dev/sda1
  • rebootしてみる
$ sudo reboot

効果なし・・。終了時に異音がする

USBポートの電源OFF

もっと根本的なところに立ち返って、USBポートの電源OFFを試してみる

参考サイト
http://s.webry.info/sp/vogel.at.webry.info/201711/article_2.html

  • hub-ctrlのインストール
$ sudo apt-get install libusb-dev
$ wget http://www.gniibe.org/oitoite/ac-power-control-by-USB-hub/hub-ctrl.c
$ gcc -O2 hub-ctrl.c -o hub-ctrl-armhf-static -lusb -static
$ sudo mv hub-ctrl-armhf-static /usr/local/bin/hub-ctrl
  • BUSやPORTの番号を調べる2
$ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=smsc95xx, 480M
        |__ Port 5: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 480M

分かりづらい場合はこちらで調べる

$ udevadm info --query=path --name=/dev/sda1
/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.5/1-1.5:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1

--name=pathpathは調べたいブロックデバイス名
1-1.5が該当箇所になる

  • デバイスの取り外しをする
$ echo -n "1-1.5" | sudo tee /sys/bus/usb/drivers/usb/unbind

確認すると、以下が無くなっており取り外されたことが分かる

Port 5: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 480M

$ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/5p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=smsc95xx, 480M
  • 該当ポートの電源OFF
$ sudo hub-ctrl -b 1 -d 2 -P 5 -p 0

-bがBUS、-dがDevice、-PがPORTの数字を入れる
-pは0がOFF、1がON

  • rebootしてみる
$ sudo reboot

効果あり!終了時の異音がなくなった

Serviceとして登録する

これで目的達成でもいいが、このままだと毎回手動で処理しないといけないので、システムのサービスとして登録してみる

参考サイト
https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff

  • initがどの仕組みで動いているか確認

initは起動/終了処理を司るプロセスで、ディストリビューションやバージョンによって使われている仕組みが違うらしい(あまり詳しくない)
そのため、どの仕組みで動いているか確認する

$ ps -aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.6  27096  6128 ?        Ss    4月20   0:03 /sbin/init splash
(略)
$ ls -l /sbin/init
lrwxrwxrwx 1 root root 20  7月  6  2017 /sbin/init -> /lib/systemd/systemd

どうやらsystemdという仕組みで動いているらしい

  • サービスの作成

参考サイトの内容を見ると、今回やりたいことからすると、**.serviceというサービスを作って、それが終了時に呼ばれるようにすればよさそうだと分かった

まず、hdd_off.serviceについては以下のようにした

hdd_off.service
[Unit]
Description=hdd off for shutdown and reboot
Before=shutdown.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/usr/bin/hdd_off.sh
RemainAfterExit=true

[Install]
WantedBy=shutdown.target

ざっくり説明すると、shutdown/reboot/halt時に1度だけ外付けHDDの電源をOFFする、ようにした

以下、ちゃんとした説明
shutdown.targetがshutdown/reboot/halt全てのタイミングで関連づけられているため、このtargetが呼ばれる時に実行する設定にした

Before=shutdown.target
WantedBy=shutdown.target

外付けHDDの電源をOFFするスクリプトを作り、サービス起動時に実行するようにする

ExecStart=/usr/bin/hdd_off.sh

ちなみにスクリプトhdd_off.shについては長くなるので、内容の記載は割愛する

  • 作成したファイルの配置

ファイルの権限などを変更して

$ sudo chown root:root hdd_off.sh
$ sudo chown root:root hdd_off.service
$ sudo chmod +x /usr/bin/hdd_off.sh

必要な場所に配置する
どうやらユーザー設定のサービスは/etc/systemd/systemに置くのがお作法らしい

$ sudo mv hdd_off.sh /usr/bin/
$ sudo mv hdd_off.service /etc/systemd/system/
  • サービスとして認識されているか確認
$ sudo systemctl list-unit-files --type=service | grep hdd_off
hdd_off.service                        disabled

サービスとして認識されていればいいので、disabledでOK

  • 動作確認
$ sudo systemctl start hdd_off
$ sudo systemctl stop hdd_off

ちなみにサービスの動作確認だけが目的だったので、外付けHDD未接続の状態で試した

$ sudo systemctl status hdd_off
● hdd_off.service - hdd off for shutdown and reboot
   Loaded: loaded (/etc/systemd/system/hdd_off.service; disabled; vendor preset: enabled)
   Active: inactive (dead)

 4月 21 10:44:26 raspberrypi systemd[1]: Starting hdd off for shutdown and reboot...
 4月 21 10:44:26 raspberrypi sudo[1201]:     root : TTY=unknown ; PWD=/ ; USER=root ; COMMAND=/sbin/blkid
 4月 21 10:44:26 raspberrypi sudo[1201]: pam_unix(sudo:session): session opened for user root by (uid=0)
 4月 21 10:44:26 raspberrypi sudo[1201]: pam_unix(sudo:session): session closed for user root
 4月 21 10:44:26 raspberrypi hdd_off.sh[1199]: HDD is nothing
 4月 21 10:44:26 raspberrypi systemd[1]: Started hdd off for shutdown and reboot.
 4月 21 10:44:29 raspberrypi systemd[1]: Stopped hdd off for shutdown and reboot.

ログを確認すると、hdd_off.shが実行され、HDD未接続時のログが出ているのでOK

4月 21 10:44:26 raspberrypi hdd_off.sh[1199]: HDD is nothing

  • サービスの有効化
$ sudo systemctl enable hdd_off
Created symlink /etc/systemd/system/shutdown.target.wants/hdd_off.service → /etc/systemd/system/hdd_off.service.
  • 自動で外付けHDDの電源がOFFになってくれるか確認
$ sudo reboot

いい感じで電源OFFでrebootしたように見える!
一応ログで確認したいので、syslogの出力を確認してみる

$ less /var/log/messages

が、それとわかるようなログは見当たらなかった
どうやらsystemdのログはsyslogには出力されないらしい?
この辺はよく分からないので、調査が必要

まとめ

目的は達成!のはず

Raspberry Pi 3 ModelB で外付けHDDを停止してから終了(shutdownなど)させるようにしたい

終了時にHDDからの異音はなくなったが、ログでそれが確認できなかった。
その点は課題として残っている



  1. ぶっちゃけるとumountしてshutdownすればいいだろうと思っていたのだが、そんな簡単じゃなかったので、まじめに方法を考える羽目になりました 

  2. udevadmで調べたときに、1-1.2に接続されているとうまく電源OFFできなかった。理由は不明