udevルールの書き方

Daniel Drake (dsd) 著
バージョン 0.6

この文書の最新バージョンは、常に以下のサイトにあります。
http://www.reactivated.net/udevrules.php(英語オリジナルサイト)
http://www.gentoo.gr.jp/transdocs/udevrules/udevrules.html(日本語翻訳版)

日本語翻訳版は、著者に許可を得て、五十嵐 正尚(igarashi@gentoo.gr.jp)が翻訳し、GentooJPで公開しているものです。翻訳版に関することは訳者に連絡してください。
日本語翻訳版 最終更新日 2005-05-16

内容

  1. この文書について
  2. 更新履歴
  3. 執筆時に使用したソフトウェアのバージョン
  4. 用語紹介: devfs、sysfs、ノードなど
  5. なぜルールを書く必要がありますか? (この文書の目的)
  6. ルールを書く上での基本事項
  7. NAMEとSYMLINKパラメータでの設定自動化のための付加機能
  8. キーでのシェル形式パターン照合の使い方
  9. キーを書く上での基本事項
  10. 基本キーによるデバイス識別方法
  11. SYSFSファイルによるデバイス識別方法
  12. 複数SYMLINK形式の使い方
  13. 所有権とパーミッション制御
  14. 例: 著者所有のUSBプリンタ向けのルールの書き方
  15. 例: USBストレージ方式対応デジカメ向けのルールの書き方
  16. USBストレージ向けルールの書き方に関する追記
  17. 例: 著者所有のCDドライブに便利なルールの書き方
  18. 例: 著者所有のネットワークインターフェースに名前を付けるルールの書き方
  19. SYSFS内におけるudevinfoを実行すべき場所を探し出すコツ
  20. ルールのデバッグ方法
  21. 著者と謝辞

この文書について

udevはLinuxカーネル2.6以降を対象とし、デバイス名を固定する機能を備え、動的な/devディレクトリをユーザスペースで実現する方法を提供します。 これまでの/devの実装であるdevfsは、現在後方互換のためだけに残されており、udevはその後任と考えられています。 udevとdevfsではどちらが良いかということは、慎重に議論されるべき問題です。 ご自分で比較する前に、まずこの文書を読むべきです。

udevはよく考え抜かれていますが、私は最初、自分のシステムではどのように調整すればよいのかとても戸惑いました。この文書では、ルールを書く手順がもう少し明確になることを目指しています。

いつでも意見や感想をお待ちしております。どんな意見、問題、改善案でも連絡先にお願いします。

この文書は、udev/hotplugをインストール済みであり、初期設定で問題なく動作していることを想定しています。まだudevを設定しておらず、動作していないなら、Decibels udev Primer(日本語訳)に従ってその作業を行うことをお勧めします(少しGentoo Linux固有のことが含まれていますが、他のディストリビューションにも有用なはずです)。

更新履歴

2005年5月9日 v0.6: udevinfo、グループとパーミッション、ログ取り、udevtestに関する情報を含む様々な更新。

2004年6月20日 v0.55: 複数シンボリックリンク形式に関する情報を追加。細かい変更/更新。

2004年4月26日 v0.54: Debian情報を追加。細かい修正。 ルールファイルをなんと呼ぶべきかに関しての情報を過去ものに戻した。 ネットワークインターフェースの名前付けに関する情報を追加。

2004年4月15日 v0.53: 細かい修正。NAME{all_partitions}に関する情報を追加。udevinfoを使用する際のコツに関する別の情報を追加。

2004年4月14日 v0.52: udevの初期設定が他のファイルを考慮するようになるまで、udev.rulesの使用を推奨するように戻した。細かい作業。

2004年4月6日 v0.51: udev.rulesの先頭に追加するより、各自のlocal.rulesファイルの使用を推奨するように書いた。

2004年4月3日 v0.5: ちょっとした整理とudev配布物に含まれる可能性があるため、その準備。

2004年3月20日 v0.4: 全体的に改良、明確化、および整理。USBストレージ向けのルールの書き方に関する情報をさらに追加。

2004年2月23日 v0.3: sysfsの名前付け動作方法とそれにどのように一致させるかを強調するために、いろんな部分を書き直し。 udev 018の新しいSYSFS{filename}名前付け規則を説明するルールの書き方を更新。 セクションの体裁を改良と、いろんな箇所をわかりやすくした。KDEに関する情報を追加。

2004年2月18日 v0.2: 例の中のちょっとした間違いを修正。 マスストレージデバイスの識別に関するセクションを更新。nvidiaのセクションを更新

2004年2月15日 v0.1: 最初の公開。

執筆時に使用したソフトウェアのバージョン

Linuxカーネル 2.6.11
udev 056

用語紹介: devfs、sysfs、ノードなど

基本的な紹介だけです。完全に正確ではないかもしれません。

標準的なlinuxを基本とするシステムでは、/devディレクトリは、ファイルに似たデバイスノードを保持するために使用されます。 デバイスノードは、システムに含まれる特定のデバイスに対応します。 各ノードは、システム構成の一部(デバイス)を指します。デバイスは、実際に存在するかもしれないし、存在しないかもしれません。 ユーザスペースで動作するアプリケーションは、システムハードウェアとやり取りをするためにこれらのデバイスノードを使用できます。例えば、ユーザが行うマウス動作を、画面上のマウスポインタの動きに結びつけるために、XFree86は/dev/input/miceを監視します。

もともとの/devディレクトリは、システムに組み込まれる可能性のある全てのデバイスが配置されていました。 そんなわけで/devディレクトリは、一般的にとても大きくなっていました。 devfsは、もろもろの機能に加え、より扱いやすい手法(特に目を引くのは、システムに接続されたハードウェアだけが/devに配置されたことでした)を提供するために登場しました。 しかし、devfsには簡単に解決することができない問題があることが判明しました。

udevは、/devディレクトリを管理する新しい手法です。 過去の/dev実装にある問題を解決するように設計され、将来にわたって破綻しないものを提供します。 udevは、ユーザが指定するルールsysfsによって提供される情報を照合して、システムに組み込まれたデバイスに相当する/devデバイスノードを作成し命名します。 ルールを書く工程は、ユーザが(選択的に)行う必要がある数少ないudevに関係する作業のうちの一つです。 この文書は、そのルールを書く工程を詳しく説明することが目的です。

sysfsは、2.6カーネル向けの新しいファイルシステムです。 sysfsはカーネルによって管理され、システムに接続されているデバイスに関する基本情報をユーザスペースに提供します。 udevは、ハードウェアに相当するデバイスノードを作成するために、この情報を使用します。 sysfsは/sysにマウントされることで、情報を読み出せる状態になります。 udevに取り組む前に、まず/sysにあるファイル群を調査したいとお思いになるでしょう。この文書全体に渡って、用語/sysSYSFSを使用します。どちらにも読み替え可能です。


なぜルールを書く必要がありますか?

上で述べたように、udevのルールを書くかどうかは、自由に選択できます。 初期設定でも、デバイスを接続することができ、過去の/dev実装でのように、そのデバイスに適切なノード(例えば、マスストレージデバイス用である/dev/sdaなど)が作成されるでしょう。

しかし、udevはデバイスノードの名前を自由に変えることができます。 名前を変更したくなる理由には、利便性とデバイス名の固定化の二つが考えられます。

プリンタが接続されたときに、/dev/printerとして命名され、さらにいつもの/dev/lp0も存在するようにする場合のudevの使用例を挙げます。 この例は、利便性(例えば、lp0ではなくprinterに読み替える)だけではなく、変更になる可能性のある名前への対策であることを意図しています。 私は二つのプリンタ(HPのレーザプリンタと、EPSONのインクジェット)を持っています。 それらプリンタの両方が接続され、システムに組み込まれるた場合、/dev/lp0と/dev/lp1になります。
どうすれば、どちらのノードがどちらのプリンタを指しているかを知ることができるでしょう。 簡単な方法はありません。接続された順で、最初のプリンタがlp0を割り当てられ、二番目がlp1に割り当てられます。異なる順番でプリンタが接続されると、この名前は逆になります。そして、それは常にHPのレーザプリンタがlp1であることを想定している私のスクリプトを混乱させるでしょう。

しかし、もしHPレーザプリンタに(lpXに加えて)lp_hpの名前が与えられ、一方のプリンタに(lpYに加えて)lp_epsonの名前が与えられるなら、私のスクリプトは、これらの名前を使えるでしょう。udevの魔法は、このようなことを制御でき、このような固定された名前が常に意図するデバイスを指すことを確実にします。

この名前の固定化機能は、外部マスストレージデバイス(例えば、USBハードディスク)において、/etc/fstabに正確なデバイスを書き込むことを可能にするのに、とても役に立ちます。

ルールを書くことは、udevの動作を調整する一つの手段でしかないという認識を持つことが大切です。 ルールを書くことは、既存の特定デバイスに対応するデバイスノードがない場合の問題に対する回避策ではありません。 該当する既存のルールがない場合、udevはカーネルが提供する名前を使ってとにかくノードを作成します。

ルールを書く上での基本事項

udevは、/devの下を配置するときに、一連のルールファイルを読んで、どのノードを含めるかと、それらのノードにどのような名前を付けるかを決定します。

初期設定のudevルールは、/etc/udev/rules.d/50-udev.rulesにあります。 このファイルにざっと目を通すとおもしろいことが分かるかもしれません。 そこには少しの例や、いくつかのdevfs形式の/devレイアウトを提供する初期設定ルールが含まれています。 しかし、今後udevを更新するときに起こりうる面倒を軽減するために、このファイルにルールを直接書くべきではありません。

/etc/udev/rules.d/にあるファイルは、辞書順で解析されます。 udevは、ファイル中に新しく検出されたハードウェアに一致するルールを見つけるとすぐに、ルール処理を止めます。 udevの初期設定と照合される前に、ユーザが用意したルールが処理されることが重要です。そうでないと、ユーザの命名規則は無効になってしまうでしょう。 /etc/udev/rules.d/10-local.rulesファイル(デフォルトでは存在しないので、作成してください)の中にユーザ指定のルールを保持しておくことを推奨します。 10は50より前なので、ユーザ指定のルールが最初に評価されることがおわかりでしょう。 ユーザ指定のルールファイルの名前は、.rulesサフィックスで終わっている必要があります。そうしないと利用されません。

ユーザ指定のルールは、基本の/devレイアウトを作成するudevの初期設定を、事実上無効にしてしまいます。したがって、ユーザが記述するルールには、実用的である初期設定の名前とユーザ指定の名前両方を得るために、devfs形式の名前やシンボリックリンクも指定することをお勧めします。

ルールファイルでは、"#"で始まる行は、コメントとして扱われます。 ルールファイルの中のコメントされてない全ての行が、ルールに相当します。

ルールは複数のキーで構成されます。複数のキーはコンマによって区切られます。 一部のキーは情報の読み込みと照合用で、その他のものは、情報の割当てやアクションの実行用です。
  1. システムにあるいろいろなデバイスに一致する、少なくとも一つの識別キー(identification key)を指定する必要があります。 識別キーついては、後にある基本キーによるデバイス識別方法セクションに記載されています。
  2. 結果としてデバイスノードがどのようにして作成されるかを制御するための、少なくとも一つの割当てキー(assignment key)を指定する必要があります。 割当てキーには、NAME、SYMLINK、OWNER、GROUP、MODEがあり、このドキュメントですべて説明しています。
一般的なルールは、デバイスに名前を付けることを決定するために、複数の基本識別キーが使われます。そして、デバイスノード名を決めるために一つのNAME割当てキーが指定されます。 udevは、一つのデバイスに対し一つのノードだけを作成します。 したがって、一つのデバイスに対し複数のノードを通してアクセスしたい場合は、SYMLINK割当てキーに、別のノードを指定する必要があります。

以下に例を示すためにudevの例にあるルールをちょっと修正したものを取り上げます。
BUS="usb", SYSFS{serial}="HXOLL0012202323480", NAME="lp_epson", SYMLINK="printers/epson_stylus"
この場合の識別キーは、BUSSYSFS{serial}で、割当てキーは、NAMESYMLINKです。 udevは、このルールをUSBバスによって接続されかつHXOLL0012202323480のシリアルナンバーを持つデバイスに対して一致させます。 udevがデバイスに名前を付けるルールとして採用するには、(どれか一つではなく)すべての指定されたキーが一致する必要があります。
udevは、このノードをlp_epsonと命名し、/dev/lp_epsonに作成するでしょう。
udevは、さらに/dev/lp_epsonへのシンボリックリンクを、/dev/printers/epson_stylusに作成します(printersディレクトリは、自動的に作成されます。)。 これで、/dev/printers/epson_stylusもしくは/dev/lp_epsonにデータを送ることで、EPSONプリンタで印刷することができます。

ユーザが追加または修正したどんなルールも、udevに通知するまで有効にはなりません。 何かルールファイルを修正した場合は常に以下のコマンドを確実に実行することを忘れないでくささい。
# udevstart

NAMEとSYMLINKパラメータでの設定自動化のための付加機能

ルールのNAMEとSYMLINKパラメータに、デバイスの名前づけを支援する基本オペレータを使用することができます。 プログラム言語が分かる人は、この種のものをprintf形式に似た文字列置換として知っていると思います。 NAME/SYMLINKパラメータの一部もしくは全てを組み立てることが可能な、いくつかのオペレータがあります。 これらオペレータは、デバイスに関するカーネルデータを参照します。 以下の例を見てみましょう。
BUS="usb", SYSFS{vendor}="FUJIFILM", SYSFS{model}="M100", NAME="camera%n"
%nオペレータは、camera0、camera1、などのようなNAMEを作成するために、カメラデバイスに対する"カーネル番号"に置き換えられます。

他にはよく使われるオペレータとして、%kがあります。 これは、例えば"hda1"などのような、カーネルがデバイスに付けると予想される名前を表します。 ハードウェアのデフォルトの名前を作成するための、NAME="%k"が指定されているルールをよく見るでしょう。 このようなルールでは、ユーザ指定のものは通常SYMLINKパラメータによって設定されます。

udevのmanページに説明付きでオペレータの全リストがあります。

キーでのシェル形式パターン照合の使い方

キーを書く場合、より柔軟性を高めるためにシェル形式のパターン照合を使用することができます。以下に初期設定のudevルールを取り上げます。
KERNEL="ts*", NAME="input/%k"
ここでは*オペレータが使われています。これは、文字列長が0以上のすべての種類の文字で構成される文字列全体に一致します。 このルールの書き方は、以下のことを意味します。
"ts"の文字列で始まり、その後に任意で何かの文字が続くKERNEL名によって識別されるデバイスに一致し、指定ディレクトリの下にKERNEL名(%k)で名前をつけます。
?オペレータはよく似ており、何かの一文字に一致します(0文字には一致しません)。

どれかの一文字に一致する、かぎ括弧[ ]も使用できます。以下にudevのmanページから直接引用します。
例えば, パターン文字列"tty[SR]"は、"ttyS"か"ttyR"に一致します。
一致範囲を指定することもできます。 例えば、[0-9]はいずれかの一文字の数字に一致します。 以下にudevインストール直後の初期設定にあるルール例を示します。
KERNEL="fd[0-9]*", NAME="floppy/%n"
このルールは以下のことを意味します。
"fd"で始まり、それに一文字の何かの数字が続き、その後に任意で何かの文字が続くKERNEL名によって識別されるデバイスに一致します。フロッピーのディレクトリの下にデバイスのカーネル番号(%n)でデバイスに名前をつけます。
これらのワイルドカード/パターン一致は、基本キーとsysfsでの識別情報の両方を含め、どのキータイプででも使用できます(キータイプに関しては後の説明を参照してください)。

ここでは、ルールの書き方に関する基本事項の範囲外である一部の情報(特に[ ]オペレータの柔軟性)をわざと割愛しています。 これに関する詳しい情報は、udevのmanページにあります。

キーを書く上での基本事項

udevは、いくつかの基本キーを照合する仕組みを提供しています。さらにSYSFS内のデバイス情報と照合するための柔軟な方法も提供します。 標準的なルールは、普通のキー(BUSとKERNELなど)と、 同一ポートに接続された異なるハードウェア間で区別をするSYSFSキーの両方が一致します。

「自分のプリンタのシリアルナンバーをどうやって探せばいいの? 私のカメラのモデルは何だろう?」と疑問に思うかもしれません。 ルールの書き方は、思うほど難しくありません。 一番やっかいなのは/sys内で対象のデバイスを探して、どの情報を使うかを決めることです。

基本キーによるデバイス識別方法

基本キーに関するより詳しい情報はudevのmanページを参照してください。

有効なキーは次のとおりです。 IDとPLACEキーは、役に立つこともありますが、一般的にルールでは使用されません。 この文書は、BUSとKERNELキーやSYSFS{...}キー(次のセクションで説明します)の使い方に重点を置きます。 例を使ってこれらのキーの使い方を示します。

さらに柔軟な方法として、udevは外部のスクリプトを呼び出してその結果を使うためのキーや、環境変数を使うためのキーも準備しています。 これは、この文書の範囲外とします。より詳細な説明は、udevのmanページを見てください。

SYSFSファイルによるデバイス識別方法

前提となる知識: SYSFSは、ディレクトリツリーの下にハードウェアに関する情報を提供するたくさんの小さなファイルを保持しています。 一つのファイルは、一般に一つだけ"データ項目"を持ちます。- 例えば、デバイス名や製造者情報やプロダクトIDがあります。

SYSFS{...}キーは、前のセクションで説明した基本キーと組み合わせることができます。


特定のSYSFSの情報と照合するために、SYSFS{ファイル名}形式のキーを使えます。ファイル名は、SYSFSツリーの中のファイルに相当します。 例としては、私のカメラが接続された場合、"USB 2.0M DSC"という内容で/sys/block/sda/device/modelにファイルが存在します。これと照合するために、次のようなキーを使えます。SYSFS{model} = "USB 2.0M DSC"

sysfsにあるすべてのファイルが、この方法で照合することができます。 ただ、(複数のキーを使って)一つ以上のファイルと照合させる場合、同一ディレクトリにあるファイルとだけに照合させる必要があります。 一般的には、一つのデバイスに関する情報を提供するディレクトリは、いくつか存在します。 (後の例で示すとおり、)それらを混合して照合することはできません。

幸いにして、ルールを書く過程において、SYSFSにある無数のファイルを探し回る必要はありません。udevinfoユーティリティがその大変な作業を代わりにやってくれます。このプログラムはudevの配布物の中に含まれています。

まず始めにしなければならないことは、対象のハードウェアに対応する、"dev"というファイルを含むディレクトリが/sysのどこにあるかを見つけることです。 udevinfoは、そのようなディレクトリ上でだけ動作可能です。 これらのディレクトリは、すべてが/sys/block/sys/classのどちらか一方の下で見つかります。 - その他の場所は、どこも参照する意味がありません! しかし、udevinfoはこれらのディレクトリを経由してリンクを辿って、sysfsの別のセクションで見つかる情報を読み出します。

一度だけこのようなディレクトリを見つければ、udevルールのキーを書く作業を手助けしてくれる以下のコマンドが使えます。
# udevinfo -a -p /sys/path/to/hardware/info
udevinfoを実行するための/sys内の適切な位置を見つけることについては、まだ明確になっていないことが分かるでしょう。 接続したデバイスに対し既にデバイスノード(例えば、/dev/sda)が作成されている可能性があり、その場合はudevinfoが役に立ちます! 私の/dev/sdaノードの例でいうと、以下のコマンドを実行するとsysfsの適切な位置を示してくれます。
# udevinfo -q path -n /dev/sda

/block/sda
(上記で示した)このコマンドの出力は、sysfsパスが/sys/block/sdaで始まることを示しています。 これで私は"udevinfo -a -p /sys/block/sda"を実行できます。 これらの二つのコマンドは、以下のように連ねることができます。
# udevinfo -a -p $(udevinfo -q path -n /dev/sda)
注記: 前に示したものには、udevinfoにあらかじめフルパス(/sys/なんとか/パス)を指定していて、今回はこれらのコマンドを連結することでsysfsに関係するパスを指定していることに気が付くかもしれません。 どちらでも特に問題はありません。どちらのパス形式も受け付けられます。

ここでルールの書き方に移り、私の環境での"udevinfo -a -p /sys/block/sda"の実行結果の抜粋を、色づけをして以下に示します。

follow the class device's "device"
  looking at the device chain at '/sys/devices/pci0000:00/0000:00:02.1/usb3/3-3/3-3:1.0/host0/0:0:0:0':
    BUS="scsi"
    ID="0:0:0:0"
    SYSFS{detach_state}="0"
    SYSFS{type}="0"
    SYSFS{max_sectors}="240"
    SYSFS{device_blocked}="0"
    SYSFS{queue_depth}="1"
    SYSFS{scsi_level}="3"
    SYSFS{vendor}="        "
    SYSFS{model}="USB 2.0M DSC    "
    SYSFS{rev}="1.00"
    SYSFS{online}="1"

  looking at the device chain at '/sys/devices/pci0000:00/0000:00:02.1/usb3/3-3':
    BUS="usb"
    ID="3-3"
    SYSFS{detach_state}="0"
    SYSFS{bNumInterfaces}=" 1"
    SYSFS{bConfigurationValue}="1"
    SYSFS{bmAttributes}="c0"
    SYSFS{bMaxPower}="  0mA"
    SYSFS{idVendor}="052b"
    SYSFS{idProduct}="1514"
    SYSFS{bcdDevice}="0100"
    SYSFS{bDeviceClass}="00"
    SYSFS{bDeviceSubClass}="00"
    SYSFS{bDeviceProtocol}="00"
    SYSFS{bNumConfigurations}="1"
    SYSFS{speed}="12"
    SYSFS{manufacturer}="Tekom Technologies, Inc"
    SYSFS{product}="USB 2.0M DSC"
udevinfoツールは、udevルールにそのままコピーペーストして使うことができる多くの情報を提供してくれます。 上記の出力結果に色をつけた理由は、 通常はudevinfoの出力の異なる箇所からの情報を組み合わせて照合することができないことを示すためです。 上記の出力結果で、異なる色が付いているセクションの情報を組み合わせることはできません。 - 出力結果の各セクションが、SYSFS内での異なるディレクトリを参照している情報だからです。 例えば、以下のルールは機能しません。
BUS="scsi", SYSFS{manufacturer}="Tekom Technologies, Inc", NAME="%k"
このルールは、青いセクションにだけ存在する情報とBUS="scsi"(緑)で始まるセクションにある情報と組み合わさっているので機能しません。 BUS="usb"と、上記の青いセクションにある情報だけを使用しているならちゃんと機能するでしょう。

多くの情報が、基本的なルールの書き方には関係ないことがわかるでしょう(本当にたくさんあります!)。 一般的には、変更にならないことが分かっている情報(例えばモデル名)を探すべきです。

デバイスを識別するユーザ指定のルールを記述すると、初期設定のdevfs形式のルールが機能しなくなることに注意してください。 たいていの場合、NAME="%k"を使用するのが賢明で、初期設定の実用的な名前がなくならないように、SYMLINKパラメータに追加の名前を指定してください。

以下にudevinfoの出力を基にしたルールの書き方の手順を三つの例で示します。 その後、正確な情報を提供するために各デバイス固有の小技やコツをいくつか記述しようと思います。

読者の一人が、KDEのコントロールセンターがルールを書くのに役に立つということを、知らせてきました。 USBデバイス(やその他)に関する情報が、KDEコントロールセンターの"Info Centre"セクションで見つかるということです。 このインターフェースは、シリアルナンバー、ベンダIDなどのような情報を表示します。 GUI的なやり方が好ましいなら、こちらを調査したいと思うでしょう。

現在リリースされているGNOMEボリューム管理は、実デバイスとしてシンボリックリンクノードを扱うことができません。 上記で説明したのとは反対に、NAMEパラメータにユーザ指定の名前を指定して、SYMLINKパラメータに%kを指定しようと思うかもしれません。

複数SYMLINK形式を使えば、ユーザ指定ルールが初期設定を上書きする仕様に対処できます。

複数SYMLINK形式の使い方

最近取り入れられた機能の一つに、NAMEを指定せずに、複数のSYMLINKキーを単純に指定するルールが書けるようになったことがあります。 これで、ユーザ指定ルールがudevの初期設定を実質的に無効にする問題を避けることができます。

そのルールを以下に取り上げます。
KERNEL="hdc", SYMLINK="dvd"
udevはこのルールを見つけると、記憶しておきます。 そして、NAMEパラメータも含む同一デバイスに一致する別のルールを見つけたときに、そのNAMEパラメータで指定されているノードに加え、両方のルールにあるSYMLINKパラメータで指定されているシンボリックリンクも作成します。
実際問題として、udevは私のhdcデバイスのノードを命名する際に、いつものようにブロックデバイス用の初期設定ルールを使い、追加の私個人指定の"dvd"シンボリックリンクを作成します。

普通のルールと同様に、udevがNAMEパラメータを指定しているルールを見つける前にこの形式のルールを見つけたときだけ有効になります。

所有権とパーミッション制御

作成されるデバイスノードの名前付け制御と同様に、udevルールは、そのデバイスノードの所有権とパーミッション属性の制御も可能にします。

GROUPキーは、どのunixグループにデバイスノードを所有させるかを定義できます。 ここにudevの初期設定から例を示します。 この例は、フレームバッファ(fb)デバイスをvideoグループにするように定義しています。
KERNEL="fb[0-9]*", NAME="fb/%n", SYMLINK="%k", GROUP="video"
おそらくあまり使えないOWNERキーは、どのunixユーザにデバイスノードを所有させるかを定義できます。 フロッピーデバイスを"john"の所有にする場合のちょっと変な状況を仮定すると、次のように使います。
KERNEL="fd[0-9]*", OWNER="john"
上記のルールには、NAMESYMLINKが一つも指定されていないことがわかるでしょう。 これは、udevが、フロッピーノードをjohnの所有にしたいということを記憶しておき、フロッピーデバイスノードに対するNAMEが定義されたルールを見つけると、所有者を適用する点で、複数シンボリック形式に似ています。

上で記述した形式を使用すると、もっと華麗なこともできます。 udevの初期設定では、すべてのサウンドデバイスノードが"audio"グループによって所有されるように定義するのに以下のルールを使用しています。
SUBSYSTEM="sound", GROUP="audio"
これに続くサウンドデバイスに名前を付ける全てのルールにGROUP="audio"キーをやたらと指定する必要をなくします。

udevのデフォルトでは、unixパーミッションに0660(所有者とグループだけが読み書き可能)を持つノードを作成するようになっています。 これは、/etc/udev/udev.confの中のdefault_mode設定によって設定されています。 デバイスノードにデフォルトパーミッションを適用したくない場合もあるかもしれません。幸いにして、ルールにMODE割当てキーを使うことで簡単にデフォルト設定より優先させることができます。 例として、以下のルールはinotifyノードが全てのユーザに読み書き可能になるように定義しています。
KERNEL="inotify", NAME="misc/%k", SYMLINK="%k", MODE="0666"

例: 著者所有のUSBプリンタ向けのルールの書き方

私は、プリンタを接続した後、ルールを書くために/sysディレクトリから関連する位置を探し始めました。 どこにも見つからなかったのですが、私のプリンタにデバイスノード/dev/lp0が割り当てられていることに気づきました。 udevinfoは、便利なpathを指定すると以下のように教えてくれます。
# udevinfo -q path -n /dev/lp0
/class/usb/lp0
"udevinfo -a -p /sys/class/usb/lp0"を実行すると、通常通りに多くの情報を提供してくれます。 デバイスを識別する以下の固有の情報を選択しました。
looking at the device chain at '/sys/devices/pci0000:00/0000:00:02.1/usb3/3-3':
BUS="usb"
SYSFS{manufacturer}="EPSON"
SYSFS{product}="USB Printer"
SYSFS{serial}="L72010011070626380"
この場合のudevルールは以下のようになります。
BUS="usb", SYSFS{serial}="L72010011070626380", NAME="%k", SYMLINK="epson_680"
そうすると、私のプリンタのノードは/dev/lp0(または、別のプリンタが前もって接続されている場合は/dev/lp1)で存在し、/dev/epson_680常にそのプリンタのためのデバイスノードを指します。

例: 著者所有のUSBストレージ方式対応デジカメ向けのルールの書き方

簡単な説明: 私のカメラは外付けSCSIハードディスクとして認識されます(USBハードディスクやフラッシュメモリカードリーダのようなデバイスにも使用されるusb-strageドライバを使います)。 そして、そのディスク上のパーティションをマウントして、画像ファイルをコピーできます。すべてのカメラがこのように動作するわけではありません。ほとんどのカメラは、画像ファイルを扱うために、さらにソフトウェア(gphoto2など)を必要とします。

これにはちょっとしたコツがあります。私のカメラが接続されると、デフォルトでいくつかのノードが作成されます。 /dev/sda/dev/sda1/dev/sg1さえも作成されるかもしれません。 この例が示しているものは重要です。もしルールが上手に指定されなければ、上記3つのノードすべてに一致することがありえます。

sda1は、私がマウント用に/dev/cameraとして使用しようと思うノードです。 udevinfoはsda、sda1、sg1の間に利用できそうな差異は何も提示してくれません。 これら3つのノードを区別するために信頼できる方法は、KERNEL名を見ることであると私は判断しました。

KERNEL="sd?1"のようなキーは、"sda1"、"sda1"、"sdc1"のようなKERNEL名に一致し、そして同様に重要なことに、それは、sda、sdb、sg1のようなKERNEL名に一致しないであろうということです。 このようなキー指定には、/dev/sda/dev/sg1ノードに一致させないという目的があります。 対象のデバイスはデジタルカメラです。その上ではfdiskやその類の操作をしようなんて夢にも思わないので、私にとってこれらの2つのノードは、まったく使いものになりません。 このキーは/dev/sda1ノードを捕捉しようとします。これはマウント可能なので、使いものになります!

このノード(sda1)は、ブロックデバイスとして扱われるので、/sys/blockから探すことは、作業を始めるのに向いています。

私の環境での/sys/blockには、sdaというディレクトリがあります。 /sys/block/sdaには、sda1というディレクトリがあります。 これら両方のディレクトリにdevファイルがあるので、そこでudevinfoを実行できます。 以下を実行すると、私のカメラとそれが接続されているUSBポートに関するたくさんの情報を表示してくれます。
# udevinfo -a -p /sys/block/sda/sda1
udevinfoの出力に、以下のちょっと役に立つ意味がわかりやすい情報を見つけました。
SYSFS{product}="USB 2.0M DSC"
よってこれで私のルールを書くことができます。ルールを完全にするために、BUSキーも加えます(これもudevinfoの出力で見つかります)。
BUS="usb", SYSFS{product}="USB 2.0M DSC", KERNEL="sd?1", NAME="%k", SYMLINK="camera"
こうして、私のカメラを接続すると、/dev/sda1(もしくは、sda1が利用できないなら、/dev/sdb1になるかもしれません)という名前で、常に間違いなく/dev/cameraからリンクされます。 /dev/sda(もしくはsdb)ノードは、いつものようにまだ出現します。 しかし私が指定する不変の"camera"シンボリックが、マウント可能パーティションを指しているということが重要です。

USBストレージ向けルールの書き方に関する追記

大容量のUSBハードディスクを所持するCarl Streeterが、/dev/sdaノードが役に立たなかった私のデジタルカメラの例とは違った説明をメールしてきました。 /dev/sdaのようなノード上でfdiskhdparmなどのツールをちょくちょく使う必要があることを指摘しています。

以下にCarlのルールを示します。
BUS="usb", KERNEL="sd*", SYSFS{product}="USB 2.0 Storage Device", NAME="%k", SYMLINK="usbhd%n"
このルールは、以下のようなシンボリックリンクを作成します。 Carlとはマウント不可の/dev/sdaノードが必要かどうかは、状況と対象のデバイスに依存するということで共通認識を持っています。 どちらの設定方法にしろ都合のよい方を使用してください。

これとは別の複雑な状況として、複数のスロットを持つUSBストレージカードリーダを持っている場合があります。 新しいカードが刺されたり抜かれたりしたときに、一般的にこのような種類のデバイスはその情報を通知しません。 よって、リーダが接続されている間に未使用スロットにカードを刺しても、マウントする必要がある追加のデバイスノードは、作成されないでしょう!
この問題は、他のUSBディスクにも当てはまります。 例えば、新しいパーティションを作成した場合、デバイスを再接続するまで、新しいパーティションノードは出現しないでしょう。

udevは、これに対する一つの解決方法を提供します。 ブロックデバイスのすべてのパーティション用のノードを作成することができます。 指定したすべてのルールに対して、ブロックデバイスで16個のパーティションノードを作成します。 これをするには、以下に示すように単にNAMEキーを修正します。
BUS="usb", SYSFS{product}="USB 2.0 Storage Device", NAME{all_partitions}="usbhd"
こうすることで、usbhd、usbhd1、usbhd2、usbhd3、...、usbhd15というノードが作成されるでしょう。

例: 著者所有のCDドライブ向けの有用なルールの書き方

私のPCには二つのCDドライブがあります。一つは、DVD読み込み対応で、一つはCD読み書き対応のものです。 DVDのノードはhdcで、CDRWのノードはhddです。 あえてシステムの結線を変更する場合を除いて、これを変更するつもりはありません。

でも、利便性のために/dev/dvd/dev/cdrwのようなノードを好む人が(私自身も含めて)います。 これらドライバの"hdX"の値がわかっているので、ルールを書くのは簡単です。 以下の例は、それだけで自明でしょう。
BUS="ide", KERNEL="hdc", NAME="%k", SYMLINK="dvd cdroms/cdrom%n"
BUS="ide", KERNEL="hdd", NAME="%k", SYMLINK="cdrw cdroms/cdrom%n"
デフォルトの50-udev.rulesファイルにブロックデバイス用の名前を生成するスクリプトを実行するルールがあることに気が付くかもしれません。 これに惑わされないでください。やはりユーザ指定のルールは、デフォルトルールの前に処理されるファイルに設定するので、デフォルト設定は、ルールを設定済みのハードウェアに名前をつけるときには使用されません。

例: USB Visor Palm Pilot向けのルールの書き方

これらのデバイスは、USBシリアルデバイスのように動作します。よってデフォルトではttyUSB1ノードだけが得られます。 ユーザスペースのpalmユーティリティは、/dev/pilotがあることを前提としています。 よってそのノードを作成するルールを使う必要があります。 以下のルールはこれを行います。

BUS="usb", SYSFS{product}="Palm Handheld", KERNEL="ttyUSB*", SYMLINK="pilot"
この状況に関する有用な議論があるCarsten Clasohm's blog entry(訳注: Carsten Clasohmのブロブ)から応用しました。 さらに個々の設定に合わせるために、上記ルールに所有権とパーミッションキーを追加したいと思うかもしれません。

例: 著者所有のネットワークインターフェースに名前を付けるルールの書き方

最近のバージョンのudevにある興味深い新しい機能に、nameifユーティリティのように、ネットワークインタフェースの名前を付け直す機能があります。 ネットワークインターフェースは、/devに出現しませんが、一般的にはそれらは名前によって参照されます(例えば、ifconfigで使用される場合)。 ネットワークデバイスには様々ありますが、ルールを書く工程はほとんど同じです。

やはりudevinfoはルールを書く手がかりになります。 以下は私の"eth0"のネットワークデバイスの名前を変更したい場合の例です(以下の出力結果は省略されています)。
# udevinfo -a -p /sys/class/net/eth0/
  looking at class device '/sys/class/net/eth0':
    SYSFS{address}="00:52:8b:d5:04:48"
すべてのネットワークアダプタには固有のMACアドレスがありますので、ルールを書く場合にはこれを使うことを選択しました。 この値は、ネットワークカードを変更しない限り変更がありません。 以下に一つ警告があります。 大文字小文字を区別しますので、必ず(上記のように)udevinfoから取得したMACアドレスを使ってください。 ifconfigのようなユーティリティを使う場合は、それらは大文字を使うので、気をつけてください。

ルールの例を以下に示します。
KERNEL="eth*", SYSFS{address}="00:52:8b:d5:04:48", NAME="lan"
このルールを有効にするためにネットワークドライバをリロードしなければならないでしょう。 モジュールをアンロードして再度ロードするか、もしくは単にシステムをリブートすればよいです。 "eth0"ではなく"lan"を使うようにシステムを構成しなおす必要もあります。 私の場合、eth0を参照するものすべてを完全に削除しないで、これを進めてしまい、少々苦労をしました。
これが完了すれば、ifconfigやそれに似たユーティリティのどれにでも"eth0"の代わりに"lan"を使えるはずです。

SYSFS内におけるudevinfoを実行すべき場所を探すためのコツ

ここではより多くのデバイス固有のコツを求めています。 提供できることならなんでも連絡してください

ルールのデバッグ方法

ルールを書き終わって忘れずにudevstartを実行しても、有効にならないなら、それをデバッグするのには二つの方法があります。

/etc/udev/udev.confには、udev_logオプションがあります。 そのオプションをyesに設定すると、udevはどのノードにどのルールを適用したかに関するいくつかの役に立つ情報をシステムロガーに出力します。 そのログ情報は、ほとんどの場合/var/log/messagesにあるでしょう。

さらに、ユーザが作成したいノードのsysfsにおけるパスを調べたいなら、ノードに対しudevがするはずであったことを一つずつ追って確認するために、udevtestを使用できます。 以下に例を示します。
# udevtest /sys/class/sound/dsp/
version 056
looking at '/class/sound/dsp/'
opened class_dev->name='dsp'
configured rule in '/etc/udev/rules.d/50-udev.rules[132]' applied, added symlink '%k'
configured rule in '/etc/udev/rules.d/50-udev.rules[132]' applied, 'dsp' becomes 'sound/%k'
creating device node '/dev/sound/dsp', major = '14', minor = '3', mode = '0660', uid = '0', gid = '18'
udevtestは、デバッグ/テストだけをするツールです。たとえ作成しているように表示しても、実際にはデバイスノードを作成しません!

著者と謝辞

この文書はDaniel Drake <dan@reactivated.net>
によって書かれました。 ご意見ご感想などなんなりと送ってください!

Copyright (C) 2003-2005 Daniel Drake
この文書はGNU General Public License, Version 2の下に公開されています。