4クロックで支度しな

脊髄反射で思ったことを書き垂れます。68060とか名乗っときながら4クロックはヌルいとか言わないで。

Raspberry PiでUSBに繋いだストレージ(USBメモリ・HDD・SSDなど)をマウントするちょっと素敵な方法

きっかけ

Raspberry Pi内のデータをUSBメモリにバックアップしたり、大きいデータを持つためにHDDをつないだりして、USBに複数のストレージデバイスが接続された時に、

  • 各ストレージデバイスを一意に識別する方法
    • 特に、全く同じ機種を複数接続したときに、それぞれを識別する方法
  • 同じデバイスに対して、常に同じやり方でマウントできるようにする方法
    • 特に、挿したUSBポートや、挿した順番とかに依存しない方法

を得たい。
Raspbianでは、/dev がUDEVによって管理されるので、その辺の設定ファイルを書く事で対処できる。

第1章 各デバイスのSERIAL IDが異なる場合

1. USBからストレージデバイスを全部外した状態で、Raspberry Piを起動。

コマンドライン

ls /dev/sd*

で、「sdなんちゃら」(「なんちゃら」の所はアルファベット1文字になる)が出てこないのを確認。

2. 任意のストレージデバイスを1個だけ繋いでみる

コマンドライン

ls /dev/sd*

すると、「sda」とか「sda1」とか出てくるはず。
場合によっては「sdb」とか「sdb1」とかかも。
ここでは「sda」「sda1」として話を進める。

3. マウントしてみて、どのデータを収めたデバイスなのかを確認する

※新品のデバイス2つを新たに接続したい場合とかのように、確認が不要な場合はこの項目は飛ばして下さい。

コマンドライン

sudo mount /dev/sda1 /mnt

とか、

ls /mnt

とかやって、繋いだストレージデバイスがどれなのかを特定する。
確認したら、

sudo umount /dev/sda1

で、デバイスをアンマウントしておく(デバイス内のファイルやディレクトリを開いていたら、閉じておく)。

4. デバイスのIDを調べる

コマンドライン

sudo udevadm info -q all -n /dev/sda

を実行すると、デバイスに関する情報がずらずらと表示される。
必要なのは、

E: ID_SERIAL=

の行。例えば、わたしの環境では、SanDiskUSBメモリを繋いでいるので、

E: ID_SERIAL=SanDisk_Cruzer_Fit_00000000000000000000-0:0

みたいになる(数字の部分は適当に改変してます)。
「=」から右の部分をメモっておくとGOOD。

5. デバイスを外す

普通にUSB端子からズブッと抜いちゃいます。

6. デバイスの固有の名前を考える。

/dev ディレクトリ内に存在しないファイル名にする必要あり。
例えば、

usbmem_backup

とか。

7. UDEVのルールを書く

/etc/udev/rules.d 内に、このデバイスに6.で考えた名前を割り当てるためのルールファイルを書く。
ファイル名の先頭に出来るだけ大きな2桁の数字(99とか)を付ける。例えば、

99-usbmem_backup.rules

とか。
内容は以下を参考に。

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_SERIAL}=="SanDisk_Cruzer_Fit_00000000000000000000-0:0", 
SYMLINK+="usbmem_backup%n"

長いので行を分けているけれど、実際は一行で記述。
個別に変更する必要があるのは、

  • 「ENV{ID_SERIAL}==」の右の部分。4.で調べたID_SERIALを使用。
  • 「SYMLINK+=」の右の部分。6.で考えた名前を使用。
    • ただし、最後に%nを付けておく。これは、デバイス内のパーティションを指すデバイスファイル(例えば「/dev/sda1」とか)も一緒に生成させるために使う。

なおこのディレクトリはパーミッションの問題でrootしか書き込めないので、

  • エディタをsudoで起動し、ファイルを作成する
  • 他の場所にファイルを作成し、sudo cp でファイルをコピーする

のどちらかで対応。

8. 2~7を、接続したいデバイスそれぞれに対し実施する

9. 完了

特にudevを再起動する必要とかはなし。
バイスを挿した時ごとに、/etc/udev/rules.d 内を実行する模様。
あとは /etc/fstab に書くなり、必要なときにmountするなり、ご自由に。

第2章 デバイスが同じSERIAL IDを持つ場合

そんな場合があるのかどうか確かめてはいないが、もしそうであった場合には、各デバイスを識別するには他の方法を使うしかない。
例えば、USBのどのポートに繋いだかという情報を元に設定するとか。

1. USBからストレージデバイスを全部外した状態で、Raspberry Piを起動。

第1章の1.と同じ。

2. 任意のストレージデバイスを1個だけ繋いでみる

第1章の2.と同じ。ただし、デバイスごとに違うUSBポートに接続すること。

3. マウントしてみて、どのデータを収めたデバイスなのかを確認する

第1章の3.と同じ。

4.デバイスの刺さっているUSBポート番号を調べる

第1章と同様に、コマンドライン

sudo udevadm info -q all -n /dev/sda

を実行すると、デバイスに関する情報がずらずらと表示される。
今度は、必要なのは、

E: ID_PATH_TAG=

の行。例えば、わたしの環境では、SanDiskUSBメモリを繋いでいるので、

E: ID_PATH_TAG=platform-bcm2708_usb-usb-0_1_2_1_0-scsi-0_0_0_0

とか、別のポートにつなぐと、

E: ID_PATH_TAG=platform-bcm2708_usb-usb-0_1_3_1_0-scsi-0_0_0_0

「=」から右の部分をメモっておくとGOOD。

5. デバイスを外す

第1章と同じ。

6. デバイスの固有の名前を考える。

第1章と同じ。

7. UDEVのルールを書く

/etc/udev/rules.d 内に、このデバイスに6.で考えた名前を割り当てるためのルールファイルを書く。
ファイル名の先頭に出来るだけ大きな2桁の数字(99とか)を付ける。例えば、

99-usbmem_backup.rules

とか。
内容は以下を参考に。

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_PATH_TAG}=="platform-bcm2708_usb-usb-0_1_2_1_0-scsi-0_0_0_0", 
SYMLINK+="usbmem_backup%n"

長いので行を分けているけれど、実際は一行で記述。
個別に変更する必要があるのは、

  • 「ENV{ID_PATH_TAG}==」の右の部分。4.で調べたID_PATH_TAGを使用。
  • 「SYMLINK+=」の右の部分。6.で考えた名前を使用。
    • ただし、最後に%nを付けておく。これは、デバイス内のパーティションを指すデバイスファイル(例えば「/dev/sda1」とか)も一緒に生成させるために使う。

なおこのディレクトリはパーミッションの問題でrootしか書き込めないので、

  • エディタをsudoで起動し、ファイルを作成する
  • 他の場所にファイルを作成し、sudo cp でファイルをコピーする

のどちらかで対応。

8. 2~7を、接続したいデバイスそれぞれに対し実施する

9. 完了

第1章と同じ。
ただし、USBのポート番号だけで判別している(何が挿さっているか見ていない)ので、実際に運用する場合には挿すUSBのポートを変えないように。
ちなみに、UDEVのルールにはワイルドカードが使えるので、

  • USBのポート2か3に繋いだデバイスに指定の名前を付けたい

というような場合には、例えば

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_PATH_TAG}=="platform-bcm2708_usb-usb-0_1_[23]_1_0-scsi-0_0_0_0", 
SYMLINK+="usbmem_backup%n"

とかやると、USBのポート2か3に接続されたデバイスを、「/dev/usbmem_backup」等の名前にすることが可能。

さらに、

  • USBの特定のポート(複数可)に接続された
  • あるSERIAL IDを持ったデバイ

に対するルールも定義可能。
例えば、

SUBSYSTEM=="block",
ENV{ID_BUS}=="usb",
ENV{ID_PATH_TAG}=="platform-bcm2708_usb-usb-0_1_[23]_1_0-scsi-0_0_0_0", 
ENV{ID_SERIAL}=="SanDisk_Cruzer_Fit_00000000000000000000-0:0", 
SYMLINK+="usbmem_backup%n"

とか書いたら、USBのポート2か3に接続された、指定のSERIAL IDを持つデバイスを「usbmem_backup」等の名前にすることが可能。

最後に

UDEVのルールに書けるワイルドカードは「[]」の他にも、「*」「?」があったり、「%n」の他にも様々な置換文字列が存在するので、デバイス名により凝った名前を付けたい、というような人は「udev 置換文字列」などでググられたし。

2016/11/16 追記

以前Amazonで購入したSanDiskのCruzer Fitの32GBを再度購入してみたところ、
ID_SERIALの内容が微妙に変わっていた(SanDisk_Cruzer_Fit_ 以降の数字の部分)。
同じ製品でもロットによってID_SERIALが異なるケースがあるようなので、
USBメモリの寿命などにより同じものを買い直した場合でも、デバイスの情報を再度取得してみて確認することをオススメする。