Linux核心模組程式設計/proc 檔案系統(轉)

worldblog發表於2007-08-10
Linux核心模組程式設計/proc 檔案系統(轉)[@more@]

  /proc 檔案系統

  在Linux中有額外的機制可以為核心和核心模組將資訊傳送給程式 -- /proc 檔案系統。最初設計的目的是允許更方便的對程式資訊進行訪問(因此得名),現在它被每一個有有趣的東西報告的核心使用,例如 /proc/modules 有模組的列表 /proc/meminfo 有記憶體使用的統計表。

  使用proc 檔案系統的方法和使用裝置驅動程式非常相似--建立一個 /proc 檔案需要的所有資訊的結構,包括任何處理函式的指標(在我們的例子中只有一個,當某人試圖從 /proc 檔案讀時呼叫的那一個)。然後,init_module 在核心中登記該結構而cleanup_module 登出它。

  我們使用 proc_register_dynamic(這是在 2.0 版中的情況,在 2.2 版中如果我們將節點設定為0系統將自動為我們做到) 的原因是我們不想預先決定我們的檔案的節點數字,而是為防止衝突而由核心決定它。通常的檔案系統存在於磁碟上而不是記憶體中(/proc 在記憶體中),在這中情況下,節點數是是指向檔案的索引節點所在的磁碟位置的指標。節點包含檔案的資訊(例如檔案的存取許可權)和指向磁碟位置或檔案資料可以被找到的幾個位置的指標。

  因為當檔案被開啟或關閉的時候不能得到呼叫,所以在這個模組中沒有地方放置 MOD_INC_USE_COUNT 和 MOD_DEC_USE_COUNT,並且,如果檔案被開啟隨後模組被移除,我們沒有辦法避免後果。在下一 章我們會看到一個艱難的但更靈活的可以處理/proc檔案的實現方式,它也可以讓我們防止那個問題。

  範例 procfs.c

  /* procfs.c - create a "file" in /proc

* Copyright (C) 1998-1999 by Ori Pomerantz

*/

/* 必要的標頭檔案 */

/* 核心模組標準標頭檔案 */

#include /* 核心工作 */

#include /* 明確指定是模組 */

/* 處理CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include

#endif

/* 使用proc 檔案系統所必要的 */

#include

/* 在 2.2.3 版/usr/include/linux/version.h 中包含這個宏

* 但 2.0.35 版不包含 - 因此我在此加入這個以防需要。 */

#ifndef KERNEL_VERSION

#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))

#endif

/* 將資料放入 proc 檔案

引數

====

1. 如果你決定使用緩衝區,資料應該被插入它。

2. 字元指標的指標。如果你不想使用由核心分配的緩衝區時這將有用。

3. 檔案的當前位置。

4. 第一個引數中的緩衝區的大小。

5. Zero (為將來使用?)。

用法和返回值

============

如果你像我那樣使用自己的緩衝區,將它放在第二個引數的位置並返回在那個緩衝區中使用的位元組數。

返回值為0 意味著這次沒有更多資訊(檔案尾)。負數返回值是錯誤條件。

更多資訊

========

我不是透過讀文件而發現用這個函式去做什麼的,而是透過讀使用它的程式碼。我只想看看什麼使用了

proc_dir_entry的get_info成員(如果你有興趣的話,我使用了一個查詢和搜尋的組合),我發現它被

/fs/proc/array.c使用。

如果有什麼關於核心的事情不清楚,這是一個通常的辦法。在 Linux 中我們有自由的獲取原始碼的巨大優勢--使用它。

*/

int procfile_read(char *buffer,

char **buffer_location,

off_t offset,

int buffer_length,

int zero)

{

int len; /* The number of bytes actually used */

/* 這是靜態的,因此當我們離開這個函式時它還會待在記憶體中 */

static char my_buffer[80];

static int count = 1;

/* 我們將所有的資訊放在一個裡面,所以如果使用者問是否有更多的資訊,答案總是“沒有”。

*

* 這是很重要的,因為來自庫的標準讀函式將持續釋出讀系統呼叫直到核心答覆沒有更多資訊

* 或它的緩衝區被填滿。

*/

if (offset > 0)

return 0;

/* 填充緩衝區並得到長度 */

len = sprintf(my_buffer,

"For the %d%s time, go away! ", count,

(count % 100 > 10 && count % 100 < 14) ? "th" :

(count % 10 == 1) ? "st" :

(count % 10 == 2) ? "nd" :

(count % 10 == 3) ? "rd" : "th" );

count++;

/* 告訴呼叫函式緩衝區在哪兒*/

*buffer_location = my_buffer;

/* 返回長度 */

return len;

}

struct proc_dir_entry Our_Proc_File =

{

0, /* 節點數 - 忽略,它將被 proc_register[_dynamic] 填充*/

4, /* 檔名長度 */

"test", /* 檔名*/

S_IFREG | S_IRUGO, /* 檔案模式 - 這是一個可以被擁有者,使用者組和其他所有的使用者讀取的

* 普通檔案 */

1, /* 連線數 (檔案被引用的目錄數) */

0, 0, /* 檔案的UID和GID - 我們將它賦予 root */

80, /* 用ls報告的檔案大小。 */

NULL, /* 使用節點的函式(連線,刪除,等等)--我們不支援 */

procfile_read, /* 對這個檔案的讀函式,當某人試圖蔥它讀入什麼時被呼叫。 */

NULL /* 我們能夠在這兒有一個填充檔案節點的函式,允許我們修改許可權和擁有權,等等。 */

};

/* 初始化模組--登記 proc 檔案 */

int init_module()

{

/* proc_register[_dynamic] 成功則成功,否則失敗。 */

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)

/* 在 2.2版中,如果在這個結構中它為0則 proc_register 自動的分配一個動態的節點數

* 因此不再需要proc_register_dynamic

*/

return proc_register(&proc_root, &Our_Proc_File);

#else

return proc_register_dynamic(&proc_root, &Our_Proc_File);

#endif

/* proc_root 是 proc檔案系統的根目錄。這是我們想讓我們的檔案所處的位置 */

}

/* 清除 - 從 /proc中登出我們的檔案 */

void cleanup_module()

{

proc_unregister(&proc_root, Our_Proc_File.low_ino);

}

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-940230/,如需轉載,請註明出處,否則將追究法律責任。

相關文章