您的位置:首页 > 运维架构 > Linux

linux下proc文件的读写(部分转载)

2017-09-11 16:51 316 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。

in Linux, proc文件系统是一个虚拟文件系统,用户和应用程序可以通过proc文件系统得到当前的一些系统信息,并可以改变一些内核的参数。/proc下的文件是一种特殊文件,不能够像一般文件一样创建删除。

如果要创建一个 proc 文件,并且不用 proc_fs 默认提供的 file_operations 的话,可以使用 proc_create() 这个函数(见方法二),通过最后一个参数来指定要创建的 proc 文件的 file_operations。

每个 proc 文件也都会用到 file_operations,在调用 create_proc_entry() 创建 proc 文件时,其中一步是调用 proc_register(),proc_register() 会为 proc_dir_entry 提供一个默认的 file_operations,而 proc_create() 与 create_proc_entry() 唯一差别就是在调用 proc_register() 前先设置好 proc_dir_entry 的 file_operations,这样在
proc_register() 时就不会设置使用 proc_fs 默认的 file_operations 了。

下面使用两种方法来讨论proc文件的创建、删除与读写,不论使用哪种方法创建proc文件,创建目录的方法都是使用proc_mkdir函数,如果" /proc/driver " 已存在,可直接在其目录下创建proc文件,指定文件名"driver/key", 如果/proc/dirver目录不存在,将不能成功创建指定文件名"driver/key"对应的proc文件(/proc/driver/key)。

方法一:(create_proc_entry创建proc文件)

1.1 .创建目录:

[c] view
plain copy

struct proc_dir_entry *proc_mkdir(const char *name,  

                struct proc_dir_entry *parent);  

1.2 .创建proc文件:

[c] view
plain copy

struct proc_dir_entry *create_proc_entry( const char *name,  mode_t mode,  

                struct proc_dir_entry *parent );  

create_proc_entry函数用于创建一个一般的proc文件,其中name是文件名,比如“hello”,mode是文件模式,parent是要创建的proc文件的父目录(若parent = NULL则创建在/proc目录下)。

1.3 .删除proc文件/目录:

[c] view
plain copy

void remove_dir_entry(const char *name, struct proc_dir_entry *parent);  

参数同proc_mkdir()函数类似

1.4 .创建可读写的proc文件

proc文件实际上是一个叫做proc_dir entry的struct(定义在proc_fs.h),该struct中有int read_proc和int write_proc两个元素,要实现proc的文件的读写就要给这两个元素赋值。但这里不是简单地将一个整数赋值过去就行了,需要实现两个回调函数。

在用户或应用程序访问该proc文件时,就会调用这个函数,实现这个函数时只需将想要让用户看到的内容放入page即可。

写回调函数原型:int mod_write( struct file *filp, const char __user *buff, unsigned long len, void *data );

在用户或应用程序试图写入该proc文件时,就会调用这个函数,实现这个函数时需要接收用户写入的数据(buff参数)。

写一个模块测试proc文件的读写:

[c] view
plain copy

#include linux/module.h  

#include linux/kernel.h  

#include linux/proc_fs.h  

#include linux/sched.h  

#include asm/uaccess.h  

   

#define STRINGLEN 1024  

   

char global_buffer[STRINGLEN];  

   

struct proc_di
10d8a
r_entry *example_dir, *hello_file;  

   

int proc_read_hello(char *page, char **start, off_t off, int count, int *eof,  

                void *data) {  

        int len;  

        len = sprintf(page, global_buffer); //把global_buffer的内容显示给访问者  

        return len;  

}  

   

int proc_write_hello(struct file *file, const char *buffer, unsigned long count,  

                void *data) {  

        int len;  

   

        if (count = STRINGLEN)  

                len = STRINGLEN – 1;  

        else  

                len = count;  

   

        /* 

         * copy_from_user函数将数据从用户空间拷贝到内核空间 

         * 此处将用户写入的数据存入global_buffer 

         */  

        copy_from_user(global_buffer, buffer, len);  

        global_buffer[len] = \0′;  

        return len;  

}  

   

static int __init proc_test_init(void) {  

        example_dir = proc_mkdir("proc_test", NULL);  

        hello_file = create_proc_entry("hello", S_IRUGO, example_dir);  

        strcpy(global_buffer, "hello");  

        hello_file->read_proc = proc_read_hello;  

        hello_file->write_proc = proc_write_hello;  

        return 0;  

}  

   

static void __exit proc_test_exit(void) {  

        remove_proc_entry("hello", example_dir);  

        remove_proc_entry(“proc_test”, NULL);  

}  

   

module_init(proc_test_init);  

module_exit(proc_test_exit);  

写入proc文件

echo "Hello from kernel" /proc/proc_test/hello'

读取proc文件内容,将看到屏幕上显示了我们写入的字符串:Hello from kernel

cat /proc/proc_test/hello
 
方法二:(proc_create创建proc文件)

proc_create() 一般在创建使用 seq_file 接口的proc 文件时使用。 其中seq_file接口定义在#include<linux/seq_file.h>中,如果open函数使用了single_open,release函数必须为single_release

proc_create函数原型: struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops)

2.1 .创建目录:

[c] view
plain copy

struct proc_dir_entry *proc_mkdir(const char *name,  

                struct proc_dir_entry *parent);  

2.2.创建文件:

static int proc_show_ver(struct seq_file *file, void *v)

{

 int cnt = 0;

 seq_printf(file, "Driver: %s\n", DRV_NAME);    /*函数seq_printf是最常用的输出函数,它用于把给定参数按照给定的格式输出到seq_file文件*/

 seq_printf(file, "Author: %s\n", AUTH);

 seq_printf(file, "Version: %s\n", VER);

 seq_printf(file, "Time: %s %s\n", __DATE__, __TIME__);

 return cnt; 

}

static int proc_key_open(struct inode *inode, struct file *file)

{

 single_open(file, proc_show_ver, NULL);  /*将proc_show_ver 和 seq_file文件关联起来*/

 return 0;

}

static struct file_operations proc_file_ops = {

 .owner   = THIS_MODULE,

 .open     = proc_key_open

 .read     = seq_read,     /*定义在linux/seq_file.c*/

 .release = single_release,  /*定义在linux/seq_file.c*/

};

ver_proc = proc_create(PROC_NAME, 0, NULL, &proc_file_ops);

2.3 删除proc文件(和方法一相同)

remove_proc_entry(PROC_NAME, NULL);

2.4 proc文件使用 (和方法一相同)

按照上述的代码,仅能够察看proc文件,cat /proc/PROC_NAME

几点注意:

proc 项创建时要避免已经存在同名的 proc 项,否则注册时内核会报错(但还是会成功返回那个 proc 项),在删除时有时会删不掉(尤其是 proc 目录)。

删除一个 proc 目录会把这个目录所有的 proc 文件都删除。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: