sysctl是一種用戶應(yīng)用來(lái)設(shè)置和獲得運(yùn)行時(shí)內(nèi)核的配置參數(shù)的一種有效方式,通過(guò)這種方式,用戶應(yīng)用可以在內(nèi)核運(yùn)行的任何時(shí)刻來(lái)改變內(nèi)核的配置參數(shù),也可以在任何時(shí)候獲得內(nèi)核的配置參數(shù),通常,內(nèi)核的這些配置參數(shù)也出現(xiàn)在proc文件系統(tǒng)的/proc/sys目錄下,用戶應(yīng)用可以直接通過(guò)這個(gè)目錄下的文件來(lái)實(shí)現(xiàn)內(nèi)核配置的讀寫操作,例如,用戶可以通過(guò)
cat /proc/sys/net/ipv4/ip_forward
來(lái)得知內(nèi)核IP層是否允許轉(zhuǎn)發(fā)IP包,用戶可以通過(guò)
echo 1 > /proc/sys/net/ipv4/ip_forward
把內(nèi)核 IP 層設(shè)置為允許轉(zhuǎn)發(fā) IP 包,即把該機(jī)器配置成一個(gè)路由器或網(wǎng)關(guān)。 一般地,所有的 Linux 發(fā)布也提供了一個(gè)系統(tǒng)工具 sysctl,它可以設(shè)置和讀取內(nèi)核的配置參數(shù),但是該工具依賴于 proc 文件系統(tǒng),為了使用該工具,內(nèi)核必須支持 proc 文件系統(tǒng)。下面是使用 sysctl 工具來(lái)獲取和設(shè)置內(nèi)核配置參數(shù)的例子:
# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
注意,參數(shù) net.ipv4.ip_forward 實(shí)際被轉(zhuǎn)換到對(duì)應(yīng)的 proc 文件/proc/sys/net/ipv4/ip_forward,選項(xiàng) -w 表示設(shè)置該內(nèi)核配置參數(shù),沒(méi)有選項(xiàng)表示讀內(nèi)核配置參數(shù),用戶可以使用 sysctl -a 來(lái)讀取所有的內(nèi)核配置參數(shù),對(duì)應(yīng)更多的 sysctl 工具的信息,請(qǐng)參考手冊(cè)頁(yè) sysctl(8)。
但是 proc 文件系統(tǒng)對(duì) sysctl 不是必須的,在沒(méi)有 proc 文件系統(tǒng)的情況下,仍然可以,這時(shí)需要使用內(nèi)核提供的系統(tǒng)調(diào)用 sysctl 來(lái)實(shí)現(xiàn)對(duì)內(nèi)核配置參數(shù)的設(shè)置和讀取。
在源代碼中給出了一個(gè)實(shí)際例子程序,它說(shuō)明了如何在內(nèi)核和用戶態(tài)使用sysctl。頭文件 sysctl-exam.h 定義了 sysctl 條目 ID,用戶態(tài)應(yīng)用和內(nèi)核模塊需要這些 ID 來(lái)操作和注冊(cè) sysctl 條目。內(nèi)核模塊在文件 sysctl-exam-kern.c 中實(shí)現(xiàn),在該內(nèi)核模塊中,每一個(gè) sysctl 條目對(duì)應(yīng)一個(gè) struct ctl_table 結(jié)構(gòu),該結(jié)構(gòu)定義了要注冊(cè)的 sysctl 條目的 ID(字段 ctl_name),在 proc 下的名稱(字段procname),對(duì)應(yīng)的內(nèi)核變量(字段data,注意該該字段的賦值必須是指針),條目允許的最大長(zhǎng)度(字段maxlen,它主要用于字符串內(nèi)核變量,以便在對(duì)該條目設(shè)置時(shí),對(duì)超過(guò)該最大長(zhǎng)度的字符串截掉后面超長(zhǎng)的部分),條目在proc文件系統(tǒng)下的訪問(wèn)權(quán)限(字段mode),在通過(guò) proc設(shè)置時(shí)的處理函數(shù)(字段proc_handler,對(duì)于整型內(nèi)核變量,應(yīng)當(dāng)設(shè)置為&proc_dointvec,而對(duì)于字符串內(nèi)核變量,則設(shè)置為 &proc_dostring),字符串處理策略(字段strategy,一般這是為&sysctl_string)。
sysctl 條目可以是目錄,此時(shí) mode 字段應(yīng)當(dāng)設(shè)置為 0555,否則通過(guò) sysctl 系統(tǒng)調(diào)用將無(wú)法訪問(wèn)它下面的 sysctl 條目,child 則指向該目錄條目下面的所有條目,對(duì)于在同一目錄下的多個(gè)條目,不必一一注冊(cè),用戶可以把它們組織成一個(gè) struct ctl_table 類型的數(shù)組,然后一次注冊(cè)就可以,但此時(shí)必須把數(shù)組的最后一個(gè)結(jié)構(gòu)設(shè)置為NULL,即
{
??????? .ctl_name = 0
}
注冊(cè)sysctl條目使用函數(shù)register_sysctl_table(struct ctl_table *, int),第一個(gè)參數(shù)為定義的struct ctl_table結(jié)構(gòu)的sysctl條目或條目數(shù)組指針,第二個(gè)參數(shù)為插入到sysctl條目表中的位置,如果插入到末尾,應(yīng)當(dāng)為0,如果插入到開(kāi)頭,則為非0。內(nèi)核把所有的sysctl條目都組織成sysctl表。
當(dāng)模塊卸載時(shí),需要使用函數(shù)unregister_sysctl_table(struct ctl_table_header *)解注冊(cè)通過(guò)函數(shù)register_sysctl_table注冊(cè)的sysctl條目,函數(shù)register_sysctl_table在調(diào)用成功時(shí)返 回結(jié)構(gòu)struct ctl_table_header,它就是sysctl表的表頭,解注冊(cè)函數(shù)使用它來(lái)卸載相應(yīng)的sysctl條目。 用戶態(tài)應(yīng)用sysctl-exam-user.c通過(guò)sysctl系統(tǒng)調(diào)用來(lái)查看和設(shè)置前面內(nèi)核模塊注冊(cè)的sysctl條目(當(dāng)然如果用戶的系統(tǒng)內(nèi)核已經(jīng)支持proc文件系統(tǒng),可以直接使用文件操作應(yīng)用如cat, echo等直接查看和設(shè)置這些sysctl條目)。
下面是作者運(yùn)行該模塊與應(yīng)用的輸出結(jié)果示例:
# insmod ./sysctl-exam-kern.ko
# cat /proc/sys/mysysctl/myint
0
# cat /proc/sys/mysysctl/mystring
# ./sysctl-exam-user
mysysctl.myint = 0
mysysctl.mystring = ""
# ./sysctl-exam-user 100 "Hello, World"
old value: mysysctl.myint = 0
new value: mysysctl.myint = 100
old vale: mysysctl.mystring = ""
new value: mysysctl.mystring = "Hello, World"
# cat /proc/sys/mysysctl/myint
100
# cat /proc/sys/mysysctl/mystring
Hello, World
#
示例:
頭文件:sysctl-exam.h:
//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,
};
#endif
內(nèi)核模塊代碼??sysctl-exam-kern.c:
//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[] = {
{
.ctl_name = MY_INT_EXAM,
.procname = "myint",
.data = &myint,
.maxlen = sizeof(int),
.mode = 0666,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = MY_STRING_EXAM,
.procname = "mystring",
.data = mystring,
.maxlen = MY_MAX_SIZE,
.mode = 0666,
.proc_handler = &proc_dostring,
.strategy = &sysctl_string,
},
{
.ctl_name = 0
}
};
static struct ctl_table my_root = {
.ctl_name = MY_ROOT,
.procname = "mysysctl",
.mode = 0555,
.child = my_sysctl_exam,
};
static struct ctl_table_header * my_ctl_header;
static int __init sysctl_exam_init(void)
{
my_ctl_header = register_sysctl_table(&my_root, 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-exam-user.c:
//application: sysctl-exam-user.c
#include
#include
#include
#include "sysctl-exam.h"
#include
#include
_syscall1(int, _sysctl, struct __sysctl_args *, args);
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);
}
#define SIZE(x) sizeof(x)/sizeof(x[0])
#define OSNAMESZ 100
int oldmyint;
int oldmyintlen;
int newmyint;
int newmyintlen;
char oldmystring[MY_MAX_SIZE];
int oldmystringlen;
char newmystring[MY_MAX_SIZE];
int newmystringlen;
int myintctl[] = {MY_ROOT, MY_INT_EXAM};
int mystringctl[] = {MY_ROOT, MY_STRING_EXAM};
int main(int argc, char ** argv)
{
if (argc < 2)
{
oldmyintlen = sizeof(int);
if (sysctl(myintctl, SIZE(myintctl), &oldmyint, &oldmyintlen, 0, 0)) {
perror("sysctl");
exit(-1);
}
else {
printf("mysysctl.myint = %d\n", oldmyint);
}
oldmystringlen = MY_MAX_SIZE;
if (sysctl(mystringctl, SIZE(mystringctl), oldmystring, &oldmystringlen, 0, 0)) {
perror("sysctl");
exit(-1);
}
else {
printf("mysysctl.mystring = "%s"\n", oldmystring);
}
}
else if (argc != 3)
{
printf("Usage:\n");
printf("\tsysctl-exam-user\n");
printf("Or\n");
printf("\tsysctl-exam-user aint astring\n");
}
else
{
newmyint = atoi(argv[1]);
newmyintlen = sizeof(int);
oldmyintlen = sizeof(int);
strcpy(newmystring, argv[2]);
newmystringlen = strlen(newmystring);
oldmystringlen = MY_MAX_SIZE;
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);
}
}
exit(0);
}
?
評(píng)論
查看更多