proc ファイル システムは、Linux カーネルの現在の状態を反映しています。
カーネルの現在の状態は、その上で実行されているプロセス、ハードウェア情報、ネットワーク情報などのさまざまな情報を表すことができます。そのため、このシステムは、ユーザー レベルのプロセスがこれらすべての情報に簡単にアクセスできるように設計されています。
procファイルシステムは疑似ファイルシステムとも言います。これは、このファイル システム内のファイルがアクセスされたときに情報がロードされ、このファイル システム内のファイルのサイズが通常ゼロになる理由です。
システムで ls /proc を実行すると、次のような結果が表示されます:
$ ls /proc 1 15 1681 1719 35 60 713 878 cgroups filesystems kpageflags pagetypeinfo sysrq-trigger ....
したがって、このファイル システムにはファイルとディレクトリが含まれていることがわかります。ファイルまたはディレクトリの名前は、アルファベットまたは数字です。数値のファイル名またはディレクトリ名は、ほとんどの場合、システムで実行されているプロセスに対応しており、数字はプロセスのプロセス ID を表しています。そのため、プロセス ID を使用して対応するファイルを開くことで、プロセスに関するカーネル レベルの情報を簡単に知ることができます。
この記事では、ローダブル カーネル モジュール (LKM) に関する知識を基に構築し、これらの proc ファイルがどのように作成、読み取り、書き込みされるかについて説明します。
/proc の下にあるさまざまなファイルを理解するには、Linux proc ファイル システムに関する以前の記事を参照してください。
Proc ファイルの作成
Linux カーネル モジュールに関する記事では、LKM の作成、ロード、およびアンロードの方法について説明しました。これが、実行時に Linux カーネルに機能を追加するための基本的な概念でした。 proc ファイルは同じ原理で機能します。各 proc ファイルは、LKM の形式で作成、ロード、およびアンロードされます。
次のコードでは、proc ファイルを作成し、その読み取りおよび書き込み機能を定義しようとしています。
#include <linux/module.h> #include <linux/kernel.h> #include <linux/proc_fs.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> #define MAX_LEN 4096 int read_info( char *page, char **start, off_t off,int count, int *eof, void *data ); ssize_t write_info( struct file *filp, const char __user *buff,unsigned long len, void *data ); static struct proc_dir_entry *proc_entry; static char *info; static int write_index; static int read_index; int init_module( void ) { int ret = 0; info = (char *)vmalloc( MAX_LEN ); memset( info, 0, MAX_LEN ); proc_entry = create_proc_entry( "procEntry123", 0644, NULL ); if (proc_entry == NULL) { ret = -1; vfree(info); printk(KERN_INFO "procEntry123 could not be created\n"); } else { write_index = 0; read_index = 0; proc_entry->read_proc = read_info; proc_entry->write_proc = write_info; printk(KERN_INFO "procEntry123 created.\n"); } return ret; } void cleanup_module( void ) { remove_proc_entry("procEntry123", proc_entry); printk(KERN_INFO "procEntry123 unloaded.\n"); vfree(info); } ssize_t write_info( struct file *filp, const char __user *buff, unsigned long len, void *data ) { int capacity = (MAX_LEN-write_index)+1; if (len > capacity) { printk(KERN_INFO "No space to write in procEntry123!\n"); return -1; } if (copy_from_user( &info[write_index], buff, len )) { return -2; } write_index += len; info[write_index-1] = 0; return len; } int read_info( char *page, char **start, off_t off, int count, int *eof, void *data ) { int len; if (off > 0) { *eof = 1; return 0; } if (read_index >= write_index) read_index = 0; len = sprintf(page, "%s\n", &info[read_index]); read_index += len; return len; }
上記のコードでは:
- init_module 関数では、「create_proc_entry」関数を使用して「procEntry123」という名前の proc ファイルを作成しました
- create_proc_entry 関数の 2 番目の引数で説明されているように、ファイルは適切な権限で作成されます。
- proc ファイルの読み取りと書き込みには、read_info と write_info の 2 つの関数が使用されます。
- これら 2 つの関数のアドレスは、proc_dir_entry 構造体のメンバーに割り当てられます。
- 上記の手順は、proc ファイルの読み取りおよび書き込み時に呼び出す関数をコードが認識できるようにするために行われました。
- write_info 関数では、バッファに書き込む容量がある場合、関数 copy_from_user を使用して、ユーザー空間からカーネル モジュールに割り当てられたメモリ バッファに文字列をコピーします。
- 関数 read_info では、バッファに存在する情報がユーザー空間に送り返されます。
上記のコードの Makefile は次のようになります:
$ cat Makefile obj-m += proc.o all: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
上記のコードをコンパイルすると、次のようになります:
$ make sudo make -C /lib/modules/2.6.32-21-generic/build M=/home/himanshu modules make: Entering directory `/usr/src/linux-headers-2.6.32-21-generic' CC [M] /home/himanshu/proc.o /home/himanshu/proc.c: In function ‘init_module’: /home/himanshu/proc.c:33: warning: assignment from incompatible pointer type Building modules, stage 2. MODPOST 1 modules LD [M] /home/himanshu/proc.ko make: Leaving directory `/usr/src/linux-headers-2.6.32-21-generic'
コードが正常にコンパイルされると、モジュールが挿入され、次のコマンドによってロードされます:
$ sudo insmod proc.ko
挿入後、proc ディレクトリが表示される場合、エントリ「procEntry123」が見つかります。
$ ls /proc/procEntry123 /proc/procEntry123
ここで、書き込みと読み取りを試みると:
$ echo "TGS" > /proc/procEntry123 $ cat /proc/procEntry123 TGS
これで、proc ファイルを読み書きできることがわかります。同様に、すべての標準 proc ファイルが実装されます。