实验8 创建proc文件
一、实验目的
通过添加一个功能为创建proc
文件的内核模块,进一步理解系统调用的相关知识。
二、实验内容
通过加载内核模块,为/proc
文件路径下创建以下内容:
-
一个名叫
proc_test
的子目录。一个名叫current
的文件,只读,读出的内容是读它的进程的情况。 -
一个名叫
current_too
的链接,指向current
。 -
一个名叫
hello
的文件,读出加入其中的文件。
三、实验内容
编写相关内核模块的C
语言代码如下
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
//以上几行是模块必须包含的头文件和宏,不需要深究
#define STRINGLEN 1024
char global_buffer[STRINGLEN]; //这里申请了一块大小为1024的内存
struct proc_dir_entry *example_dir, *hello_file, *current_file, *symlink;
struct proc_dir_entry *my_dir, *DXH_file, *
xxxxxxxx_file,*xxxxxxxxsym;
int proc_read_current(char *page, char **start, off_t off, int count, int *eof,
void *data) { //当用户读取"current"文件的内容时,内核调用这个函数
int len;
MOD_INC_USE_COUNT; //模块引用计数增加1,保证模块不会被卸载
len = sprintf(page, "current process usages:\nname:%s\ngid:%d\npid:%d\n", current->comm, current->pgrp,
current->pid);
//告诉用户,读出的文件内容是一行字符串,说明了当前进程的名字和pid等等。
MOD_DEC_USE_COUNT; //模块引用计数减1。
return len;
}
int proc_read_hello(char *page, char **start, off_t off, int count, int *eof
, void *data) { //当用户读取"hello"文件的内容时,内核调用这个函数
int len;
MOD_INC_USE_COUNT;
len = sprintf(page, "hello message:\n%s write:%s\n", current->comm, global_buffer);
//给global_buffer(前面申请的1024大小的内存)的前面加上两行文字,作为用户读出的内容
MOD_DEC_USE_COUNT;
return len;
}
static int proc_write_hello(struct file *file, const char *buffer, unsigned long count,
void *data) { //当用户写"hello"文件的内容时,内核调用这个函数
int len;
MOD_INC_USE_COUNT;
if (count > STRINGLEN) //如果要写的内容多于1024个字符,就把多出来的部分截断
len = STRINGLEN;
else
len = count;
copy_from_user(global_buffer, buffer, len); //从用户的缓冲区获得要写的数据,注意必须用copy_from_user
global_buffer[len] = '\0'; //给字符串后面加一个0,表示字符串结束
MOD_DEC_USE_COUNT;
return len;
}
int proc_read_DXH(char *page, char **start, off_t off, int count, int *eof, void *data) { //当用户读取"csy"文件的内容时,内核调用这个函数
int len;
MOD_INC_USE_COUNT; //模块引用计数增加1,保证模块不会被卸载
len = sprintf(page, "current process usages:\nname:%s\ngid:%d\npid:%d\n", current->comm, current->pgrp,
current->pid);
//告诉用户,读出的文件内容是一行字符串,说明了当前进程的名字和pid等等。
MOD_DEC_USE_COUNT; //模块引用计数减1。
return len;
}
int proc_read_xxxxxxxx(char *page, char **start, off_t off, int count, int *eof,
void *data) { //当用户读取"f20182642"文件的内容时,内核调用这个函数
int len;
MOD_INC_USE_COUNT;
len = sprintf(page, "hello message:csy write:hello!%s\n", global_buffer);
//给global_buffer(前面申请的1024大小的内存)的前面加上两行文字,作为用户读出的内容
MOD_DEC_USE_COUNT;
return len;
}
static int proc_write_xxxxxxxx(struct file *file, const char *buffer, unsigned long count,
void *data) { //当用户写"hello"文件的内容时,内核调用这个函数
int len;
MOD_INC_USE_COUNT;
if (count > STRINGLEN) //如果要写的内容多于1024个字符,就把多出来的部分截断
len = STRINGLEN;
else
len = count;
copy_from_user(global_buffer, buffer, len); //从用户的缓冲区获得要写的数据,注意必须用copy_from_user
global_buffer[len] = '\0'; //给字符串后面加一个0,表示字符串结束
MOD_DEC_USE_COUNT;
return len;
}
int init_module() { //这是我们熟悉的init_module函数,将会在加载模块的时候被调用,我们需要在加载模块的时候创建proc文件
example_dir = proc_mkdir("proc_test", NULL);
example_dir->owner = THIS_MODULE; //创建目录(相当于Windows的文件夹) /proc/proc_test
xxxxxxxx_dir = proc_mkdir("xxxxxxxx", example_dir);
xxxxxxxx_dir->owner = THIS_MODULE;
current_file = create_proc_read_entry("current", 0666, example_dir, proc_read_current, NULL);
current_file->owner = THIS_MODULE; //创建只读文件 /proc/proc_test/current
hello_file = create_proc_entry("hello", 0644, example_dir);
strcpy(global_buffer, "hello");
hello_file->read_proc = proc_read_hello;
hello_file->write_proc = proc_write_hello;
hello_file->owner = THIS_MODULE; //创建一个可以读写的文件 /proc/proc_test/hello
symlink = proc_symlink("current_too", example_dir, "current");
symlink->owner = THIS_MODULE; //创建一个链接(相当于Windows的快捷方式)/proc/proc_test/current_too,指向current
csy_file = create_proc_read_entry("DXH", 0666, xxxxxxxx_dir, proc_read_csy, NULL);
csy_file->owner = THIS_MODULE;
xxxxxxxx_file = create_proc_entry("xxxxxxxx", 0644, xxxxxxxx_dir);
strcpy(global_buffer, "xxxxxxxx");
xxxxxxxx_file- > read_proc = proc_read_f20182642;
xxxxxxxx_file- > write_proc = proc_write_f20182642;
xxxxxxxx_file- > owner = THIS_MODULE;
xxxxxxxxsym = proc_symlink("xxxxxxxx_too", xxxxxxxx_dir, "xxxxxxxx_too");
xxxxxxxxsym->owner = THIS_MODULE;
return 0;
}
void cleanup_module() { //要卸载模块了,因此需要把创建的目录和文件都清除掉。
remove_proc_entry("current_too", example_dir);
remove_proc_entry("hello", example_dir);
remove_proc_entry("current", example_dir);
remove_proc_entry("proc_test", NULL);
remove_proc_entry("xxxxxxxx_too", xxxxxxxx_dir);
remove_proc_entry("xxxxxxxx", xxxxxxxx_dir);
remove_proc_entry("xxxxxxxx", xxxxxxxx_dir);
remove_proc_entry("xxxxxxxx", NULL);
}
编译程序
gcc -c -I/usr/src/linux-2.4.20-8/include proc_test.c
查看所有已添加的系统调用
lsmod
可见名为proc_test
的模块已经被加入
进入相应目录,可以看到文件已经创建
四、实验结果
使用命令在对应目录下读取文件
more hello
可以看到代码中的文字输出在控制台中,这是由于该模块将前文C
程序代码中的字符串写入了对应文件夹的对应位置,因此能够被读取文件的命令顺利读取出来.
hello
文件
其他文件
五、实验心得
本次实验实现了编写内核模块,并利用它实现增加文件、写入信息的功能。完成本次实验需要有一定的C
语言功底,并且需要对Linux
下的函数和功能实现有一定了解。
本次实验仅仅是在模板代码的基础上实现了一些最基本的功能,要完整的理解岁所有的代码,编写出更复杂的系统模块,还需要付出更多的时间来进行Linux
系统以及C
语言编程的学习和实践。