proc文件系统的使用

mac2022-06-30  75

/proc文件系统是Linux内核的一个虚拟文件系统,说它虚拟,是因为和磁盘分区上的文件系统不同,它只有在内核启动以后,工作起来的时候才会被动态创建。

/proc下面的内容会随着内核的配置和工作的状态在变化,比如/proc/meminfo这个文件,里面的内容是内存信息,不同的机器自然不同;还有就是/proc目录下面用数字命名的子目录,每个子目录的名字也就是数字,对应当前系统正在运行的进程,而子目录里面的内容就是对应进程的信息。

/proc里面还有其他许多信息,这里就不一一描述了,有兴趣可以谷歌一下。

Linux内核经过多年发展,/proc目录下的林林总总,已经是非常多了,虽然已经开发出了新的/sys文件系统替代/proc,但是,许多传统的程序仍然使用/proc文件系统作为内核与用户程序的接口。

如何让内核更高效,那是内核开发人员的事情。作为一个使用内核的开发人员,掌握/proc文件系统的使用方法也是很有用的,和/sys文件系统组织严密的结构相比,用/proc有时候还是很方便的。

不多说废话了,先入个门,介绍/proc的最基本操作。

这一集我们就介绍操作/proc文件系统的三个最基本函数:

代码片段1 定义在内核代码的<linux/proc_fs.h>

struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,        struct proc_dir_entry *parent);   struct proc_dir_entry *proc_mkdir(const char *name,struct proc_dir_entry *parent);   void remove_proc_entry(const char *name, struct proc_dir_entry *parent);   

先插一句,本例所有代码使用内核版本2.6.38.2,系统是ubuntu 11.04 amd64,要注意哦。

这三个函数,从函数名称就可以理解出来意思,第一个create_proc_entry()函数用做创建一个节点,也就是创建一个文件;

第二个proc_mkdir()函数建立一个目录;

第三个remove_proc_entry()函数是删除一个节点,实际上,不仅能删除节点,也可以删除proc_mkdir()函数创建的目录。

需要注意的是,proc相关的函数,操作的目标都是在/proc目录下。好,继续看函数参数:

create_proc_entry()函数:name 是节点的名称,一个字符串;mode 访问权限,可以使用八进制表示,chmod命令使用的权限一样;parent 父目录,注意是一个struct proc_dir_entry结构,如果写NULL表示/proc目录。

proc_mkdir()函数:name 子目录名称,一个字符串;parent 父目录,和上面解释一样。

remove_proc_entry()函数:参数同上面一样。

函数介绍完毕。有这三个函数就可以开工了。废话少说,贴代码:

 代码片段2 自己写的小模块,演示如何建立删除/proc节点

#include <linux/module.h>  #include <linux/init.h>  #include <linux/version.h>  #include <linux/proc_fs.h>   MODULE_LICENSE("Dual BSD/GPL");  MODULE_AUTHOR("<freshpassport@gmail.com>");   #define USER_ROOT_DIR "pt"  #define USER_ENTRY1   "pt_entry1"    static struct proc_dir_entry *pt_root;  static struct proc_dir_entry *pt_entry1;   static int proc_test_init(void)  {       pt_root = proc_mkdir(USER_ROOT_DIR, NULL);    if (NULL==pt_root)    {      printk(KERN_ALERT "Create dir /proc/%s error!\n",          USER_ROOT_DIR);      return -1;    }    printk(KERN_INFO "Create dir /proc/%s\n", USER_ROOT_DIR);        pt_entry1 = create_proc_entry(USER_ENTRY1,        0666, pt_root);    if (NULL == pt_entry1)    {      printk(KERN_ALERT "Create entry %s under /proc/%s error!\n",          USER_ENTRY1, USER_ROOT_DIR);      goto err_out;    }    printk(KERN_INFO "Create /proc/%s/%s\n",        USER_ROOT_DIR, USER_ENTRY1);     pt_entry1->read_proc = NULL;    pt_entry1->write_proc = NULL;     return 0;   err_out:    remove_proc_entry(USER_ROOT_DIR, pt_root);    return -1;  }   static void proc_test_exit(void)  {       remove_proc_entry(USER_ENTRY1, pt_root);    remove_proc_entry(USER_ROOT_DIR, NULL);    printk(KERN_INFO "All Proc Entry Removed!\n");  }   module_init(proc_test_init);  module_exit(proc_test_exit);  

一个标准的2.6内核模块写法。proc_test_init()函数是入口,proc_test_exit()函数是出口。

最开始引入了4个头文件,其中3个是内核模块标配的头文件,第4个是主角,proc_fs.h,前面说了,操作/proc的函数就定义在里面。

第9行,USER_ROOT_DIR定义了我们要在/proc目录下建立的子目录名称,也是用户的根目录;第10行,USER_ENTRY1定义了欲在USER_ROOT_DIR下面建立的节点名称。

第13、14行分别定义了USER_ROOT_DIR和USER_ENTRY1对应的目录结构pt_root和pt_entry1。

操作的数据介绍好了,说下流程吧。

proc_test_init()函数:

此函数是加载模块的时候执行的入口函数,会被内核自动调用。第19行,函数一开始就调用proc_mkdir()函数,在/proc目录下建立一个子目录,注意proc_mkdir()函数的第二个参数,NULL表示以/proc作为根目录。

子目录USER_ROOT_DIR建立成功后,紧接着调用create_proc_entry()函数建立一个文件节点,注意函数的第三个参数parent,不是NULL,而是pt_root,表示以USER_ROOT_DIR作为根目录。

文件建立成功后,需要设置pt_entry1的读写回调函数为NULL,这样做的目的是该文件节点读写操作都不处理。

proc_test_exit()函数:

用户调用rmmod卸载内核模块的时候被内核调用。此函数删除已经建立的节点,要注意的是remove_proc_entry()函数的parent实参,这里容易出错,导致内核报错。

最后贴一下Makefile:

obj-m += proc_test1.o   all:      make -C /usr/src/linux-headers-2.6.38-8-generic M=`pwd` modules   clean:      make -C /usr/src/linux-headers-2.6.38-8-generic M=`pwd` clean 

看看执行的效果:

下面是加载模块后列出文件节点

root@iscsia:~/proc_test# ll /proc/pt/  total 0  -rw-rw-rw- 1 root root 0 2011-07-01 15:04 pt_entry1 

下面是读文件节点/proc/pt/pt_entry1

root@iscsia:~/proc_test# cat /proc/pt/pt_entry1   root@iscsia:~/proc_test#  

什么结果都没有,正常,因为回调函数都给设置为NULL了。

下面是写文件节点/proc/pt/pt_entry1

root@iscsia:~/proc_test# echo "hello,entry" > /proc/pt/pt_entry1  -bash: echo: write error: Input/output error 

看来写操作不是很理想,报错了,pt_entry1不是很合作啊,也是,前面都给人家设置成NULL了,也不能全怪人家了。哈哈。下次继续介绍如何进行自己的读写操作。

转载于:https://www.cnblogs.com/Dennis-mi/articles/5239325.html

最新回复(0)