皆さん、
動的デバイス管理ツールudev
udevとはsystemdの別名です。
すみません、
udevは具体的には次のような流れでデバイスを認識し、
- カーネルが追加・
削除されたデバイスを認識する - ueventによってudevに変更内容が通知される
- udevは通知された内容をもとに事前に設定されたルールに従って処理する
たとえばPCIやUSB、
udev自身がルールに従って主体的に情報を収集し、
- 適切なモジュールの自動ロード
- ストレージ接続・
切断時のマウント・ アンマウント - 各種デバイスファイルの権限の変更
- デバイス認識に伴うスクリプトの実行
- デバイスファイルやシンボリックリンクの作成
- サービスの起動・
停止
特に任意のファイル名やシンボリックリンクの作成は、
udevのルールと変更方法
udevがインストールされたシステムにおいて、
udevのルールファイルは以下のいずれかのディレクトリに保存されています。
- /etc/
udev/ rules. d:システムの管理者が作成・ 変更することを想定したルールファイルの保存場所 - /run/
udev/ rules. d:一時的に作成されるルールファイルの保存場所 - /lib/
udev/ rules. d:パッケージ等システムが提供するルールファイルの保存場所
上記ディレクトリのうち
複数のディレクトリで同じファイル名だった場合は、
モジュール自動ロードのルールファイル
具体的なルールファイルの中身を見てみましょう。
# do not edit this file, it will be overwritten on update
ACTION!="add", GOTO="drivers_end"
ENV{MODALIAS}=="?*", RUN{builtin}+="kmod load $env{MODALIAS}"
SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", RUN{builtin}+="kmod load tifm_sd"
SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", RUN{builtin}+="kmod load tifm_ms"
SUBSYSTEM=="memstick", RUN{builtin}+="kmod load ms_block mspro_block"
SUBSYSTEM=="i2o", RUN{builtin}+="kmod load i2o_block"
SUBSYSTEM=="module", KERNEL=="parport_pc", RUN{builtin}+="kmod load ppdev"
KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", RUN{builtin}+="kmod load sm_ftl"
LABEL="drivers_end"
ルールファイルはキーバリューの変数をベースにした判定システムです。変数にはカーネルからueventと渡されるものだけでなく、
変数には
ルールは1行ずつ処理されていきます。上記ファイルの内容を順番に見ていきましょう。
ACTIONとGOTO変数
ACTION!="add", GOTO="drivers_end"
上記は
「ACTION」
- add:デバイスの追加
- remove:デバイスの除去
- change:デバイスの状態変更
- move:デバイスの親子関係や名前の変更
- online:デバイスがオンラインになった
- offline:デバイスがオフラインになった
- bind:ドライバーとデバイスが紐付けられた
- unbind:ドライバーとデバイスの関連付けを切断
大抵のルールはaddとremoveのみを考慮しています。それ以外については必要になったときに調べると良いでしょう。
「GOTO」
ENVとRUN変数
前項のACTIONとGOTOのおかげで、
ENV{MODALIAS}=="?*", RUN{builtin}+="kmod load $env{MODALIAS}"
ENVはカーネルドライバーの中や他のルールで設定されるデバイスプロパティです。連想配列的にアクセス可能なので、
RUNは追加したコマンドを実行する変数です。
「builtin」
変数の値の中で他の変数を参照できます。上記の例だと
MODALIASには
SUBSYSTEMとKERNEL、LABEL変数
ここまでの基本をおさえておくと、
SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", RUN{builtin}+="kmod load tifm_sd"
SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", RUN{builtin}+="kmod load tifm_ms"
SUBSYSTEM=="memstick", RUN{builtin}+="kmod load ms_block mspro_block"
SUBSYSTEM=="i2o", RUN{builtin}+="kmod load i2o_block"
SUBSYSTEM=="module", KERNEL=="parport_pc", RUN{builtin}+="kmod load ppdev"
KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", RUN{builtin}+="kmod load sm_ftl"
SUBSYSTEMはそのデバイスが所属しているサブシステムです。
「i2o」
「module」
SUBSYSTEM変数とは別にSUBSYSTEMS変数もあります。後者の変数には、
ファイルの最後はLABEL変数です。GOTOはLABEL変数がセットされている値と一致する場所までジャンプします。
LABEL="drivers_end"
アクセス権の変更
udevでルールを記述する場合の代表的な例がアクセス権限の変更です。
USBなどのデバイスをホットプラグしたものの、
たとえばUSBシリアルコンソールデバイスを接続したときを考えてみましょう。一般的なUSBシリアルコンソールデバイスなら接続すると同時に
$ ls -l /dev/ttyUSB0 crw-rw---- 1 root dialout 188, 0 2月 3 19:48 /dev/ttyUSB0
そして一般ユーザーは、
$ sudo adduser $USER dialout
ちなみにグループ変更の設定を反映するためには、
さて、
ACTION=="remove", GOTO="serial_end"
SUBSYSTEM!="tty", GOTO="serial_end"
SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb"
SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}"
SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACE_NUM}="$attr{bInterfaceNumber}"
LABEL="serial_end"
最初の2行からこのルールは切断されたとき以外でなおかつサブシステムがttyのときのみ適用されることがわかります。またusbサブシステムやusb-serialサブシステムの下に接続されている場合は、
ポイントはIMPORT{builtin}
」
hwdbはもう少し複雑です。実はシステム上には
ちなみに次のようにsysfs上のパスを指定することで、
$ udevadm test-builtin usb_id /sys/class/tty/ttyUSB0 calling: test-builtin Load module index Parsed configuration file /lib/systemd/network/99-default.link Created link configuration context. /sys/devices/pci0000:00/0000:00:14.0/usb3/3-1/3-1:1.0: if_class 255 protocol 0 ID_VENDOR=FTDI ID_VENDOR_ENC=FTDI ID_VENDOR_ID=0403 ID_MODEL=TTL232R-3V3 ID_MODEL_ENC=TTL232R-3V3 ID_MODEL_ID=6001 ID_REVISION=0600 ID_SERIAL=FTDI_TTL232R-3V3_FTGC0U6E ID_SERIAL_SHORT=FTGC0U6E ID_TYPE=generic ID_BUS=usb ID_USB_INTERFACES=:ffffff: ID_USB_INTERFACE_NUM=00 ID_USB_DRIVER=ftdi_sio Unload module index Unloaded link configuration context.
さてシリアルコンソールデバイスに関する諸々の設定は
- OWNER:所有者の設定
- GROUP:所有グループの設定
- MODE:パーミッションの設定
上記3つをどう設定するかはケースバイケースでしょう。よく例としてあがるのが、
そういえば前に出力していた/dev/
SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666"
SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666"
SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="tty", KERNEL=="sclp_line[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="tty", KERNEL=="ttysclp[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="tty", KERNEL=="3270/tty[0-9]*", GROUP="tty", MODE="0620"
SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty"
KERNEL=="tty[A-Z]*[0-9]|ttymxc[0-9]*|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"
この最後の行が効いていたために、
設定例はいくつかあります。まずシンプルにカーネル上のファイル名に合わせて一括変換する方法です。
ACTION=="remove", GOTO="serial_end"
SUBSYSTEM!="tty", GOTO="serial_end"
KERNEL=="ttyUSB[0-9]*", MODE="0666"
LABEL="serial_end"
ttyUSBxすべてではなく、
ACTION=="remove", GOTO="serial_end"
SUBSYSTEM!="tty", GOTO="serial_end"
ENV{ID_VENDOR_ID}=="0403", ENV{ID_MODEL_ID}=="6001", MODE="0666"
LABEL="serial_end"
上記ではベンダーIDとモデルIDで絞っています。これらの値はたとえばlsusbなどで確認できます。
$ lsusb (中略) Bus 003 Device 004: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
FTDIのチップが載った一般的なUSBシリアルコンソールケーブルです。ルールを追加したら、
$ sudo udevadm control --reload
さらにUSBシリアルコンソールを接続し直しましょう。
$ ls -l /dev/ttyUSB0 crw-rw-rw- 1 root dialout 188, 0 2月 3 20:11 /dev/ttyUSB0
これでシリアルコンソールを使うために、
デバイスに対するシンボリックリンクの追加
もう一つの例が、
「/dev」
ポイントは
そこで必要になるのが起動ごとに固有の名前になる
- enp0s25:Ethernet
(en)、 PCIのBus 0、 Slot 25 (p0s25) - enx001de1570857:Ethernet
(en)、 MACアドレス (xMACADDR) - wlp3s0:Wireless LAN
(wl)、 PCIのBus 3、 Slot 0 (p3s0)
他にもACPIテーブル上にデバイスインデックスが付いていたら
実はすでに既存のルールで、
$ ls -l /dev/serial/by-id/ lrwxrwxrwx 1 root root 13 2月 3 20:11 usb-FTDI_TTL232R-3V3_FTGC0U6E-if00-port0 -> ../../ttyUSB0 $ ls -l /dev/serial/by-path/ lrwxrwxrwx 1 root root 13 2月 3 20:11 pci-0000:00:14.0-usb-0:1:1.0-port0 -> ../../ttyUSB0
ただし若干長いですね。そこで
ACTION=="remove", GOTO="serial_end"
SUBSYSTEM!="tty", GOTO="serial_end"
ENV{ID_VENDOR_ID}=="0403", ENV{ID_MODEL_ID}=="6001", MODE="0666", SYMLINK+="ftdi"
LABEL="serial_end"
SYMLINK変数にパス名を追加すると、
設定をリロードした上で、
$ ls -l /dev/ftdi lrwxrwxrwx 1 root root 7 2月 3 20:21 /dev/ftdi -> ttyUSB0
さらにデバイスを取り外すと、
このようにudevのルールファイルを書けば、