web-dev-qa-db-ja.com

「/ dev」Linuxファイルはどのように作成されますか?

Linuxには、実際にはファイルではない特別なファイルがあります。

これらの最も注目に値する明確な例は、devフォルダー内の「ファイル」にあります。

  • /dev/null-ファイルへの書き込みをすべて無視します
  • /dev/random-ファイルの内容ではなくランダムなデータを出力します
  • /dev/tcp-ネットワーク経由でこのファイルに書き込んだデータを送信します

まず、これらの種類の "ファイル"の名前は、実際にはなんらかのスクリプトまたはバイナリの変装です。

次に、それらはどのように作成されますか?これらのファイルはカーネルレベルでシステムに組み込まれていますか、または「マジックファイル」を自分で作成する方法はありますか(/dev/rickroll)?

115
IQAndreas

/dev/zeroは、「特別なファイル」、特に「デバイスノード」の例です。通常、これらはディストリビューションのインストールプロセスで作成されますが、必要に応じて完全に自分で作成できます。

lsについて/dev/zeroについて質問した場合:

# ls -l /dev/zero
crw-rw-rw- 1 root root 1, 5  Nov 5 09:34 /dev/zero

先頭の「c」は、これが「キャラクターデバイス」であることを示しています。もう1つのタイプは「ブロックデバイス」です(lsによって「b」として出力されます)。非常に大まかに言えば、ハードディスクなどのランダムアクセスデバイスはブロックデバイスである傾向があり、テープドライブやサウンドカードなどのシーケンシャルなものはキャラクターデバイスである傾向があります。

「1、5」の部分は「メジャーデバイス番号」と「マイナーデバイス番号」です。

この情報があれば、mknodコマンドを使用して、独自のデバイスノードを作成できます。

# mknod foobar c 1 5

これにより、現在のフォルダーにfoobarという名前の新しいファイルが作成されます。このファイルは正確に/dev/zeroと同じことを行います。 (もちろん、必要に応じてさまざまな権限を設定できます。)この「ファイル」に実際に含まれるのは、上記の3つの項目(デバイスタイプ、メジャー番号、マイナー番号)だけです。 lsを使用して、他のデバイスのコードを検索し、それらも再作成できます。飽きたら、rmを使用して、作成したデバイスノードを削除します。

基本的に、メジャー番号はLinuxカーネルにどのデバイスドライバーと通信するかを指示し、マイナー番号はデバイスドライバーにどのデバイスと通信するかを指示します。 (たとえば、おそらく1つのSATAコントローラーがありますが、それに複数のハードディスクが接続されています。)

invent何か新しいことを行う新しいデバイスを使用する場合は、Linuxカーネルのソースコードを編集して、独自のカスタムカーネルをコンパイルする必要があります。だから、それをしないようにしましょう! :-)しかし、あなたがすでにうまく持っているものを複製するデバイスファイルを追加することができます。 udevのような自動化されたシステムは、基本的にデバイスイベントを監視し、mknod/rmを自動的に呼び出します。それ以上の魔法はありません。

まだother種類の特殊ファイルがあります:

  • Linuxは、ディレクトリを特別な種類のファイルと見なします。 (通常、ディレクトリを直接開くことはできませんが、可能であれば、特別な形式のデータを含む通常のファイルであり、そのディレクトリ内のすべてのファイルの場所をカーネルに指示します。)

  • シンボリックリンクは特別なファイルです。 (しかし、ハードリンクはそうではありません。)ln -sコマンドを使用してシンボリックリンクを作成できます。 (マンページを参照してください。)

  • 「名前付きパイプ」または「FIFO」(先入れ先出しキュー)と呼ばれるものもあります。 mkfifoで作成できます。 A FIFOは、一度にtwoプログラムで開くことができる魔法のファイルです。1回の読み取りと1回の書き込みです。これが発生すると、通常のシェルパイプのように機能します。ただし、各プログラムを個別に起動できます...

「特別」ではないファイルは、「通常のファイル」と呼ばれます。 Unixのドキュメントでこれについて言及することがあります。それが意味することです。デバイスノードでもシンボリックリンクでもないファイル。魔法のようなプロパティのない、通常の毎日のファイルです。

102

/devエントリのほとんどは、ブロックデバイスiノードまたはキャラクターデバイスiノードです。 ウィキペディアには多くの詳細があります それについて、私は繰り返すつもりはありません。

ただし、質問に記載されている/dev/tcpは、既存の回答では説明されていません。 /dev/tcp/dev/udpは、他のほとんどの/devエントリとは異なります。ブロックデバイスとキャラクターデバイスはカーネルによって実装されますが、/dev/tcp/dev/udpはユーザーモードで実装されます。

Bashシェルは、/dev/tcpおよび/dev/udpksh93からコピー)の実装を持つ1つのプログラムです。 bashリダイレクション演算子を使用してパスの下を開こうとすると、通常のopenシステムコールは実行されません。代わりにbashはTCPソケットを作成し、指定されたポートに接続します。

これは、bashcat/dev/tcp/::1/22を開こうとすることの違いを示す次の例に見られるように、ユーザーモードと一部のプログラムでのみ実装されます。

$ cat /dev/tcp/::1/22
cat: /dev/tcp/::1/22: No such file or directory
$ cat < /dev/tcp/::1/22
SSH-2.0-OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.3

ksh93との違いは、bashはリダイレクトオペレーターとのTCP接続のみを実行し、sourceまたは.組み込み。

34
kasperd

他の回答で説明されているデバイスノード( mknod(2) で作成、または devfs によって提供))に加えて、Linuxには他の「魔法の"特別な 仮想ファイルシステムによって提供されるファイル 、特に/proc/proc(5) を参照、 procfs )および/sys/内( sysfs の説明を参照)。

これらの疑似ファイル( stat(2) -では、デバイスではなく通常のファイルとして表示される)は、カーネルによって提供される仮想ビューです。特に、/proc/から(たとえば、cat /proc/$$/mapsを使用して、または open(2) -ing /proc/self/statusをプログラムで)読み取っても、通常はディスクまたはネットワークからの物理I/Oを伴うため、非常に高速です。

/proc/に追加の疑似ファイルを作成するには、通常、独自の kernel module を記述してロードする必要があります(たとえば、 this を参照) )。

19

これらはデバイスノードと呼ばれ、mknodを使用して手動で、またはudevによって自動的に作成されます。それらは通常、カーネル内のドライバーを備えたキャラクターまたはブロックデバイスへのファイルのようなインターフェイスです。ディスクはブロックデバイスであり、ttyやシリアルポートなどはキャラクターデバイスです。

名前付きパイプ、FIFO、ソケットなど、他の「特殊な」ファイルタイプもあります。

13
cas

Linux Device Drivers (強く推奨)はこれを詳細に説明しており、例としてこれを行うカーネルモジュールを作成していますが、簡単に言えば、各デバイスドライバーには特定の関数が呼び出されます「特別な」ファイルは、ディスク上のストレージハードウェアにアクセスするのではなく、これらの関数内で特別なことを行うだけです。

たとえば、/dev/nullの書き込み関数は、バイトを無視して何もしません。 /dev/randomの読み取り関数は乱数を返します。

6
Karl Bielefeldt

mount -t devtmpfs

最近のシステムでは、/devは通常、どこにでもマウントできるファイルシステムタイプであることがわかります。 Ubuntu 16.04:

mkdir d
Sudo mount -t devtmpfs none d
head -c 10 d/random
Sudo umount d

これはCONFIG_DEVTMPFS=yによって有効にされ、カーネル自体が必要に応じてデバイスファイルを作成および破棄できるようにします。

CONFIG_DEVTMPFS_MOUNT=y

このオプションにより、カーネルは/devにdevtmpfsを自動マウントします。

drivers/base/Kconfig ドキュメント:

config DEVTMPFS_MOUNT
    bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs"
    depends on DEVTMPFS
    help
      This will instruct the kernel to automatically mount the
      devtmpfs filesystem at /dev, directly after the kernel has
      mounted the root filesystem. The behavior can be overridden
      with the commandline parameter: devtmpfs.mount=0|1.
      This option does not affect initramfs based booting, here
      the devtmpfs filesystem always needs to be mounted manually
      after the rootfs is mounted.
      With this option enabled, it allows to bring up a system in
      rescue mode with init=/bin/sh, even when the /dev directory
      on the rootfs is completely empty.

file_operations

最後に、独自のキャラクターデバイスカーネルモジュールを作成して、何が起こっているのかを正確に確認する必要があります。

次に、最小限の実行可能な例を示します。 キャラクターデバイス(またはキャラクタースペシャル)ファイルについて

最も重要なステップは、file_operations構造体を設定することです。例:

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = read,
    .open = open,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

ファイル関連のシステムコールごとに呼び出される関数ポインタが含まれています。

次に、これらのファイル関連のシステムコールをオーバーライドして、好きなように実行できることが明らかになります。これが、カーネルが/dev/zeroのようなデバイスを実装する方法です。

mknodなしで/devエントリを自動的に作成します

最後の謎は、カーネルが/devエントリを自動的に作成する方法です。

このメカニズムは、次のように自分でカーネルモジュールを作成することで確認できます。 https://stackoverflow.com/questions/5970595/how-to-create-a-device-node-from-the- init-module-code-of-a-linux-kernel-module/45531867#45531867 そして、device_create呼び出しになります。