//header: sysctl-exam.h
#ifndef _SYSCTL_EXAM_H
#define _SYSCTL_EXAM_H
#include
#define MY_ROOT (CTL_CPU + 10)
#define MY_MAX_SIZE 256
enum {
MY_INT_EXAM = 1,
MY_STRING_EXAM = 2,
}; //sysctl 条目 ID,用户态应用和内核模块需要这些 ID 来操作和注册 sysctl 条目
#endif
//kernel module: sysctl-exam-kern.c
#include
#include
#include
#include "sysctl-exam.h"
static char mystring[256];
static int myint; // 定义模块内部变量
static struct ctl_table my_sysctl_exam[] = { // 在该内核模块中,每一个 sysctl 条目对应一个 struct ctl_table 结构
{
.ctl_name = MY_INT_EXAM,
.procname = "myint",
.data = &myint,
.maxlen = sizeof(int),
.mode = 0666, //条目在proc文件系统下的访问权限
.proc_handler = &proc_dointvec, //在通过proc设置时的处理函数(字段proc_handler,对于整型内核变量,应当设置为&proc_dointvec,而对于字符串内核变量,则设置为 &proc_dostring),
},
{
.ctl_name = MY_STRING_EXAM,
.procname = "mystring",
.data = mystring,
.maxlen = MY_MAX_SIZE,
.mode = 0666,
.proc_handler = &proc_dostring,
.strategy = &sysctl_string, //字符串处理策略(字段strategy,一般这是为&sysctl_string)。
},
{
.ctl_name = 0 //必须把数组的最后一个结构设置为NULL
}
};
static struct ctl_table my_root = {
.ctl_name = MY_ROOT,
.procname = "mysysctl",
.mode = 0555,
.child = my_sysctl_exam,
};//Sysctl 条目可以是目录,此时 mode 字段应当设置为 0555,否则通过 sysctl 系统调用将无法访问它下面的 sysctl 条目,
//child 则指向该目录条目下面的所有条目,对于在同一目录下的多个条目,不必一一注册,用户可以把它们组织成一个 struct ctl_table 类型的数组,然后一次注册就可以
static struct ctl_table_header * my_ctl_header;
static int __init sysctl_exam_init(void)
{
my_ctl_header = register_sysctl_table(&my_root, 0); //第一个参数为定义的struct ctl_table结构的sysctl条目或条目数组指针
//第二个参数为插入到sysctl条目表中的位置,如果插入到末尾,应当为0,如果插入到开头,则为非0
return 0;
}
static void __exit sysctl_exam_exit(void)
{
unregister_sysctl_table(my_ctl_header);
}
module_init(sysctl_exam_init);
module_exit(sysctl_exam_exit);
MODULE_LICENSE("GPL");
用户态应用通过sysctl系统调用来查看和设置前面内核模块注册的sysctl条目
用户空间代码如下
int myintctl[] = {MY_ROOT, MY_INT_EXAM};
int mystringctl[] = {MY_ROOT, MY_STRING_EXAM};
int sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,void *newval, size_t newlen)
{
struct __sysctl_args args={name,nlen,oldval,oldlenp,newval,newlen};
return _sysctl(&args);
}
if (sysctl(myintctl, SIZE(myintctl), &oldmyint, &oldmyintlen, &newmyint, newmyintlen)) {
perror("sysctl");
exit(-1);
}
else {
printf("old value: mysysctl.myint = %d\n", oldmyint);
printf("new value: mysysctl.myint = %d\n", newmyint);
}
if (sysctl(mystringctl, SIZE(mystringctl), oldmystring, &oldmystringlen, newmystring, newmystringlen)) {
perror("sysctl");
exit(-1);
}
else {
printf("old vale: mysysctl.mystring = \"%s\"\n", oldmystring);
printf("new value: mysysctl.mystring = \"%s\"\n", newmystring);
}