60 lines
2.6 KiB
C
60 lines
2.6 KiB
C
/*
|
||
* print_string.c - 将输出发送到我们运行的tty,无论是通过X11、telnet等。我们通过将字符串打印到当前任务关联的tty
|
||
*/
|
||
#include <linux/init.h>
|
||
#include <linux/kernel.h>
|
||
#include <linux/module.h>
|
||
#include <linux/sched.h> /* 引入 current */
|
||
#include <linux/tty.h> /* 引入 tty 相关声明 */
|
||
|
||
static void print_string(char *str)
|
||
{
|
||
/* 当前任务的tty */
|
||
struct tty_struct *my_tty = get_current_tty();
|
||
|
||
/* 如果my_tty为NULL,则当前任务没有可以打印的tty(例如,如果它是一个守护进程)。如果是这样,我们无法执行任何操作 */
|
||
if (my_tty) {
|
||
const struct tty_operations *ttyops = my_tty->driver->ops;
|
||
/* my_tty->driver是一个包含tty函数的结构体,其中一个函数(write)用于将字符串写入tty。
|
||
* 它可以用于从用户或内核的内存段获取字符串。
|
||
*
|
||
* 该函数的第一个参数是要写入的tty,因为同样的函数通常会用于所有相同类型的tty。
|
||
* 第二个参数是指向字符串的指针。第三个参数是字符串的长度。
|
||
*
|
||
* 如下所示,有时需要使用预处理器来创建适用于不同内核版本的代码。我们在这里采取的方法不具备通用性
|
||
* 处理这种情况的正确方法在linux/Documentation/SubmittingPatches的第2节中有描述。
|
||
*/
|
||
(ttyops->write)(my_tty, /* tty本身 */
|
||
str, /* 字符串 */
|
||
strlen(str)); /* 长度 */
|
||
|
||
/* tty最初是硬件设备,通常严格遵循ASCII标准。在ASCII中,要换行需要两个字符,即回车符(结束当前行)和换行符(开始新行)。
|
||
* 在Unix中,ASCII换行符用于两个目的 - 因此我们不能只使用\n,因为它没有回车符,下行会在换行符后的列开始。
|
||
*
|
||
* Unix 和 MS Windows 的文本文件格式因而有所不同
|
||
* - Unix 文本文件使用单一的 LF(\n),在显示或编辑时会在每个 LF 位置换行。
|
||
* - Windows 文本文件使用 CR+LF(\r\n),在显示或编辑时会在每个 CR+LF 位置换行。
|
||
*
|
||
* \015 代表 Carriage Return (CR),即 ASCII 值为 13
|
||
* \012 代表 Line Feed (LF),即 ASCII 值为 10
|
||
*/
|
||
(ttyops->write)(my_tty, "\015\012", 2);
|
||
}
|
||
}
|
||
|
||
static int __init print_string_init(void)
|
||
{
|
||
print_string("模块已插入。你好, 世界! ");
|
||
return 0;
|
||
}
|
||
|
||
static void __exit print_string_exit(void)
|
||
{
|
||
print_string("模块已移除。再见, 世界! ");
|
||
}
|
||
|
||
module_init(print_string_init);
|
||
module_exit(print_string_exit);
|
||
|
||
MODULE_LICENSE("GPL");
|