/proc 虛擬文件系統(實例)

? 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);

刪除新建的文件或目錄?

?

二.編碼

C代碼??收藏代碼
  1. #ifndef?__KERNEL__??
  2. #define?__KERNEL__??
  3. #endif??/*?__KERNEL__?*/??
  4. ??
  5. #include?<linux/module.h>??
  6. #include?<linux/kernel.h>??
  7. #include?<linux/init.h>??
  8. #include?<linux/types.h>??
  9. #include?<linux/netdevice.h>??
  10. #include?<linux/proc_fs.h>??
  11. #include?<linux/inet.h>??
  12. #include?<linux/vmalloc.h>??
  13. ??
  14. #define?MAX_COOKIE_LENGTH?PAGE_SIZE??
  15. ??
  16. static?struct?proc_dir_entry?*test_proc_dir;??
  17. static?struct?proc_dir_entry?*log_proc_dir;??
  18. static?char?*cookie_pot;?????//?內核緩沖區,用于寫數據??
  19. static?int?tValue?=?12;??????//?顯示值??
  20. ??
  21. //?讀取日志文件函數??
  22. int?ProcLogRead(?char?*buffer,??
  23. ????????????????????????char?**start,??
  24. ????????????????????????off_t?offset,??
  25. ????????????????????????int?length,??
  26. ????????????????????????int?*eof,??
  27. ????????????????????????void?*data?)??
  28. {??
  29. ????int?len;??
  30. ????if(?offset?>?0?)??
  31. ????{??
  32. ????????*eof?=?1;??
  33. ????????return?0;??
  34. ????}??
  35. ??
  36. ????len?=?sprintf(buffer,?"number:%x\n",tValue);??
  37. ????return?len;??
  38. }??
  39. ??
  40. ??
  41. //?寫日志文件函數??
  42. int?ProcLogWrite(?struct?file?*filp,??
  43. ????????????????????????????const?char?__user?*buff,??
  44. ????????????????????????????unsigned?long?len,??
  45. ????????????????????????????void?*data)??
  46. {??
  47. ????if(?copy_from_user(?cookie_pot,buff,len?)?)??//?拷貝用戶空間值至內核緩沖區??
  48. ????{??
  49. ????????return?-EFAULT;??
  50. ????}??
  51. ??????
  52. ????sscanf(cookie_pot,"%d",&tValue);????//?保存至全局變量tValue??
  53. ????printk(KERN_ALERT?"%s?len:%lu?vl:%d\n",cookie_pot,len,tValue);??
  54. ????return?len;??
  55. }??
  56. ??
  57. ??
  58. static?int?__init?testproc_init(void)??
  59. {??
  60. ????int?ret?=?0;??
  61. ??
  62. ????printk(KERN_ALERT?"proc?test?init\n");??
  63. ??
  64. ????cookie_pot?=?(char*)vmalloc(?MAX_COOKIE_LENGTH?);???//?為內核緩沖區分配空間??
  65. ????if(!cookie_pot)??
  66. ????{??
  67. ????????ret?=?-ENOMEM;??
  68. ????}??
  69. ????else??
  70. ????{??
  71. ????????memset(cookie_pot,0,MAX_COOKIE_LENGTH);??
  72. ??
  73. ????????test_proc_dir?=?proc_mkdir("test",init_net.proc_net);???????//?新建/proc/net/test目錄,注:2.6.32以上內核,用init_net.proc_net取代先前的pro_net??
  74. ????????log_proc_dir?=?create_proc_entry("log",0644,test_proc_dir);?????//?新建文件?/proc/net/test/log??
  75. ??
  76. ????????if(test_proc_dir?==?NULL??
  77. ????????????||?log_proc_dir?==?NULL)??
  78. ????????{??
  79. ????????????ret?=?-ENOMEM;??
  80. ????????????vfree(cookie_pot);??
  81. ????????}??
  82. ????????else??
  83. ????????{??
  84. ????????????//?注冊讀寫函數??
  85. ????????????log_proc_dir->read_proc?=?ProcLogRead;??
  86. ????????????log_proc_dir->write_proc?=?ProcLogWrite;??
  87. ????????}??
  88. ????}??
  89. ??
  90. ????return?0;??
  91. }??
  92. ??
  93. ??
  94. static?void?__exit?testproc_exit(void)??
  95. {??
  96. ????printk(KERN_ALERT?"clean?test?proc\n");??
  97. ??
  98. ????remove_proc_entry("log",test_proc_dir);?????//?刪除log文件??
  99. ????remove_proc_entry("test",init_net.proc_net);????//?刪除test目錄??
  100. ??
  101. ????vfree(cookie_pot);??
  102. }??
  103. ??
  104. module_init(testproc_init);??
  105. module_exit(testproc_exit);??
  106. ??
  107. MODULE_LICENSE("Dual?BSD/GPL");??
  108. MODULE_AUTHOR("kettas");??
  109. MODULE_DESCRIPTION("proc?test");??
  110. MODULE_VERSION("1.0.0");??
  111. MODULE_ALIAS("Proc?01");??

?

三.編譯運行

?

Shell代碼??收藏代碼
  1. [scada@linux?proc_test]$?sudo?insmod?proc_test.ko??
  2. [scada@linux?proc_test]$?ll?/proc/net/test/??
  3. 總用量?0??
  4. -rw-r--r--.?1?root?root?0?1月??11?22:14?log??
  5. [scada@linux?proc_test]$?cat?/proc/net/test/log???
  6. number:c??

?

?

四.接口操作

? ? 上面用cat命令直接查看log文件,既然內核提供了通用的read(),write()文件訪問接口,那試試。

C代碼??收藏代碼
  1. #include?<unistd.h>??
  2. #include?<stdio.h>??
  3. #include?<sys/types.h>??
  4. #include?<sys/stat.h>??
  5. #include?<fcntl.h>??
  6. #include?<assert.h>??
  7. #include?<string.h>??
  8. ??
  9. int?main(int?argc,char?**argv)??
  10. {??
  11. ????int?fd?=?open("/proc/net/test/log",O_RDWR,0);??
  12. ????assert(fd?!=?-1);??
  13. ??
  14. ????char?*vl?=?"10";??//?此處為字符串???
  15. ??
  16. ????//?write??
  17. ????int?ret?=?write(fd,vl,strlen(vl));??
  18. ????printf("ret:%d\n",ret);??
  19. ??
  20. ????//?read??
  21. ????char?buff[100]?=?{};??
  22. ????ret?=?read(fd,buff,100);??
  23. ????assert(ret?!=?-1);??
  24. ??
  25. ????printf("read:%s\n",buff);??
  26. ????close(fd);??
  27. ??
  28. ????return?0;??
  29. }??

?

運行:

Shell代碼??收藏代碼
  1. [scada@linux?proc_test]$?sudo?./write_test??
  2. ret:2??
  3. read:number:a??

? ?向/proc/net/test/log寫入10后,顯示了16進制結果a,測試OK

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385021.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385021.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385021.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

內核模塊中對文件的讀寫

平時網絡部分的東西碰的多些&#xff0c;這塊一開始還真不知道怎么寫&#xff0c;因為肯定和在用戶空間下是不同的。google過后&#xff0c;得到以下答案。一般可以用兩種方法&#xff1a;第一種是用系統調用。第二種方法是filp->open()等函數。下面分別來說下這兩種方法。1…

Makefile文件試錯

1成功&#xff1a; src $(wildcard ./*cpp) obj $(patsubst %.cpp,%.o ,$(src))target test$(target) : $(obj)g $(obj) -o $(target) -I/usr/include/mysql -L/usr/lib/mysql/ -lmysqlclient %.o: %.cppg -c $< -o $ -I/usr/include/mysql -L/usr/lib/mysql/ -lmysql…

內核定時器timer_list使用

Linux內核中提供了timer使用的API&#xff0c;做一個簡單的記要。 1. 包含的頭文件&#xff1a;linux/timer.h 2. 數據類型&#xff1a;struct timer_list; 包含的主要成員&#xff1a; a. data:傳遞到超時處理函數的參數&#xff0c;主要在多個定時器同時使用時&#xff0c;區…

內存四區

1.代碼區&#xff1a; 代碼區Code&#xff0c;程序被操作系統加載到內存的時候&#xff0c;所有的可執行代碼都加載到代碼區&#xff0c;也叫代碼段&#xff0c;這塊內存是不可以在運行期間修改的。 2. 靜態區 所有的全局變量以及程序中的靜態變量都存儲在靜態區。 #include<…

最高效的進(線)程間通信機制--eventfd

我們常用的進程&#xff08;線程&#xff09;間通信機制有管道&#xff0c;信號&#xff0c;消息隊列&#xff0c;信號量&#xff0c;共享內存&#xff0c;socket等等&#xff0c;其中主要作為進程&#xff08;線程&#xff09;間通知/等待的有管道pipe和socketpair。線程還有特…

malloc,calloc,realloc

與堆操作相關的兩個函數 malloc #include<stdio.h> #include<stdlib.h> #include<string.h>int main() {char *p malloc(10); //內存隨機&#xff0c;未做處理int i;for(i 0; i < 10: i){printf(“%d “,p[i]);} free(p);return 0; } 運行結果&…

Linux內核同步機制之completion

內核編程中常見的一種模式是&#xff0c;在當前線程之外初始化某個活動&#xff0c;然后等待該活動的結束。這個活動可能是&#xff0c;創建一個新的內核線程或者新的用戶空間進程、對一個已有進程的某個請求&#xff0c;或者某種類型的硬件動作&#xff0c;等等。在這種情況下…

可變參數函數(一)

一個函數可以接受不定數的參數個數&#xff0c;這就是可變參數函數&#xff0c;比較常見的比如printf(),scanf()&#xff1b; printf(const char* format,…); printf(“%d”,i); printf(“%s”,s); printf(“the number is %d,stirng is :%s”,i,s); 變量參數函數的簡單實現&a…

Linux內核線程kernel thread詳解--Linux進程的管理與調度

內核線程為什么需要內核線程Linux內核可以看作一個服務進程(管理軟硬件資源&#xff0c;響應用戶進程的種種合理以及不合理的請求)。 內核需要多個執行流并行&#xff0c;為了防止可能的阻塞&#xff0c;支持多線程是必要的。 內核線程就是內核的分身&#xff0c;一個分身可以處…

可變參數函數(二)

函數樣例&#xff1a; #include<stdio.h> #include<stdlib.h> #include<stdarg.h>double add(int n,...) {int i 0;double sum 0;va_list argptr;va_start(argptr,n);for(i 0 ; i < n; i){double d va_arg(argptr,double);printf("%d argument …

Linux 內核網絡協議棧 ------sk_buff 結構體 以及 完全解釋 (2.6.16)

在2.6.24之后這個結構體有了較大的變化&#xff0c;此處先說一說2.6.16版本的sk_buff&#xff0c;以及解釋一些問題。一、先直觀的看一下這個結構體~~~~~~~~~~~~~~~~~~~~~~在下面解釋每個字段的意義~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

可變參數輸出(三)

Linux C關于輸出函數的定義&#xff1a; int printf(const char *format,…); int vprintf(const char * format,va_list ap); int vfprintf(FILE *stream,cosnt char *format,va_list ap); int vsprintf(char *str,const char *format,va_list ap); int vsnprintf(char *str,s…

最常用的設計模式---適配器模式(C++實現)

適配器模式屬于結構型的設計模式&#xff0c;它是結構型設計模式之首&#xff08;用的最多的結構型設計模式&#xff09;。 適配器設計模式也并不復雜&#xff0c;適配器它是主要作用是將一個類的接口轉換成客戶希望的另外一個接口這樣使得原本由于接口不兼容而不能一起工作的那…

Linux 簡單打印日志(二)

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> //#include<windows.h> #include <unistd.h> // linux下頭文件#define FILE_MAX_SIZE (1024*1024)void get_local_time(char* buffer){time_t rawtime;struct …

程序隨筆——C++實現的一個線程池

1.線程池簡介 我們知道在線程池是一種多線程處理形式&#xff0c;處理過程中我們將相應的任務提交給線程池&#xff0c;線程池會分配對應的工作線程執行任務或存放在任務隊列中&#xff0c;等待執行。 面向對象編程中&#xff0c;創建和銷毀對象是需要消耗一定時間的&#xff0…

線程池原理及創建并C++實現

本文給出了一個通用的線程池框架&#xff0c;該框架將與線程執行相關的任務進行了高層次的抽象&#xff0c;使之與具體的執行任務無關。另外該線程池具有動態伸縮性&#xff0c;它能根據執行任務的輕重自動調整線程池中線程的數量。文章的最后&#xff0c;我們給出一個簡單示例…

Linux 打印簡單日志(一)

簡單日志輸出&#xff1a; #include<stdio.h> #include<string.h> #include<stdlib.h>void write(char* filename,char* szStr){FILE* fp;fp fopen(filename,"at");if(fp ! NULL){fwrite(szStr,256,1,fp); //fclose(fp);fp NULL;} }int main(int…

c++簡單線程池實現

線程池&#xff0c;簡單來說就是有一堆已經創建好的線程&#xff08;最大數目一定&#xff09;&#xff0c;初始時他們都處于空閑狀態&#xff0c;當有新的任務進來&#xff0c;從線程池中取出一個空閑的線程處理任務&#xff0c;然后當任務處理完成之后&#xff0c;該線程被重…

Linux 打印可變參數日志

實現了傳輸進去的字符串所在的文檔&#xff0c;函數和行數顯示功能。 實現了將傳入的可變參數打印到日志功能。 #include<stdio.h> #include<stdarg.h> #include<string.h>const char * g_path "/home/exbot/wangqinghe/log.txt"; #define LOG(fm…

C++強化之路之線程池開發整體框架(二)

一.線程池開發框架 我所開發的線程池由以下幾部分組成&#xff1a; 1.工作中的線程。也就是線程池中的線程&#xff0c;主要是執行分發來的task。 2.管理線程池的監督線程。這個線程的創建獨立于線程池的創建&#xff0c;按照既定的管理方法進行管理線程池中的所有線程&#xf…