torutkのブログ

ソフトウェア・エンジニアのブログ

[Linux]USBメモリの着脱を検出する方法

Linuxで、USBメモリが挿されたことを検出して処理を実行したく、調べてみました。

  1. GNOMEが立ち上がっていると自動でマウントするので、マウントポイント(一般的には/media/disk)をポーリングする
  2. dmesgのログを解析する(/var/log/messagesに出されるkernelログあたりか)
  3. hotplugを使ってUSBメモリ挿入を検出
  4. dbusを使ってUSBメモリ挿入を検出

といった方法がありそうです。

ここで、1, 2,は周期的にポーリングするのでちょっと避けたい。
3.は簡単そうだったが、今後はdbusに一元化されるようなので、4.の方法が本命かな。とりあえず、dbus-monitorというコマンドがあるので、実行してからUSBを挿抜して調べます。

$ dbus-monitor --system
    :
signal sender=:1.0 -> dest=(null destination) path=/org/freedesktop/Hal/Manager; interface=org.freedesktop.Hal.Manager; member=DeviceAdded
   string "/org/freedesktop/Hal/device/usb_device_XXX_XX_XXXXXXXXX"
    :

USBメモリを挿入すると、interface="org.freedesktop.Hal.Manager; member=DeviceAddedのDBusメッセージが複数回発生します。違いは、stringの内容です。

usb_device_XXX_XX_XXXXXXXXXX
usb_device_XXX_XX_XXXXXXXXXX_if0
usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host
usb_device_XXX_XX_XXXXXXXXXX_usbraw
usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host_scsi_device_lun0
usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host_scsi_device_lun0_scsi_generic
storage_serial_NNNN_XXXXXXXXXX
volume_uuid_UUUU_UUUU

USBメモリは、SCSIバイスを模擬するので、USBデバイスとしての認識後、SCSIとしての設定が行われて、storageとして認識されたあとに、diskとして認識されるという流れのようです。
ちなみに、ここで、/dev/disk/by-uuidディレクトリを見ると、

$ ls -l /dev/disk/by-uuid
UUUU-UUUU -> ../../sda1
    :

のように、DBusのメッセージで流れたvolume_uuid_UUUU_UUUUの部分と同じIDでデバイスファイル(へのシンボリックリンク)が作成されていました。

なお、XXXXやNNNN、UUUUは、メモリ個別にIDや名称が入ります。

ここで、GNOMEデスクトップを起動し、GNOMEによるUSBメモリの自動マウントが発生したときのdbus-monitor出力を見ると、以下のメッセージが関連していそうです。

signal sender=:1.0 -> dest=(null destination) path=/org/freedesktop/Hal/Devices/volume_uuid_UUUU_UUUU; interface=org.freedesktop.Hal.Device; member=PropertyModified
   int32 2
   array [
      struct {
         string "volume.mount_point"
         boolean false
         boolean false
      }
      struct {
         string "volume.is_mounted"
         boolean false
         boolean false
      }
   ]


ちなみに、GNOME上でアンマウント操作をすると、

signal sender=:1.0 -> dest=(null destination) path=/org/freedesktop/Hal/devices/volume_uuid_UUUU_UUUU; interface=org.freedesktop.Hal.Device; member=PropertyModified
   int32 2
   array [
      struct {
         string "volume.mount_point"
         boolean false
         boolean false
      }
      struct {
         string "volume.is_mounted"
         boolean false
         boolean false
      }
   ]

USBメモリを抜くと、

signal sender=:1.0 -> dest=(null destination) path=/org/freedesktop/Hal/Manager; interface=org.freedesktop.Hal.Manager; member=DeviceRemoved
   string "/org/freedesktop/Hal/devices/usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host_scsi_device_lun0_scsi_generic"
   :

と、member=DeviceRemovedとしてあとは同様のメッセージが流れます。

usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host_scsi_device_lun0_scsi_generic
volume_uuid_UUUU_UUUU
usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host_scsi_device_lun0
storage_serial_NNNN_XXXXXXXXXX
usb_device_XXX_XX_XXXXXXXXXX_if0
usb_device_XXX_XX_XXXXXXXXXX
usb_device_XXX_XX_XXXXXXXXXX_usbraw
usb_device_XXX_XX_XXXXXXXXXX_if0_scsi_host