The proc File System:

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 */


proc_1.jpg

proc_2.jpg

proc_3.jpg

發佈了42 篇原創文章 · 獲贊 4 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章