Linuxには、実際にはファイルではない特別なファイルがあります。
これらの最も注目に値する明確な例は、dev
フォルダー内の「ファイル」にあります。
/dev/null
-ファイルへの書き込みをすべて無視します/dev/random
-ファイルの内容ではなくランダムなデータを出力します/dev/tcp
-ネットワーク経由でこのファイルに書き込んだデータを送信しますまず、これらの種類の "ファイル"の名前は、実際にはなんらかのスクリプトまたはバイナリの変装です。
次に、それらはどのように作成されますか?これらのファイルはカーネルレベルでシステムに組み込まれていますか、または「マジックファイル」を自分で作成する方法はありますか(/dev/rickroll
)?
/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のドキュメントでこれについて言及することがあります。それが意味することです。デバイスノードでもシンボリックリンクでもないファイル。魔法のようなプロパティのない、通常の毎日のファイルです。
/dev
エントリのほとんどは、ブロックデバイスiノードまたはキャラクターデバイスiノードです。 ウィキペディアには多くの詳細があります それについて、私は繰り返すつもりはありません。
ただし、質問に記載されている/dev/tcp
は、既存の回答では説明されていません。 /dev/tcp
と/dev/udp
は、他のほとんどの/dev
エントリとは異なります。ブロックデバイスとキャラクターデバイスはカーネルによって実装されますが、/dev/tcp
と/dev/udp
はユーザーモードで実装されます。
Bashシェルは、/dev/tcp
および/dev/udp
(ksh93
からコピー)の実装を持つ1つのプログラムです。 bashリダイレクション演算子を使用してパスの下を開こうとすると、通常のopen
システムコールは実行されません。代わりにbashはTCPソケットを作成し、指定されたポートに接続します。
これは、bash
とcat
に/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
または.
組み込み。
他の回答で説明されているデバイスノード( 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 を参照) )。
これらはデバイスノードと呼ばれ、mknod
を使用して手動で、またはudev
によって自動的に作成されます。それらは通常、カーネル内のドライバーを備えたキャラクターまたはブロックデバイスへのファイルのようなインターフェイスです。ディスクはブロックデバイスであり、ttyやシリアルポートなどはキャラクターデバイスです。
名前付きパイプ、FIFO、ソケットなど、他の「特殊な」ファイルタイプもあります。
本 Linux Device Drivers (強く推奨)はこれを詳細に説明しており、例としてこれを行うカーネルモジュールを作成していますが、簡単に言えば、各デバイスドライバーには特定の関数が呼び出されます「特別な」ファイルは、ディスク上のストレージハードウェアにアクセスするのではなく、これらの関数内で特別なことを行うだけです。
たとえば、/dev/null
の書き込み関数は、バイトを無視して何もしません。 /dev/random
の読み取り関数は乱数を返します。
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
呼び出しになります。