Linuxにはファイルを開くためのシステム階層/スクリプトがありますか?

Linuxにはファイルを開くためのシステム階層/スクリプトがありますか?

Linuxには、ファイルを開くためのプログラム要求を処理するレイヤ/スクリプトがありますか?

Bashでファイル記述子を開くときと同じです。exec 3 <>/documents/foo.txtまたは、テキストエディタが開いたときと同じです。/documents/foo.txt

編集者が独自の読み取り/書き込みアクセスのために「ファイルを開く」ことができるとは信じられません。

むしろこれが「レイヤー」に対する要請だと思います(init.dスクリプト?)、最初は特定の数のファイルのみを開くことができ、アクセスタイプ、ファイルを開いたプロセスなどに応じて開こうとしているファイルを注意深く観察できます。

答え1

このレイヤーはLinuxや他のシステムのカーネル内にあり(ほとんどの非Unixオペレーティングシステムと同様)、歴史的なUnixデザインとは大きく変わりません。

カーネルのこの部分をカーネルといいます。VFS(仮想ファイルシステム)層。 VFSの機能は、開いたファイルの情報(ファイル間対応)を管理することです。ファイル記述子ファイル説明を開くおよびディレクトリエントリ)、ファイルパスを確認し(および解釈)、ディレクトリエントリの操作を/正しいファイルシステムドライバに渡します。...

ほとんどのファイルシステムドライバもカーネルにありますが、ヒューズファイルシステムドライバを使用すると、この機能をカーネルの外部に委任できます。たとえば、ディスクファイルシステムがある場合など、低レベルのリポジトリで実行されている場合、ファイルシステムの操作にはユーザードメインコードが含まれる場合があります。循環装置

答え2

Linuxでは、ファイルを開くことはカーネルによって直接処理されます。しかし、プロセスに影響を与え、研究するためにできることがあります。


Linuxストレージスタック図


システムコール

一番上から、アプリケーションがファイルと対話するために使用するインターフェースが次のようになります。システムコール

開いている読むそして書くその間期待どおりにしなさい統計資料ファイルを開かずにファイルに関する情報を返します。

straceを使用して、プログラムのファイル関連システムコールの使用を調べることができます。

$ strace -e trace=%file /bin/ls /etc
[...]
stat("/etc", {st_mode=S_IFDIR|0755,  ...}) = 0
openat(AT_FDCWD, "/etc", O_RDONLY...) = 3

これは、結果のシステムコールを分析し、ディレクトリ内およびが呼び出されていることls /etcを示しています。statopenat/etc

ディレクトリからファイル操作を呼び出す理由は疑問に思います。 UNIXでは、ディレクトリもファイルです。実際にすべてがファイルです


ファイル記述子

openat() = 3上記の出力内容が何であるか疑問に思います。

UNIXでは、ファイルが次に開きます。ファイル記述子、これはプロセスで開かれたファイルの唯一の表現です。ファイル記述子0、1、2は通常予約されています。標準ストリーム(ユーザー入力/出力)なので、初めて開くファイルは3になります。

以下を使用して、特定のプロセスに対して開かれたファイル記述子のリストを取得できます。lsofSティーああペンF島):

$ cat /dev/urandom > /dev/null &
[1] 3242
$ lsof -p 3242
COMMAND  PID      USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
...
cat     3242 user         0u   CHR  136,0      0t0      3 /dev/pts/0
cat     3242 user         1w   CHR    1,3      0t0   1028 /dev/null
cat     3242 user         2u   CHR  136,0      0t0      3 /dev/pts/0
cat     3242 user         3r   CHR    1,9      0t0   1033 /dev/urandom

このFD列にはファイル記述子番号とアクセス権が表示されます。

また、使用することができますfuser特定のファイルを保存するプロセスを検索します。

$ fuser /dev/urandom
/dev/urandom:         ...  3242  ...

プロセス情報擬似ファイルシステム-/proc

今あなたは疑問に思うでしょう:しかし、何をすべきlsof

さあ、一度見てみましょう!

$ strace -e trace=%file lsof -p 3242
...
stat("/proc/3242/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/3242/stat", O_RDONLY) = 4
...
openat(AT_FDCWD, "/proc/3242/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
readlink("/proc/3242/fd/0", "/dev/pts/0", 4096) = 10
lstat("/proc/3242/fd/0", {st_mode=S_IFLNK|0700, st_size=64, ...}) = 0
stat("/proc/3242/fd/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
openat(AT_FDCWD, "/proc/3242/fdinfo/0", O_RDONLY) = 7
...

したがって、lsofどのファイルを開くかを確認してください。より多くのファイルを読んでください!特に、ディレクトリ/proc/3242/fdの下のすべては、/procカーネルが保持する「偽の」ファイルシステムです。ls -lずっと見ながらその構造を見ることができます。


ファイルを開くのに影響します

ファイルを開くことに影響を与えるために使用できる方法はいくつかありますが、一部のスクリプトを置き換えるのと同じくらい簡単ではありません。

暗号化、キャッシュ、複数のディスクへのファイルの分散など、ファイルの保存やアクセス方法を変更したい場合は、デバイスマッパーあなたのニーズに適しています。

特定のディレクトリ/マウントでファイルを開くことを細かく制御するには、次のように簡単に作成できます。ヒューズファイルシステムをマウントしてマウントします。

プログラム/プロセスレベルでは、次のものを使用できます。LD_予圧Cライブラリ呼び出しを変更し、通常のシステム呼び出しが実行されないようにします。

最も難しいが最も柔軟な方法は、独自のファイルシステムドライバを作成することです。

答え3

ファイルへのアクセスを管理することは、オペレーティングシステムの最初で最も重要な機能です。 DOSは、パーソナルコンピュータで最も古いオペレーティングシステムの1つであり、ディスクオペレーティングシステムを意味します。ほとんどの場合、プログラムはハードウェアに直接アクセスできますが、ファイルにはアクセスできません。プログラムはDOS呼び出しを使用する必要があり、DOSはプログラムがデータを入れたり減算したりするファイルを管理します。ディスクユーティリティのみがDOSからハードドライブとファイルに直接アクセスできます。

最新の保護モードオペレーティングシステム(Linuxなど)はDOSのようにファイルアクセスを処理しますが、プログラム自体(またはメモリを共有するように設定された他のプログラム)以外のすべてのアクセスはカーネル(Linuxはカーネルです)

LinuxのプログラムはCライブラリの関数を呼び出してファイルデータを読み取ったり、ファイルにデータを書き込むことができます。その後、C ライブラリは、プログラムと同じコンテキストで実行され続けながら、ファイル内のデータへのアクセスを構成する役割を果たします。その後、Cライブラリはカーネル(Linux)への正しい関数呼び出しを使用してファイルにアクセスし、CPUをリング0または特権モードに切り替えます。これで、CPUはLinuxファイルシステムドライバとハードディスクドライバソフトウェアを特権モードで実行し、ハードウェアに直接アクセスしてファイルにアクセスします。データは、CライブラリがLinuxにデータを配置するように指示し、CPUがユーザモードに戻り、プログラムのセキュリティコンテキストを持ち、Cライブラリが再開され、必要なすべての処理を実行するメモリ領域にコピーされます。その後、このデータは実行のためにプログラムに返されます。

答え4

簡単に言えば、これはプログラムがファイルに書き込むときに起こるものです。

  1. プログラムは、open書き込みのためにカーネルのパスで指定されたファイルを要求します。
  2. カーネルはいくつかの内部構造を設定し、ファイルを開くいくつかの操作をファイルシステムタイプに関連するドライバに委任します。その後、カーネルは整数(例:3)のファイル記述子をプログラムに返します。
  3. writeプログラムは、カーネルにファイル記述子が参照するファイルに一連のバイト(文字列など)を追加するように要求します。
  4. カーネルは再びオペレーションをドライバに委任します。
  5. ステップ3と4は何度も繰り返すことができます。
  6. closeプログラムは、ファイル記述子が参照するファイルをカーネルに要求します。
  7. カーネルは再びオペレーションをドライバに委任し、内部構造を破壊する。

以下は、Greeting.txtファイルに「Hello World!」を書く非常に簡単なアセンブラプログラムです。

.text
.globl _start

_start:
    # Open and possible create file
    mov $2,             %rax        # syscall 'open'
    mov $path_start,    %rdi        # path
    mov $0101,          %rsi        # create + write
    mov $400,           %edx        # only user gets read permissions
    syscall

    mov %rax,           %r10        # file descriptor

    # Write string to file
    mov $1,             %rax        # syscall 'write'
    mov %r10,           %rdi        # file descriptor
    mov $msg_start,     %rsi        # start of data
    mov $msg_length,    %edx        # length of data
    syscall                         # perform syscall

    # Close file
    mov $3,             %rax        # syscall 'close'
    mov %r10,           %rdi        # file descriptor
    syscall

    # Exit program
    mov $60,            %rax        # syscall 'exit'
    syscall                         # perform syscall


.section .rodata

path_start:
    .string "greeting.txt\0"
path_end:
path_length = path_end - path_start


msg_start:
    .string "Hello World!\n"
msg_end:
msg_length = msg_end - msg_start

コードをwrite.sに保存して次にビルドします。

as -o write.o write.s
ld -o write   write.o

その後実行

./write

すべてが大丈夫であることを願っています。

(注:エラー処理は行いません。これはおもちゃのコードです。)

関連情報