将一组与模块相关的命令加载进内核
完成功能类似2,打印proc下的相关信息。但是不用重新编译内核,节省时间,更为灵活
内核模块介绍
模块是在内核空间运行的程序,实际上是一种目标文件,不能单独运行但其代码可在运行时链接到系统中作为内核的一部分运行或卸载。Linux内核模块是一个编译好的、具有特定格式的独立目标文件,用户可通过系统提供的一组与模块相关的命令将模块加载进内核,当内核模块被加载后,它有如下特点:
- 与内核一起运行在相同的内核态和内核地址空间;
- 运行时与内核具有同样的特权级;
- 可方便地访问内核中的各种数据结构。
此外,内核模块还可以很容易地被移出内核,当用户不再需要某模块功能时,可以将它从内核卸载以节省系统主存开销。
一个典型的内核模块应包含如下几个部分:
1)头文件声明。其中module.h和init.h是必不可少的。module.h包含加载模块时需要的函数和符号定义;init.h中包含模块初始化和清理函数的定义。如果在加载时允许用户传递参数,模块中还应包含moduleparam.h头文件。
2)模块许可声明。从内核2.4.10版本开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时会显示“kernel tainted”(内核被污染)的警告信息。从linux/module.h文件中可看到,被内核接受的许可证有GPL、GPL v2、GPL and additionalrights、Dual BSD/GPL、Dual MPL/GPL、Dual MIT/GPL和Proprietary。
3)初始化和清理函数声明。内核模块必须调用宏module_init和module_exit去注册初始化和清理函数。初始化和清理函数必须在宏module_init和module_exit使用前定义,否则会出现编译错误。这两个函数配对使用,例如当初始化函数申请了一个资源,那么清理函数就应释放这个资源,使得模块不留下任何副作用。除了模块初始化函数和清理函数,还可以根据需要设计编写其它函数。
设计内核模块程序
注意增加了模块相关的库函数和函数声明,命名为 mymodules.c(与下面的Makefile对应)
#include<linux/module.h>
#include<linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include<linux/sched.h>
static int mymodule_init(void)//模块初始化
{
struct file *fp;
mm_segment_t fs;
loff_t pos;
int i,j,k,temp,flag;
char cpuinfo[600],cpuinfo_end[]={'f','l','a','g','s'};
char meminfo[200],meminfo_end[]={'B','u','f','f','e','r','s'};
char uptime[20];int runtime;
char version[150];
printk("system info print.(by system_call)
");
/*cpuinfo*/
fp=filp_open("/proc/cpuinfo",O_RDONLY,0);
fs=get_fs();
set_fs(KERNEL_DS);
pos=0;
vfs_read(fp,cpuinfo,sizeof(cpuinfo),&pos);
for(i=0;i<5000;i++)
{
flag=1;
for(j=0;j<5;j++)
if(cpuinfo[i+j]!=cpuinfo_end[j])
{
flag=0;
break;
}
if(flag)
break;
}
cpuinfo[i]=' ';
printk("cpuinfo:
%s
",cpuinfo);
filp_close(fp,NULL);
set_fs(fs);
/*meminfo*/
fp=filp_open("/proc/meminfo",O_RDONLY,0);
fs=get_fs();
set_fs(KERNEL_DS);
pos=0;
vfs_read(fp,meminfo,sizeof(meminfo),&pos);
for(i=0;i<1500;i++)
{
flag=1;
for(j=0;j<7;j++)
if(meminfo[i+j]!=meminfo_end[j])
{
flag=0;
break;
}
if(flag)
break;
}
meminfo[i]=' ';
printk("meminfo:
%s
",meminfo);
filp_close(fp,NULL);
set_fs(fs);
/*uptime*/
fp=filp_open("/proc/uptime",O_RDONLY,0);
fs=get_fs();
set_fs(KERNEL_DS);
pos=0;
vfs_read(fp,uptime,sizeof(uptime),&pos);
for(i=0;i<20;i++)
{
if(uptime[i]=='.')
break;
}
uptime[i]=' ';
runtime=0;
for(j=0;j<i;j++)
{
temp=uptime[j]-'0';
for(k=0;k<i-j-1;k++)
temp*=10;
runtime+=temp;
}
printk("uptime:
system has already started for %d minutes.
",runtime/60);
filp_close(fp,NULL);
set_fs(fs);
/*version*/
fp=filp_open("/proc/version",O_RDONLY,0);
fs=get_fs();
set_fs(KERNEL_DS);
pos=0;
vfs_read(fp,version,sizeof(version),&pos);
version[132]=' ';
printk("version:
%s
",version);
filp_close(fp,NULL);
set_fs(fs);
printk("info printed over.
");
return 0;
}
static void mymodule_exit(void)//模块清理函数
{
printk("module unloading.
");
}
module_init(mymodule_init); //注册初始化函数
module_exit(mymodule_exit); //注册清理函数
MODULE_LICENSE("GPL"); //模块许可声明
Makefile
注意modules下以tab开头
ifneq ($(KERNELRELEASE),)
obj-m := mymodules.o#obj-m 指编译成外部模块
else
KERNELDIR := /lib/modules/$(shell uname -r)/build #定义一个变量,指向内核目录
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
安装模块
切换root用户,执行以下
make
insmod ./mymodules.ko
lsmod
可以看到模块已安装
查看结果
dmesg –c
完成后可删除模块
rmmod mymodules