/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.mzph.cn/news/385021.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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内核线程kernel thread详解--Linux进程的管理与调度

内核线程为什么需要内核线程Linux内核可以看作一个服务进程(管理软硬件资源&#xff0c;响应用户进程的种种合理以及不合理的请求)。 内核需要多个执行流并行&#xff0c;为了防止可能的阻塞&#xff0c;支持多线程是必要的。 内核线程就是内核的分身&#xff0c;一个分身可以处…

Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

在2.6.24之后这个结构体有了较大的变化&#xff0c;此处先说一说2.6.16版本的sk_buff&#xff0c;以及解释一些问题。一、先直观的看一下这个结构体~~~~~~~~~~~~~~~~~~~~~~在下面解释每个字段的意义~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

最常用的设计模式---适配器模式(C++实现)

适配器模式属于结构型的设计模式&#xff0c;它是结构型设计模式之首&#xff08;用的最多的结构型设计模式&#xff09;。 适配器设计模式也并不复杂&#xff0c;适配器它是主要作用是将一个类的接口转换成客户希望的另外一个接口这样使得原本由于接口不兼容而不能一起工作的那…

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…

vfprintf()函数

函数声明&#xff1a;int vfprintf(FILE *stream, const char *format, va_list arg) 函数参数&#xff1a; stream—这是指向了FILE对象的指针&#xff0c;该FILE对象标识了流。 format—c语言字符串&#xff0c;包含了要被写入到流stream中的文本。它可以包含嵌入的format标签…

TCP粘包问题分析和解决(全)

TCP通信粘包问题分析和解决&#xff08;全&#xff09;在socket网络程序中&#xff0c;TCP和UDP分别是面向连接和非面向连接的。因此TCP的socket编程&#xff0c;收发两端&#xff08;客户端和服务器端&#xff09;都要有成对的socket&#xff0c;因此&#xff0c;发送端为了将…

UML类图符号 各种关系说明以及举例

UML中描述对象和类之间相互关系的方式包括&#xff1a;依赖&#xff0c;关联&#xff0c;聚合&#xff0c;组合&#xff0c;泛化&#xff0c;实现等。表示关系的强弱&#xff1a;组合>聚合>关联>依赖 相互间关系 聚合是表明对象之间的整体与部分关系的关联&#xff0c…

ESP传输模式拆解包流程

一、 ESP简介ESP&#xff0c;封装安全载荷协议(Encapsulating SecurityPayloads)&#xff0c;是一种Ipsec协议&#xff0c;用于对IP协议在传输过程中进行数据完整性度量、来源认证、加密以及防回放攻击。可以单独使用&#xff0c;也可以和AH一起使用。在ESP头部之前的IPV4…

linux内核netfilter模块分析之:HOOKs点的注册及调用

1: 为什么要写这个东西?最近在找工作,之前netfilter 这一块的代码也认真地研究过&#xff0c;应该每个人都是这样的你懂 不一定你能很准确的表达出来。 故一定要化些时间把这相关的东西总结一下。 0&#xff1a;相关文档linux 下 nf_conntrack_tuple 跟踪记录 其中可以根据内…

网络抓包工具 wireshark 入门教程

Wireshark&#xff08;前称Ethereal&#xff09;是一个网络数据包分析软件。网络数据包分析软件的功能是截取网络数据包&#xff0c;并尽可能显示出最为详细的网络数据包数据。Wireshark使用WinPCAP作为接口&#xff0c;直接与网卡进行数据报文交换。网络管理员使用Wireshark来…

结构体中指针

结构体中带有指针的情况 #include<stdio.h>struct man {char *name;int age; };int main() {struct man m {"tom",20};printf("name %s, age %d\n",m.name,m.age);return 0; } 运行结果&#xff1a; exbotubuntu:~/wangqinghe/C/20190714$ gcc st…

python使用opencv提取视频中的每一帧、最后一帧,并存储成图片

提取视频每一帧存储图片 最近在搞视频检测问题&#xff0c;在用到将视频分帧保存为图片时&#xff0c;图片可以保存&#xff0c;但是会出现(-215:Assertion failed) !_img.empty() in function cv::imwrite问题而不能正常运行&#xff0c;在检查代码、检查路径等措施均无果后&…

线程间通信之eventfd

线程间通信之eventfd man手册中的解释&#xff1a; eventfd()创建了一个“eventfd对象”&#xff0c; 通过它能够实现用户态程序间(我觉得这里主要指线程而非进程)的等待/通知机制&#xff0c;以及内核态向用户态通知的机制&#xff08;未考证&#xff09;。 此对象包含了一个…

定时器timerfd

1.为什么要加入此定时器接口 linux2.6.25版本新增了timerfd这个供用户程序使用的定时接口&#xff0c;这个接口基于文件描述符&#xff0c;当超时事件发生时&#xff0c;该文件描述符就变为可读。我首次接触这个新特性是在muduo网络库的定时器里看到的&#xff0c;那么新增一个…

timerfd与epoll

linux timerfd系列函数总结 网上关于timerfd的文章很多&#xff0c;在这儿归纳总结一下方便以后使用&#xff0c;顺便贴出一个timerfd配合epoll使用的简单例子 一、timerfd系列函数 timerfd是Linux为用户程序提供的一个定时器接口。这个接口基于文件描述符&#xff0c;通过文…

linux僵尸进程产生的原因以及如何避免产生僵尸进程defunct

给进程设置僵尸状态的目的是维护子进程的信息&#xff0c;以便父进程在以后某个时间获取。这些信息包括子进程的进程ID、终止状态以及资源利用信息(CPU时间&#xff0c;内存使用量等等)。如果一个进程终止&#xff0c;而该进程有子进程处于僵尸状态&#xff0c;那么它的所有僵尸…

linux下僵尸进程(Defunct进程)的产生与避免

在测试基于 DirectFBGstreamer 的视频联播系统的一个 Demo 的时候&#xff0c;其中大量使用 system 调用的语句&#xff0c;例如在 menu 代码中的 system("./play") &#xff0c;而且多次执行&#xff0c;这种情况下&#xff0c;在 ps -ef 列表中出现了大量的 defunc…