Udev の紹介: デバイス イベントを管理する Linux サブシステム

Udev は、コンピューターにデバイス イベントを供給する Linux サブシステムです。 わかりやすく言うと、ネットワーク カード、外付けハード ドライブ (USB メモリを含む)、マウス、キーボード、ジョイスティック、ゲームパッド、DVD-ROM ドライブなど、コンピュータに接続されているものを検出するコードです。 そのため、udev は潜在的に有用なユーティリティであり、標準的なユーザーであれば、特定のハード ドライブが接続されたときに特定のタスクを実行するようなスクリプトを手動で作成できるほど、十分に公開されています。 udev で作業するプロセスを理解すると、ゲームパッドが接続されたときに特定のドライバーをロードしたり、バックアップドライブを接続したときに自動バックアップを実行するなど、あらゆることを行うために使用することができます。 スクリプトの目標にもよりますが、スクリプトの結果を自分の目で見ることができるとは限りませんので、スクリプトが正常にトリガーされたことをログに記録するようにしてください。 ログファイルの通常の場所は/varディレクトリですが、これはほとんどrootユーザの領域です。

お気に入りのテキストエディタを開き、この単純なスクリプトを入力します:

#!/usr/bin/bash
/usr/bin/date >> /tmp/udev.log

これを /usr/local/bin またはデフォルトの実行可能パスにあるその他の場所に配置します。 trigger.shと呼び、もちろんchmod +xで実行可能にしてください。

$ sudo mv trigger.sh /usr/local/bin
$ sudo chmod +x /usr/local/bin/trigger.sh

このスクリプトはudevとは何の関係もありません。 実行されると、このスクリプトは /tmp/udev.log ファイルにタイムスタンプを記録します。

$ /usr/local/bin/trigger.sh
$ cat /tmp/udev.log
Tue Oct 31 01:05:28 NZDT 2035

次のステップは、udev がスクリプトをトリガーするようにします。

独自のデバイス識別

デバイスイベントによってスクリプトをトリガーするために、udev はどの条件でスクリプトを呼び出すべきかを知っていなければなりません。 実際の生活では、色、メーカー、およびコンピュータに接続したという事実によってサムドライブを識別することができます。 しかし、コンピューターには別の基準が必要です。

Udev は、シリアル番号、メーカー、さらにはベンダー ID や製品 ID 番号によってデバイスを識別します。 これは、udev スクリプトの寿命の初期段階であるため、できるだけ広く、非特異的で、すべてを含むようにする必要があります。 言い換えれば、スクリプトを起動するために、ほぼすべての有効な udev イベントを最初にキャッチしたいのです。

udevadm monitor コマンドを使用すると、リアルタイムで udev にアクセスし、異なるデバイスを接続したときに何が見えるかを確認することができます。

$ su
# udevadm monitor

Monitor 機能は以下の受信イベントを表示します。

  • UDEV: udev がルール処理の後に送るイベント
  • KERNEL: カーネルの uevent

udevadm monitor が起動しているので、サムドライブに接続して画面にいろいろと情報が吹き出すのを見てみてください。 イベントの種類がADDイベントであることに注目してください。

udevadm monitor コマンドは多くの良い情報を提供しますが、サムドライブが現在 /dev ツリーのどこに位置しているかがわかっていれば、udevadm info コマンドでよりきれいなフォーマットで見ることができます。 そうでない場合は、サム・ドライブを抜いて挿し直し、すぐに次のコマンドを実行します。

$ su -c 'dmesg | tail | fgrep -i sd*'

たとえば、このコマンドが sdb: sdb1 を返したら、カーネルがサム・ドライブに sdb のラベルを割り当てていることが分かります。

別の方法として、lsblk コマンドを使用して、システムに接続されているすべてのドライブ、そのサイズとパーティションを確認することができます。

あなたの仕事は、デバイスに関するudevのレポートのうち、そのデバイスに最も固有な部分を選び出し、それらの固有属性が検出されたときにスクリプトを起動するようにudevに伝えることです。

udevadm情報プロセスは、デバイスについてレポート(デバイスパスで指定)し、親デバイスを「歩いて」上ります。 見つかったすべてのデバイスについて、キー-バリュー形式を使用して、可能なすべての属性を表示します。 デバイスの属性と単一の親デバイスからの属性に従ってマッチングするルールを構成することができます。

looking at device '/devices/000:000/blah/blah//block/sdb':
KERNEL=="sdb"
SUBSYSTEM=="block"
DRIVER==""
ATTR{ro}=="0"
ATTR{size}=="125722368"
ATTR{stat}==" 2765 1537 5393"
ATTR{range}=="16"
ATTR{discard\_alignment}=="0"
ATTR{removable}=="1"
ATTR{blah}=="blah"

udev ルールは、単一の親デバイスからの 1 つの属性を含まなければなりません。

親属性とは、物理ポートに接続されたもの、サイズを持つもの、リムーバブル デバイスであるなど、最も基本的なレベルからデバイスを説明するものです。 しかし、コンセプトの証明としては機能するので、それを使うこともできます。 さらに良い候補は SUBSYSTEM 属性で、これが「ブロック」システム デバイスであることを識別します (そのため、lsblk コマンドはデバイスを一覧表示します)。

/etc/udev/rules.

SUBSYSTEM=="block", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

ファイルを保存し、テスト用 USB ドライブを抜いて、再起動します。 Udev は十分に複雑で、一晩中ベッドに横になりながら、あのルールは構文エラーでうまくいかなかったのか、それとも単に再起動すべきだったのか、などと考えていたくはないでしょう。 POSIX のプライドがどうであろうと、再起動するのです。

システムがオンラインに戻ったら、テキストコンソール (Ctl+Alt+F3 など) に切り替え、サムドライブを接続してください。 最近のカーネルを使用している場合、ドライブを差し込むとコンソールにたくさんの出力が表示されることでしょう。 Could not execute /usr/local/bin/trigger.sh のようなエラーメッセージが表示された場合、おそらくスクリプトを実行可能にするのを忘れているのでしょう。

Now, the moment of truth:

$ cat /tmp/udev.log
Tue Oct 31 01:35:28 NZDT 2035

/tmp/udev.log から返された非常に新しい日付と時間が表示されたら、udev は正常にトリガーされました。 マウス、サム ドライブ、または他の人のサム ドライブを接続すると、無差別にスクリプトがトリガーされます。 今こそ、スクリプトをトリガーする正確なサム ドライブに焦点を当て始める時です。

これを行う方法の 1 つは、ベンダー ID と製品 ID を使用することです。 これらの番号を取得するには、lsusb コマンドを使用します。

$ lsusb
Bus 001 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 002 Device 002: ID 8087:0024 Slacker Corp. Hub
Bus 003 Device 005: ID 03f0:3307 TyCoon Corp.
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 hub
Bus 001 Device 003: ID 13d3:5165 SBo Networks

この例では、TyCoon Corp. の前の 03f0:3307 が idVendor および idProduct 属性を示しています。 これらの数字は udevadm info -a -n /dev/sdb | grep vendor の出力でも確認できますが、私は lsusb の出力の方が少し見やすいと思います。

SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/thumb.sh"

これをテストすると (そう、udev から新鮮な反応が得られることを確認するために、まだ再起動するべきです)、以前と同様に動作するはずですが、別の会社で製造された (従って別の idVendor の) サム ドライブやマウス、プリンタを接続すると、スクリプトがトリガーされません。 udevadm info -a -n /dev/sdb を使用すると、ベンダー名、シリアル番号、製品名などを確認することができます。 私が犯したほとんどの間違い (そして、オンラインで他の人が犯すのを見た) は、udev ルールにたくさんの属性を投げ込んで、なぜ動作しなくなったかを考えることです。 属性を 1 つずつテストすることが、udev がデバイスを正常に識別する最も安全な方法です。

セキュリティ

ここで、ドライブが接続されたときに自動的に何かを行うよう udev ルールを記述する際のセキュリティ上の懸念が浮かび上がりました。 私のマシンでは、自動マウントもオンにしていないのに、この記事では、何かが接続されただけでコマンドを実行するスクリプトやルールを提案しています。

  1. udev ルールが動作したら、本当に必要なときにだけスクリプトを起動するよう焦点を合わせます。 コンピュータとの間でやみくもにデータをコピーするようなスクリプトを実行することは、同じブランドのサムドライブを持ち歩いている人がそれをあなたのコンピュータに差し込んだ場合に、悪い考えです。 私は、どのコンピューターに私の udev ルールがあるか知っていますし、それらのボックスは、ほとんどの場合、私の個人的なコンピューターであり、会議に持ち運ぶコンピューターや職場のオフィスにあるものではありません。 コンピュータがより「社会的」であればあるほど、 私のデータが他の誰かのデバイスで終わってしまったり、 他の誰かのデータやマルウェアが私のデバイスにあったりするような udev ルールが適用される可能性は低くなります。

    Udev in the real world

    udev によってスクリプトがトリガーされることを確認できたので、スクリプトの機能に注意を向けることができるようになりました。 今は、実行されたという事実をログに記録するだけで、何の役にも立ちません。

    私は、親指ドライブの自動バックアップをトリガーするために udev を使用しています。 このアイデアは、私のアクティブなドキュメントのマスター コピーが私のサム ドライブにあり (サム ドライブはどこにでもあり、いつでも作業できるため)、私がドライブをそのマシンに接続するたびに、これらのマスター ドキュメントが私のコンピュータにバックアップされる、というものです。 つまり、私のパソコンがバックアップドライブで、私の本番データがモバイルというわけです。 ソースコードが公開されていますので、udevのテストを制約するさらなる例として、attachupのコードを自由に見てみてください。

    udev を最も使用するのはこれなので、ここではこの例を使用しますが、udev はゲームパッド (ゲームパッドが接続されたときに xboxdrv モジュールをロードするように設定されていないシステムで有用) やカメラ、マイク (特定のマイクが接続されたときに入力を設定するのに有用) など、他の多くのものを取得できるので、この例よりも多くのことに使用できることに気付いておいてください。

    私のバックアップ システムのシンプルなバージョンは、次の 2 つのコマンドで構成されています:

    SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", SYMLINK+="safety%n"
    SUBSYSTEM=="block", ATTRS{idVendor}=="03f0", ACTION=="add", RUN+="/usr/local/bin/trigger.sh"

    最初の行は、すでに説明した属性でサム ドライブを検出し、デバイス ツリー内でサム ドライブにシンボリック リンクを割り当てます。 割り当てられたシンボリックリンクは、safety%n です。 n は udev マクロで、カーネルが sdb1, sdb2, sdb3 などのデバイスに与える番号に解決されます。 つまり、%n は 1 や 2、3 になります。

    これは dev ツリーにシンボリックリンクを作成するので、通常のデバイスを接続するプロセスを 妨げることはありません。 つまり、デバイスの自動マウントを好むデスクトップ環境を使用している場合、問題を引き起こすことはありません。

    2行目は、スクリプトを実行します。

    私のバックアップ スクリプトは次のようになります:

    #!/usr/bin/bash
    mount /dev/safety1 /mnt/hd
    sleep 2
    rsync -az /mnt/hd/ /home/seth/backups/ && umount /dev/safety1

    このスクリプトはシンボリックリンクを使用し、udev がドライブに予想外の名前を付けることを防ぎます (たとえば、DISK というサム ドライブがすでにコンピュータに接続されていて、もう一方のサム ドライブも DISK という名前で接続すると、2つ目は DISK_ というラベルが付いて、このスクリプトは台無しになるでしょう)。 安全にマウントされたら、rsync を使用してドライブをバックアップフォルダーにバックアップします (私の実際のスクリプトは rdiff-backup を使用していますが、あなたの好きな自動バックアップソリューションを使用することができます)。 これを学び、使い、POSIX の力を享受してください。

    この記事は、GNU Free Documentation License 1.3 の下でライセンスされている Slackermedia Handbook の内容に基づいて構築されています。

コメントを残す

メールアドレスが公開されることはありません。