seo 发表于 2022-5-31 13:29:31

/proc 虚拟文件系统(实例)

/proc 虚拟文件系统(实例)发布时间:2022/5/31 13:16:01
            
                                                       
                                                       
            
      
      
               
                      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代码
   
http://tcspecial.iteye.com/images/icon_star.png


#ifndef __KERNEL__#define __KERNEL__#endif/* __KERNEL__ */    #include   #include   #include   #include   #include   #include   #include   #include   #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");

三.编译运行




   Shell代码
   
http://tcspecial.iteye.com/images/icon_star.png


$ sudo insmod proc_test.ko$ ll /proc/net/test/总用量 0-rw-r--r--. 1 root root 0 1月11 22:14 log$ cat /proc/net/test/log   number:c


四.接口操作
    上面用cat命令直接查看log文件,既然内核提供了通用的read(),write()文件访问接口,那试试。



   C代码
   
http://tcspecial.iteye.com/images/icon_star.png


#include #include   #include   #include   #include   #include   #include   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 = {};      ret = read(fd,buff,100);      assert(ret != -1);      printf("read:%s\n",buff);      close(fd);      return 0;}

运行:



   Shell代码
   
http://tcspecial.iteye.com/images/icon_star.png


$ sudo ./write_testret:2read:number:a
   向/proc/net/test/log写入10后,显示了16进制结果a,测试OK
               
      
      
   
            
      
      
https://www.yilongzhijia.cn/tupian/seo365t.jpg
页: [1]
查看完整版本: /proc 虚拟文件系统(实例)