樱的意思:使用/proc文件系统来访问Linux内核(下)
来源:百度文库 编辑:中财网 时间:2024/05/01 23:07:02
page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用start 和 off 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数)。与 write 类似,data表示的也是私有数据。此处提供的 page 缓冲区在内核空间中。因此,我们可以直接写入,而不用调用 copy_to_user。
其他有用的函数
我们还可以使用 proc_mkdir、symlinks 以及 proc_symlink 在 /proc文件系统中创建目录。对于只需要一个 read 函数的简单 /proc 项来说,可以使用create_proc_read_entry,这会创建一个 /proc 项,并在一个调用中对 read_proc函数进行初始化。这些函数的原型如清单 8 所示。
清单 8. 其他有用的 /proc 函数
代码: /* Create a directory in the proc filesystem */
struct proc_dir_entry *proc_mkdir( const char *name,
struct proc_dir_entry *parent );
/* Create a symlink in the proc filesystem */
struct proc_dir_entry *proc_symlink( const char *name,
struct proc_dir_entry *parent,
const char *dest );
/* Create a proc_dir_entry with a read_proc_t in one call */
struct proc_dir_entry *create_proc_read_entry( const char *name,
mode_t mode,
struct proc_dir_entry *base,
read_proc_t *read_proc,
void *data );
/* Copy buffer to user-space from kernel-space */
unsigned long copy_to_user( void __user *to,
const void *from,
unsigned long n );
/* Copy buffer to kernel-space from user-space */
unsigned long copy_from_user( void *to,
const void __user *from,
unsigned long n );
/* Allocate a ‘virtually‘ contiguous block of memory */
void *vmalloc( unsigned long size );
/* Free a vmalloc‘d block of memory */
void vfree( void *addr );
/* Export a symbol to the kernel (make it visible to the kernel) */
EXPORT_SYMBOL( symbol );
/* Export all symbols in a file to the kernel (declare before module.h) */
EXPORT_SYMTAB
通过 /proc 文件系统实现财富分发
下面是一个可以支持读写的 LKM。这个简单的程序提供了一个财富甜点分发。在加载这个模块之后,用户就可以使用 echo 命令向其中导入文本财富,然后再使用 cat 命令逐一读出。
清单 9 给出了基本的模块函数和变量。init 函数(init_fortune_module)负责使用 vmalloc来为这个点心罐分配空间,然后使用 memset 将其全部清零。使用所分配并已经清空的 cookie_pot 内存,我们在 /proc中创建了一个 proc_dir_entry 项,并将其称为 fortune。当 proc_entry 成功创建之后,对自己的本地变量和proc_entry 结构进行了初始化。我们加载了 /proc read 和 write 函数(如清单 9 和清单 10所示),并确定这个模块的所有者。cleanup 函数简单地从 /proc 文件系统中删除这一项,然后释放 cookie_pot 所占据的内存。
cookie_pot 是一个固定大小(4KB)的页,它使用两个索引进行管理。第一个是 cookie_index,标识了要将下一个cookie 写到哪里去。变量 next_fortune 标识了下一个 cookie 应该从哪里读取以便进行输出。在所有的 fortune项都读取之后,我们简单地回到了 next_fortune。
清单 9. 模块的 init/cleanup 和变量
代码: #include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
#define MAX_COOKIE_LENGTH PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *cookie_pot; // Space for fortune strings
static int cookie_index; // Index to write next fortune
static int next_fortune; // Index to read next fortune
int init_fortune_module( void )
{
int ret = 0;
cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );
if (!cookie_pot) {
ret = -ENOMEM;
} else {
memset( cookie_pot, 0, MAX_COOKIE_LENGTH );
proc_entry = create_proc_entry( "fortune", 0644, NULL );
if (proc_entry == NULL) {
ret = -ENOMEM;
vfree(cookie_pot);
printk(KERN_INFO "fortune: Couldn‘t create proc entry\n");
} else {
cookie_index = 0;
next_fortune = 0;
proc_entry->read_proc = fortune_read;
proc_entry->write_proc = fortune_write;
proc_entry->owner = THIS_MODULE;
printk(KERN_INFO "fortune: Module loaded.\n");
}
}
return ret;
}
void cleanup_fortune_module( void )
{
remove_proc_entry("fortune", &proc_root);
vfree(cookie_pot);
printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( cleanup_fortune_module );
向这个罐中新写入一个 cookie 非常简单(如清单 10 所示)。使用这个写入 cookie的长度,我们可以检查是否有这么多空间可用。如果没有,就返回 -ENOSPC,它会返回给用户空间。否则,就说明空间存在,我们使用copy_from_user 将用户缓冲区中的数据直接拷贝到 cookie_pot 中。然后增大cookie_index(基于用户缓冲区的长度)并使用 NULL 来结束这个字符串。最后,返回实际写入 cookie_pot的字符的个数,它会返回到用户进程。
清单 10. 对 fortune 进行写入操作所使用的函数
对 fortune 进行读取也非常简单,如清单 11所示。由于我们刚才写入数据的缓冲区(page)已经在内核空间中了,因此可以直接对其进行操作,并使用 sprintf 来写入下一个fortune。如果 next_fortune 索引大于 cookie_index(要写入的下一个位置),那么我们就将next_fortune 返回为 0,这是第一个 fortune 的索引。在将这个 fortune 写入用户缓冲区之后,在next_fortune 索引上增加刚才写入的 fortune 的长度。这样就变成了下一个可用 fortune 的索引。这个 fortune的长度会被返回并传递给用户。
清单 11. 对 fortune 进行读取操作所使用的函数
代码: int fortune_read( char *page, char **start, off_t off,
int count, int *eof, void *data )
{
int len;
if (off > 0) {
*eof = 1;
return 0;
}
/* Wrap-around */
if (next_fortune >= cookie_index) next_fortune = 0;
len = sprintf(page, "%s\n", &cookie_pot[next_fortune]);
next_fortune += len;
return len;
}
从这个简单的例子中,我们可以看出通过 /proc 文件系统与内核进行通信实际上是件非常简单的事情。现在让我们来看一下这个 fortune 模块的用法(参见清单 12)。
清单 12. 展示 fortune cookie LKM 的用法
代码: [root@plato]# insmod fortune.ko
[root@plato]# echo "Success is an individual proposition. Thomas Watson" > /proc/fortune
[root@plato]# echo "If a man does his best, what else is there? Gen. Patton" > /proc/fortune
[root@plato]# echo "Cats: All your base are belong to us. Zero Wing" > /proc/fortune
[root@plato]# cat /proc/fortune
Success is an individual proposition. Thomas Watson
[root@plato]# cat /proc/fortune
If a man does his best, what else is there? General Patton
[root@plato]#
/proc 虚拟文件系统可以广泛地用来报告内核的信息,也可以用来进行动态配置。我们会发现它对于驱动程序和模块编程来说都是非常完整的。在下面的 参考资料 中,我们可以学习到更多相关知识。
其他有用的函数
我们还可以使用 proc_mkdir、symlinks 以及 proc_symlink 在 /proc文件系统中创建目录。对于只需要一个 read 函数的简单 /proc 项来说,可以使用create_proc_read_entry,这会创建一个 /proc 项,并在一个调用中对 read_proc函数进行初始化。这些函数的原型如清单 8 所示。
清单 8. 其他有用的 /proc 函数
代码: /* Create a directory in the proc filesystem */
struct proc_dir_entry *proc_mkdir( const char *name,
struct proc_dir_entry *parent );
/* Create a symlink in the proc filesystem */
struct proc_dir_entry *proc_symlink( const char *name,
struct proc_dir_entry *parent,
const char *dest );
/* Create a proc_dir_entry with a read_proc_t in one call */
struct proc_dir_entry *create_proc_read_entry( const char *name,
mode_t mode,
struct proc_dir_entry *base,
read_proc_t *read_proc,
void *data );
/* Copy buffer to user-space from kernel-space */
unsigned long copy_to_user( void __user *to,
const void *from,
unsigned long n );
/* Copy buffer to kernel-space from user-space */
unsigned long copy_from_user( void *to,
const void __user *from,
unsigned long n );
/* Allocate a ‘virtually‘ contiguous block of memory */
void *vmalloc( unsigned long size );
/* Free a vmalloc‘d block of memory */
void vfree( void *addr );
/* Export a symbol to the kernel (make it visible to the kernel) */
EXPORT_SYMBOL( symbol );
/* Export all symbols in a file to the kernel (declare before module.h) */
EXPORT_SYMTAB
通过 /proc 文件系统实现财富分发
下面是一个可以支持读写的 LKM。这个简单的程序提供了一个财富甜点分发。在加载这个模块之后,用户就可以使用 echo 命令向其中导入文本财富,然后再使用 cat 命令逐一读出。
清单 9 给出了基本的模块函数和变量。init 函数(init_fortune_module)负责使用 vmalloc来为这个点心罐分配空间,然后使用 memset 将其全部清零。使用所分配并已经清空的 cookie_pot 内存,我们在 /proc中创建了一个 proc_dir_entry 项,并将其称为 fortune。当 proc_entry 成功创建之后,对自己的本地变量和proc_entry 结构进行了初始化。我们加载了 /proc read 和 write 函数(如清单 9 和清单 10所示),并确定这个模块的所有者。cleanup 函数简单地从 /proc 文件系统中删除这一项,然后释放 cookie_pot 所占据的内存。
cookie_pot 是一个固定大小(4KB)的页,它使用两个索引进行管理。第一个是 cookie_index,标识了要将下一个cookie 写到哪里去。变量 next_fortune 标识了下一个 cookie 应该从哪里读取以便进行输出。在所有的 fortune项都读取之后,我们简单地回到了 next_fortune。
清单 9. 模块的 init/cleanup 和变量
代码: #include
#include
#include
#include
#include
#include
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");
#define MAX_COOKIE_LENGTH PAGE_SIZE
static struct proc_dir_entry *proc_entry;
static char *cookie_pot; // Space for fortune strings
static int cookie_index; // Index to write next fortune
static int next_fortune; // Index to read next fortune
int init_fortune_module( void )
{
int ret = 0;
cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );
if (!cookie_pot) {
ret = -ENOMEM;
} else {
memset( cookie_pot, 0, MAX_COOKIE_LENGTH );
proc_entry = create_proc_entry( "fortune", 0644, NULL );
if (proc_entry == NULL) {
ret = -ENOMEM;
vfree(cookie_pot);
printk(KERN_INFO "fortune: Couldn‘t create proc entry\n");
} else {
cookie_index = 0;
next_fortune = 0;
proc_entry->read_proc = fortune_read;
proc_entry->write_proc = fortune_write;
proc_entry->owner = THIS_MODULE;
printk(KERN_INFO "fortune: Module loaded.\n");
}
}
return ret;
}
void cleanup_fortune_module( void )
{
remove_proc_entry("fortune", &proc_root);
vfree(cookie_pot);
printk(KERN_INFO "fortune: Module unloaded.\n");
}
module_init( init_fortune_module );
module_exit( cleanup_fortune_module );
向这个罐中新写入一个 cookie 非常简单(如清单 10 所示)。使用这个写入 cookie的长度,我们可以检查是否有这么多空间可用。如果没有,就返回 -ENOSPC,它会返回给用户空间。否则,就说明空间存在,我们使用copy_from_user 将用户缓冲区中的数据直接拷贝到 cookie_pot 中。然后增大cookie_index(基于用户缓冲区的长度)并使用 NULL 来结束这个字符串。最后,返回实际写入 cookie_pot的字符的个数,它会返回到用户进程。
清单 10. 对 fortune 进行写入操作所使用的函数
对 fortune 进行读取也非常简单,如清单 11所示。由于我们刚才写入数据的缓冲区(page)已经在内核空间中了,因此可以直接对其进行操作,并使用 sprintf 来写入下一个fortune。如果 next_fortune 索引大于 cookie_index(要写入的下一个位置),那么我们就将next_fortune 返回为 0,这是第一个 fortune 的索引。在将这个 fortune 写入用户缓冲区之后,在next_fortune 索引上增加刚才写入的 fortune 的长度。这样就变成了下一个可用 fortune 的索引。这个 fortune的长度会被返回并传递给用户。
清单 11. 对 fortune 进行读取操作所使用的函数
代码: int fortune_read( char *page, char **start, off_t off,
int count, int *eof, void *data )
{
int len;
if (off > 0) {
*eof = 1;
return 0;
}
/* Wrap-around */
if (next_fortune >= cookie_index) next_fortune = 0;
len = sprintf(page, "%s\n", &cookie_pot[next_fortune]);
next_fortune += len;
return len;
}
从这个简单的例子中,我们可以看出通过 /proc 文件系统与内核进行通信实际上是件非常简单的事情。现在让我们来看一下这个 fortune 模块的用法(参见清单 12)。
清单 12. 展示 fortune cookie LKM 的用法
代码: [root@plato]# insmod fortune.ko
[root@plato]# echo "Success is an individual proposition. Thomas Watson" > /proc/fortune
[root@plato]# echo "If a man does his best, what else is there? Gen. Patton" > /proc/fortune
[root@plato]# echo "Cats: All your base are belong to us. Zero Wing" > /proc/fortune
[root@plato]# cat /proc/fortune
Success is an individual proposition. Thomas Watson
[root@plato]# cat /proc/fortune
If a man does his best, what else is there? General Patton
[root@plato]#
/proc 虚拟文件系统可以广泛地用来报告内核的信息,也可以用来进行动态配置。我们会发现它对于驱动程序和模块编程来说都是非常完整的。在下面的 参考资料 中,我们可以学习到更多相关知识。
/proc文件系统的作用
linux使用ext2等和window不一样的文件系统
Linux能使用FAT32或NTFS的文件系统吗?
9.REDHAT LINUX 9.0默认使用的文件系统是()。
怎样卸装linux文件系统?
局域网内,如何访问其他的电脑;如何通过下面的工作站来访问服务器
如何在局域网内拒绝指定的计算机来访问本机呢?
在局域网内,如何通过"运行"命令来访问别的计算机呢?
Linux文件系统与dos文件系统的异同
怎样做Linux文件系统剪裁
请问linux文件系统和window的文件系统有什么区别???
winxp,linux分别使用什么文件系统?如果想在一台计算机上同时安装它们先后顺序如何?
linux /proc 下如何统计一个进程的内存占用?
怎样设置代理来访问服务器啊
来访问人员记录产品有哪些?
怎样用VB做界面来访问数据库
共享文件怎样指定用户来访问
为linux添加一个新的proc文件入口,监测虚拟存储器工作效率,把结果作为一个proc文件提供给用户
安装LINUX选哪一种文件系统好?
Window2003可不可以使用FAT32文件系统?
我使用的是DEBIAN的LINUX,如何和局域网内WIN系列操作系统联网?谢谢!
我使用的是DEBIAN的LINUX,如何和局域网内WIN系列操作系统联网?谢谢!
如何从因特网来访问局域网中的服务器
可以来访问我的QQ空间不