The proc File System:
在這篇摘抄的文章裏,我們主要介紹一下此文件系統是如何工作的,以及現有的網絡代碼是如何使用這個文件系統的,以及我們在程序
中如何寫,使用proc entry。
Overview:
proc文件系統在很多程序中被頻繁的使用,儘管它被設計成像其它文件系統那樣有目錄結構和inode,但事實上,是一些註冊了的函數
,它們提供了重要的系統變量的信息。
proc目錄有很多的子目錄-每一個運行中的進程一個以及一些關於子系統的,如文件系統,接口,終端,網絡(/proc/net)。在
/proc主目錄中也有許多的文件-interrupts,ioports,loadavg等等。在每個進程的子目錄中的文件描述此進程的一些信息,如command
line, current working directory, status等等。
內核監視所有對proc文件系統的訪問,用特殊的函數來替代普通的文件操作函數。當一個在/proc目錄下的文件被創建時,它向內核注
冊一些函數來告訴內核如果本文件被讀或者寫的話,應該如何操作。許多的file只允許讀操作,向控制檯打印一些狀態信息而已。
需要注意的一點是:內核在每次讀操作時,呼叫產生狀態信息的函數,因此如果沒有一次讀完的情況下,接下來的讀操作可能會覆蓋原
有的信息,所以我們最好一次讀完狀態信息,最好的方法是提供一個大的緩衝區,如PAGE_SIZE字節大小最好,可以一次讀完。
Network proc Files:
arp 顯示neighbor table(arp_tbl);ip地址/硬件地址,硬件類型,設備,標誌等。(arp_get_info():net/ipv4/arp.c)
dev 顯示每個註冊了的設備的統計信息。
dev_stat 顯示接收到/丟棄的包的數量以及FASTROUTE統計信息(dev_proc_stats():net/core/dev.c)
netstat display sync cookie, pruning, and ICMP statistics(netstat_get_info():net/ipv4/proc.c)
raw 爲每一個已經打開的原始套接字根據struct proto raw_prot來顯示地址,隊列以及超時信息。(
get_netinfo():net/ipv4/proc.c)
route 顯示FIB表(main_table),the interface, address, gateway, flags, and usage information
(fib_get_procinfo()):net/ipv4/fib_frontend.c)
rt_cache 顯示routing cache(rt_hash_table), the interface, address, gateway, usage,source, and other
infomation. (rt_cache_get_info() : net/ipv4/route.c)
sockstat display number of sockets that have been used and some statistics on how many were TCP, UDP,
and RAW(afinet_get_info() : net/ipv4/proc.c)
tcp display address, queue, and timeout information for each open TCP socket form struct proto tcp_prot
(get__netinfo() : net/ipv4/proc.c)
udp display address, queue, and timeout information for each open UDP socket form struct proto udp_prot
(get__netinfo() : net/ipv4/proc.c)
註冊proc文件:
這段中我們介紹一個最簡單的註冊只讀proc文件的方法(只適合linux 2.0及其以後的版本),我們可以通過實現file_operations
和inode_operations結構來使它具有更多的功能。但是後者比我們提到的第一種方法複雜,可以看看源代碼來得知後者如何實現。下面提及的
方法:定義一個函數,然後registering/unregisteriing這個函數到內核中,提供了絕大多數測試、跟蹤系統資源的方法。但要注意:只有
內核能註冊proc文件,用戶可以創建/安裝內核模塊(root用戶身份)。下面的過程假設已經安裝上了linux源代碼,並且內核被編譯成允許使
用模塊。
格式化提供信息的函數(Formatting a Function to Provide Information)
static int read_proc_function(char *buf, char **start, off_t offset, int len, int unused)
以上是linux內核在它讀proc文件時要調用的函數原型。其中最重要的一個參數時buf,一個指向緩衝區的指針,供內核儲存輸出的信
息。其它的參數一般不會改變。
一般來說,這個函數打印一個頭部(header),然後遍歷表,打印出它的內容(使用sprintf),並返回結果字符串的長度,唯一的限
制是buf不能超過PAGE_SIZE大小(PAGE_SIZE最小是4kb)。
創建proc條目:
因爲是文件系統的一部分,所以這個entry需要一個inode,可以使用proc_dir_entry結構來搞定。
#include <linux/proc_fs.h>
struct proc_dir_entry new_proc_entry = {
0, // low_ino - inode number (0 for dynamic)
5, // namelen - length of entry name
"entry", // name
S_IFREG | S_IRUGO // mode
1, // nlinks
0, // uid - owner
0, // gid - group
0, // size - not used
NULL, // ops - inode operations (use default)
&read_proc_function // read_proc - address of read function
// leave rest blank!
}
以上得我們可以複用,只需要改改name, namelen和read_proc字段就可以了。不過內核定義了許多得條目,使用它們自己得inode
number(如PROC_NET_ROUTE),注意不要與之衝突。(在include/linux/proc_fs.h)
註冊一個proc條目:
int proc_register(struct proc_dir_entry *dir, struct proc_dir_entry *entry)
int proc_net_register(struct proc_dir_entry *entry)
dir指向一個entry所屬的目錄-&proc_root和proc_net(include/proc_fs.h)可能是最有用的。entry是指向自己的指針,以上
兩個函數是相同的,除了第二個使用proc/net做爲目錄。返回0(成功)或者EAGAIN(沒有可利用的inode)。
卸載一個proc條目:
int proc_unregister(struct proc_dir_entry *dir, int inode)
int proc_net_unregister(int inode)
dir是文件(條目)駐留的目錄,inode是此文件的inode編號(proc_dir_entry.low_ino),第二個函數使用/proc/net目錄。返
回0(成功)或者EAGAIN(沒有可利用的inode)。
例子:
simple_entry.c
/* simple_entry.c
*
* This program provides an example of how to install an entry into the
* /proc File System. All this entry does is display some statistical
* information about IP.
*/
#define MODULE
#include <linux/module.h>
/* proc_fs.h contains proc_dir_entry and register/unregister prototypes */
#include <linux/proc_fs.h>
/* ip.h contains the ip_statistics variable */
#include <net/ip.h>
/* show_ip_stats
* this function is what the /proc FS will call when anything tries to read
* from the file /proc/simple_entry - it puts some of the kernel global
* variable ip_statistics's contents into the return buffer
*/
int
show_ip_stats(char *buf, char **start, off_t offset, int len, int unused)
{
len = sprintf(buf, "Some IP Statistics:/nIP Forwarding is ");
if( ip_statistics.IpForwarding )
len += sprintf(buf+len, "on/n");
else
len += sprintf(buf+len, "off/n");
len += sprintf(buf+len, "Default TTL: %lu/n", ip_statistics.IpDefaultTTL);
len += sprintf(buf+len, "Frag Creates: %lu/n", ip_statistics.IpFragCreates);
/* this could show more... */
return len;
} /* show_ip_stats */