proc文件系统是一个虚拟文件系统,用户和应用程序可以通过proc文件系统得到当前的一些系统信息,并可以改变一些内核的参数。/proc下的文件是一种特殊文件,不能够像一般文件一样创建删除。下面讨论proc文件的创建、删除与读写。
1.创建目录:
- struct proc_dir_entry *proc_mkdir(const char *name,
- struct proc_dir_entry *parent);
2.创建proc文件:
- 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目录下)。
3.删除proc文件/目录:
- void remove_dir_entry(const char *name, struct proc_dir_entry *parent);
参数同proc_mkdir()函数类似
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文件的读写:
- #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_dir_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
关于seq_file接口(创建虚拟文件容量大于1页的接口)的例子:
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
static struct proc_dir_entry *pfile;
static char *myfruits[5] = {"apple", "orange", "banana", "watermelon", "pear"};
static void *my_seq_start(struct seq_file *s, loff_t *pos)
{
if (*pos >= 5)
return NULL;
return myfruits[*pos];
}
static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
if (++*pos >= 5)
return NULL;
return myfruits[*pos];
}
static void my_seq_stop(struct seq_file *s, void *v)
{
// nothing to do;
}
static int my_seq_show(struct seq_file *s, void *v)
{
seq_printf(s, "%s ", (char *)v);
return 0;
}
static struct seq_operations proc_seq_ops = {
.start = my_seq_start,
.next = my_seq_next,
.stop = my_seq_stop,
.show = my_seq_show,
};
static int my_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &proc_seq_ops);
}
static struct file_operations proc_fops = {
.open = my_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
static int __init myproc_init(void)
{
pfile = proc_create("fruits", 0666, NULL, &proc_fops);
if (!pfile) {
printk(KERN_ERR "Can't create /proc/fruits/n");
remove_proc_entry("mydir", NULL);
return -1;
}
return 0;
}
static void __exit myproc_exit(void)
{
remove_proc_entry("fruits", NULL);
}
module_init(myproc_init);
module_exit(myproc_exit);