zoukankan      html  css  js  c++  java
  • 【转载】 使用proc文件系统和内核交互

    《使用proc文件系统和内核交互》
    本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性。
    参考资料:IBM developerWorks 《使用/proc文件系统来访问Linux内核的内容》、Linux-2.6.10内核
    来源:http://blog.csdn.net/rosetta/article/details/7563610

        此篇是在《内核模块编写》和《字符设备驱动程序编写基础》基础上写的,但这篇也是基础文章。使用proc文件系统与内核数据交互和之前写的《字符设备驱动程序编写基础》原理非常相似,只不过前者使用的是内核提供给/proc文件系统的一组专用函数,所以本节主要介绍如何使用这组函数,具体原理学习可参考给出的链接。
        可能大家都使用过cat /proc/cpuinfo(meminfo)来查看系统cpu或内存信息,或者也注意到在/proc目录中存在所有以ps -ef进程号为命令的目录,在所有对应的进程号目录中都有许多和该进程相关的文件,具体是些什么文件我不能用最确切的语言来描述或者定义,但我可以肯定的一点是这些文件应该都是由内核里反馈出来的,比如进入某个文件夹,可以cat 对应的status、maps、limits来看看到底包含什么。
        下面首先例出这组函数,再给出一个例子。
    一、相关函数和结构体
      1,struct proc_dir_entry *proc_mkdir(const char *name,
            struct proc_dir_entry *parent)//在parent目录创建一个名为name的目录。
       比如:struct proc_dir_entry *proc_net_ipsec_dir = proc_mkdir("ipsec", proc_net);//在proc_net目录创建名为ipsec的目录
      其中proc_net相当于宏,指/proc/net目录,如果第二个参数传NULL,即指默认/proc目录。以下是几个类似的宏。
        proc_root_fs /proc 
        proc_net /proc/net 
        proc_bus /proc/bus 
        proc_root_driver /proc/driver 
      2,再继续第二个函数之前有必要先说下porc_mkdir的返回值,它是一个结构体struct pro_dir_entry
      struct proc_dir_entry {
        unsigned int low_ino;
        unsigned short namelen;
        const char *name;
        mode_t mode;
        nlink_t nlink;
        uid_t uid;
        gid_t gid;       
        unsigned long size;
        struct inode_operations * proc_iops;
        struct file_operations * proc_fops;
        get_info_t *get_info;
        struct module *owner;
        struct proc_dir_entry *next, *parent, *subdir;
        void *data;
        read_proc_t *read_proc;
        write_proc_t *write_proc;
        atomic_t count;     /* use count */
        int deleted;        /* delete flag */
      };
      里面包含了一个文件(Linux把所有对象都当文件看代,目录当然也是一个文件)所有属性,比如:文件名、权限、uid、gid、前一级目录、包含的子目录等等,我记得在APUE2e在讲解文件系统时讲到过,所以可以结合上面内容进行理解。
      这次我们不对这些属性感兴趣,主要是关注下目录的读写函数,即read_proc和write_proc,一会例子中会提到。
      3,struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
                         struct proc_dir_entry *parent)//在parent目录创建一个名为name,权限为mode的文件。
        比如:struct proc_dir_entry * item = create_proc_entry("klipsdebug", 0400, "/proc/ipsec")//在/proc/ipsec目录创建一个权限为0400(只读)的文件klipsdebug
      4,create_proc_entry执行后返回的proc_dir_entry可以自己指定read、write等函数,如果只需要read函数,可以使用 
        static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
        mode_t mode, struct proc_dir_entry *base, 
        read_proc_t *read_proc, void * data)
        它其实是对create_proc_entry进行了封装,把create_proc_read_entry的传入值read_proc赋给了create_proc_entry返回值的read_proc成员,具体可看内核实现。
      5,struct proc_dir_entry *proc_symlink( const char *name,
                                           struct proc_dir_entry *parent,
                                           const char *dest );//在parent目录创建指定dest目录的名为name的符号链接。
      比如: proc_symlink("ipsec_eroute", proc_net, "ipsec/eroute/all");//在/proc/net创建指向/proc/net/ipsec/eroute/all的符号链接ipsec_eroute。
      6,void remove_proc_entry( const char *name, struct proc_dir_entry *parent );//删除parent目录中的名为name的文件
      7,还有两上函数比较重要,就是之前提到的read、write函数中需要调用的函数,这两个函数即完成了用户空间和内核空间的数据交互。
      unsigned long copy_to_user( void __user *to,
                                  const void *from,
                                  unsigned long n );//

      unsigned long copy_from_user( void *to,
                                    const void __user *from,
                                    unsigned long n );

    二、给出一个具体的例子以便理解,偷懒起见,直接copy链接处的例子,为保证代码完整性,作者及说明在代码中有所体现。

      //proc_study.c
      #include <linux/module.h>
      #include <linux/kernel.h>
      #include <linux/proc_fs.h>
      #include <linux/string.h>
      #include <linux/vmalloc.h>
      #include <asm/uaccess.h>
      MODULE_LICENSE("GPL");
      MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
      MODULE_AUTHOR("M. Tim Jones");
      #define MAX_COOKIE_LENGTH       PAGE_SIZE
      static struct proc_dir_entry *proc_entry;
      static char *cookie_pot;  // Space for fortune strings
      static int cookie_index;  // Index to write next fortune
      static int next_fortune;  // Index to read next fortune
      
      int fortune_read( char *page, char **start, off_t off,
                                 int count, int *eof, void *data )
      {
          int len;
          if (off > 0) {
              *eof = 1;
              return 0;
          }
      
          /* Wrap-around */
          if (next_fortune >= cookie_index) 
              next_fortune = 0;
      
          len = sprintf(page, "%s ", &cookie_pot[next_fortune]);
          next_fortune += len;
      
          return len;
      }
      
      ssize_t fortune_write( struct file *filp, const char __user *buff,
                                      unsigned long len, void *data )
      {
          int space_available = (MAX_COOKIE_LENGTH-cookie_index)+1;
          if (len > space_available) {
              printk(KERN_INFO "fortune: cookie pot is full! ");
              return -ENOSPC;
          }
      
          if (copy_from_user( &cookie_pot[cookie_index], buff, len )) {
              return -EFAULT;
          }
      
          cookie_index += len;
          cookie_pot[cookie_index-1] = 0;
      
          return len;
      }
      
      int init_fortune_module( void )
      {
          int ret = 0;
          cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );
          if (!cookie_pot) {
              ret = -ENOMEM;
          } else {
              memset( cookie_pot, 0, MAX_COOKIE_LENGTH );
              proc_entry = create_proc_entry( "fortune", 0644, NULL );
              if (proc_entry == NULL) {
                  ret = -ENOMEM;
                  vfree(cookie_pot);
                  printk(KERN_INFO "fortune: Couldn't create proc entry ");
              } else {
                  cookie_index = 0;
                  next_fortune = 0;
                  proc_entry->read_proc = fortune_read;
                  proc_entry->write_proc = fortune_write;
                  proc_entry->owner = THIS_MODULE;
                  printk(KERN_INFO "fortune: Module loaded. ");
              }
          }
      
          return ret;
      }
      
      void cleanup_fortune_module( void )
      {
          remove_proc_entry("fortune", &proc_root);
          vfree(cookie_pot);
          printk(KERN_INFO "fortune: Module unloaded. ");
      }
      
      module_init( init_fortune_module );
      module_exit( cleanup_fortune_module );

      //Makefile 自己改的一个Makefile
      #ifneq ($(KERNELRELEASE),)
        obj-m := my_proc.o
        my_proc-objs := proc_study.o
      #else
      KERNELDIR ?= /lib/modules/$(shell uname -r)/build
      PWD := $(shell pwd)
      
      default:
          $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
      
      clean:
          rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
          rm -rf Module.* modules.*
      
      .PHONY: default clean
      #endif

      编译生成my_proc.ko
      下面来测试下:
      [root@xxx proc]# ls /proc/fortune -al
      -rw-r--r-- 1 root root 0 05-13 16:23 /proc/fortune

      [root@xxx proc_study]# insmod my_proc.ko 
      [root@xxx proc_study]# dmesg 
      fortune: Module loaded.
      [root@xxx proc]# echo "Hello, Just a test" > /proc/fortune 
      [root@xxx proc]# echo "Secondary test" > /proc/fortune  
      [root@xxx proc]# ls /proc/fortune  -al                     
      -rw-r--r-- 1 root root 0 05-01 07:04 /proc/fortune
      [root@xxx proc]# cat /proc/fortune 
      Secondary test
      [root@xxx proc]# cat /proc/fortune 

      [root@xxx proc_study]# rmmod my_proc
      [root@xxx proc_study]# dmesg
      fortune: Module loaded.
      fortune: Module unloaded.
      

  • 相关阅读:
    Android学习之adb异常处理
    Android学习之多触点滑动
    RN animated帧动画
    RN animated组动画
    RN animated缩放动画
    RN Animated透明度动画
    Eclipse ADT中的logcat不显示解决方法
    RadioButton使用
    PropTypes使用
    SegmentedControlIOS使用
  • 原文地址:https://www.cnblogs.com/cxt-janson/p/7094321.html
Copyright © 2011-2022 走看看