? Linux下有一個神奇的目錄/proc,經常會運行 cat /proc/cpuinfo 命令查看cpu信息,/proc下的確有cpuinfo文件,但是這個文件不是物理存在的,是軟件虛擬出來的,與普通文件不同,該文件是動態的。通過/proc可以實現用戶態與內核態之間的通信。在內核模式下,可以很方便的創建/proc子目錄,并進行讀寫操作,只不過此時你需要實現文件讀寫接口,因為內核不知道如何處理該文件。
? ?下面創建/proc/test目錄,并新建log文件,進行讀寫操作。
?
一.系統API
extern struct proc_dir_entry proc_mkdir(const char *dir_name,struct proc_dir_entry *parent);
新建/proc子目錄,如parent為NULL,則在/proc根下建立目錄
extern struct proc_dir_entry proc_create_entry(const char *name,mode_t mode,struct proc_dir_entry *parent);
在/proc下新建虛擬文件
extern void *remove_proc_entry(const char *name,struct proc_dir_entry *parent);
刪除新建的文件或目錄?
?
二.編碼
- #ifndef?__KERNEL__??
- #define?__KERNEL__??
- #endif??/*?__KERNEL__?*/??
- ??
- #include?<linux/module.h>??
- #include?<linux/kernel.h>??
- #include?<linux/init.h>??
- #include?<linux/types.h>??
- #include?<linux/netdevice.h>??
- #include?<linux/proc_fs.h>??
- #include?<linux/inet.h>??
- #include?<linux/vmalloc.h>??
- ??
- #define?MAX_COOKIE_LENGTH?PAGE_SIZE??
- ??
- static?struct?proc_dir_entry?*test_proc_dir;??
- static?struct?proc_dir_entry?*log_proc_dir;??
- static?char?*cookie_pot;?????//?內核緩沖區,用于寫數據??
- static?int?tValue?=?12;??????//?顯示值??
- ??
- //?讀取日志文件函數??
- int?ProcLogRead(?char?*buffer,??
- ????????????????????????char?**start,??
- ????????????????????????off_t?offset,??
- ????????????????????????int?length,??
- ????????????????????????int?*eof,??
- ????????????????????????void?*data?)??
- {??
- ????int?len;??
- ????if(?offset?>?0?)??
- ????{??
- ????????*eof?=?1;??
- ????????return?0;??
- ????}??
- ??
- ????len?=?sprintf(buffer,?"number:%x\n",tValue);??
- ????return?len;??
- }??
- ??
- ??
- //?寫日志文件函數??
- int?ProcLogWrite(?struct?file?*filp,??
- ????????????????????????????const?char?__user?*buff,??
- ????????????????????????????unsigned?long?len,??
- ????????????????????????????void?*data)??
- {??
- ????if(?copy_from_user(?cookie_pot,buff,len?)?)??//?拷貝用戶空間值至內核緩沖區??
- ????{??
- ????????return?-EFAULT;??
- ????}??
- ??????
- ????sscanf(cookie_pot,"%d",&tValue);????//?保存至全局變量tValue??
- ????printk(KERN_ALERT?"%s?len:%lu?vl:%d\n",cookie_pot,len,tValue);??
- ????return?len;??
- }??
- ??
- ??
- static?int?__init?testproc_init(void)??
- {??
- ????int?ret?=?0;??
- ??
- ????printk(KERN_ALERT?"proc?test?init\n");??
- ??
- ????cookie_pot?=?(char*)vmalloc(?MAX_COOKIE_LENGTH?);???//?為內核緩沖區分配空間??
- ????if(!cookie_pot)??
- ????{??
- ????????ret?=?-ENOMEM;??
- ????}??
- ????else??
- ????{??
- ????????memset(cookie_pot,0,MAX_COOKIE_LENGTH);??
- ??
- ????????test_proc_dir?=?proc_mkdir("test",init_net.proc_net);???????//?新建/proc/net/test目錄,注:2.6.32以上內核,用init_net.proc_net取代先前的pro_net??
- ????????log_proc_dir?=?create_proc_entry("log",0644,test_proc_dir);?????//?新建文件?/proc/net/test/log??
- ??
- ????????if(test_proc_dir?==?NULL??
- ????????????||?log_proc_dir?==?NULL)??
- ????????{??
- ????????????ret?=?-ENOMEM;??
- ????????????vfree(cookie_pot);??
- ????????}??
- ????????else??
- ????????{??
- ????????????//?注冊讀寫函數??
- ????????????log_proc_dir->read_proc?=?ProcLogRead;??
- ????????????log_proc_dir->write_proc?=?ProcLogWrite;??
- ????????}??
- ????}??
- ??
- ????return?0;??
- }??
- ??
- ??
- static?void?__exit?testproc_exit(void)??
- {??
- ????printk(KERN_ALERT?"clean?test?proc\n");??
- ??
- ????remove_proc_entry("log",test_proc_dir);?????//?刪除log文件??
- ????remove_proc_entry("test",init_net.proc_net);????//?刪除test目錄??
- ??
- ????vfree(cookie_pot);??
- }??
- ??
- module_init(testproc_init);??
- module_exit(testproc_exit);??
- ??
- MODULE_LICENSE("Dual?BSD/GPL");??
- MODULE_AUTHOR("kettas");??
- MODULE_DESCRIPTION("proc?test");??
- MODULE_VERSION("1.0.0");??
- MODULE_ALIAS("Proc?01");??
?
三.編譯運行
?
- [scada@linux?proc_test]$?sudo?insmod?proc_test.ko??
- [scada@linux?proc_test]$?ll?/proc/net/test/??
- 總用量?0??
- -rw-r--r--.?1?root?root?0?1月??11?22:14?log??
- [scada@linux?proc_test]$?cat?/proc/net/test/log???
- number:c??
?
?
四.接口操作
? ? 上面用cat命令直接查看log文件,既然內核提供了通用的read(),write()文件訪問接口,那試試。
- #include?<unistd.h>??
- #include?<stdio.h>??
- #include?<sys/types.h>??
- #include?<sys/stat.h>??
- #include?<fcntl.h>??
- #include?<assert.h>??
- #include?<string.h>??
- ??
- int?main(int?argc,char?**argv)??
- {??
- ????int?fd?=?open("/proc/net/test/log",O_RDWR,0);??
- ????assert(fd?!=?-1);??
- ??
- ????char?*vl?=?"10";??//?此處為字符串???
- ??
- ????//?write??
- ????int?ret?=?write(fd,vl,strlen(vl));??
- ????printf("ret:%d\n",ret);??
- ??
- ????//?read??
- ????char?buff[100]?=?{};??
- ????ret?=?read(fd,buff,100);??
- ????assert(ret?!=?-1);??
- ??
- ????printf("read:%s\n",buff);??
- ????close(fd);??
- ??
- ????return?0;??
- }??
?
運行:
- [scada@linux?proc_test]$?sudo?./write_test??
- ret:2??
- read:number:a??
? ?向/proc/net/test/log寫入10后,顯示了16進制結果a,測試OK