【转载】 使用proc文件系统和内核交互

mac2022-06-30  37

《使用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\n", &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!\n");          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\n");          } 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.\n");          }      }        return ret;  }    void cleanup_fortune_module( void )  {      remove_proc_entry("fortune", &proc_root);      vfree(cookie_pot);      printk(KERN_INFO "fortune: Module unloaded.\n");  }    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.  

转载于:https://www.cnblogs.com/cxt-janson/p/7094321.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)