代替 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"); }