代替 printk
在本書開始的時候,我說過 X 和內核模塊編程不能混合。在開發內核模塊時那是對的,但在實際使用中你想可以向任何向模塊發送命令的終端(Teletype, 最初是用於和Unix系統溝通的鍵盤和打印機的組合,而今天它是用於Unix程序的文本流的抽象,無論它是一個物理的終端 X顯示器上的 xterm 還是用telnet 的網絡連接,等等。)發送消息。這對在內核模塊被釋放後識別錯誤是很重要的,因為它將被所有模塊使用。
實現這個的一個辦法是使用指向當前運行作業的指針 current得到當前作業的終端結構。然後我們在那個終端結構裡面找指向字符串寫函數的指針,我們可以用它向終端寫字符串。
范例 printk.c
/* printk.c - 向你正在運行的終端輸出文本,無論它是否通過 X11, telnet, 等等。 */
/* Copyright (C) 1998 by Ori Pomerantz */
/* 必要頭文件 */
/* 標准頭文件 */
#include /* 內核工作 */
#include /* 明確指定是模塊 */
/* 處理 CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif
/* 必要的 */
#include /* 為了 current */
#include /* 為了終端聲明 */
/* 向當前作業使用的終端打印字符串 */
void print_string(char *str)
{
struct tty_struct *my_tty;
/* 當前作業終端 */
my_tty = current->tty;
/* 如果 my_tty 為 NULL則意味著當前作用沒有你可以打印的終端。
* (這是可能的,例如它是一個守護進程)
* 在這中情況下我們不能做任何事。 */
if (my_tty != NULL) {
/* my_tty->driver 是包含終端函數的結構,它們中的一個(寫)用於向終端寫字符串。
* 它可以用於從用戶內存段或內核內存段取字符串。
*
* 函數的第一個參數是要寫向的終端,因為同一函數通常用於所有的屬某種類型的終端。
* 第二個參數控制是從內核內存段(false,0)還是從用戶內存段(true,非零)接收字符串。
* 第三個參數是指向字符串的指針,第四個是字符串的長度。
*/
(*(my_tty->driver).write)(
my_tty, /* 終端自己 */
0, /* 我們不從用戶空間取字符串 */
str, /* 字符串 */
strlen(str)); /* 長度 */
/* 終端是最初的硬件設備,它(通常)嚴格的堅持 ASCII 標准。
* 根據 ASCII,換行需要兩個字符,回車和走行。另一方面,在Unix 中,
* ASCII 走行符用於這兩個目的-因此我們不能僅僅用 \n,因為它沒有回車,
* 下一行將在上面那行後的走行符的右邊的那列開始而非行首。
*
* 順便說一下,這就是為什麼 Unix 和 Windows的文本文件不同的原因。
* 在 CP/M 和它的派生產品,例如 MS-DOS 和 Windows, ASCII 被嚴格的堅持,因此
* 新行需要走行和回車。
*/
(*(my_tty->driver).write)(
my_tty,
0,
'\015\012',
2);
}
}
/* 初始化和清除模塊 ****************** */
/* 初始化模塊-登記 proc 文件 */
int init_module()
{
print_string('Module Inserted');
return 0;
}
/* 清除 - 從/proc中注銷我們的文件 */
void cleanup_module()
{
print_string('Module Removed');
}