简单的proc动态文件系统模块

又开学了呢..寒假在家沉迷血源,并没怎么看书.新学期继续努力吧.

最近在看文件系统相关的东西,于是想起之前写的读取/proc下的文件监控系统数据的程序,proc也是一种文件系统,不过他只存在于内存中,所以叫做伪文件系统.也是早期用户能简单和内核进行交互的方式之一,现在也许用在调试内核程序比较多(?).

还是以模块的形式加载我们制作的动态文件系统.先是注册模块,

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#define PROC_NAME  "hello_proc"

static int __init my_proc_init(void) {
  printk(KERN_INFO "init and create proc");
  proc_create(PROC_NAME, 0, NULL, &hello_proc_fops);
}

static void __exit my_proc_exit(void) {
  remove_proc_entry(PROC_NAME, NULL);
}

MODULE_LICENSE("GPL");
module_init(my_proc_init);
module_exit(my_proc_exit);

注册my_proc_init为模块的入口,在加载的时候就会调用my_proc_init函数,同理卸载的时候调用my_proc_exit.
之后调用proc_create这个接口为我们在/proc下创建一个名为hello_proc的文件.
此外看了下网上还有使用create_proc_entry的方法,但是我这边无法编译说找不到这个函数定义,差了下这个方法在3.10以上的版本的内核中已经被弃用了.so..//
先来看看这个函数的定义

static inline struct proc_dir_entry *proc_create(
        const char *name, 
        mode_t mode,
        struct proc_dir_entry *parent, 
        const struct file_operations *proc_fops)

第一个name是你的proc文件的名字,第二个是你创建的文件的权限,我们填0表示的权限是是0444,安装之后是这样的:

[root@localhost proc]# ls /proc/hello_proc  -la
-r--r--r--. 1 root root 0 Feb 23 17:25 /proc/hello_proc

第三个参数是你创建的文件位置(可以这么说吧),你可以通过proc_mkdir现在/proc下创建一个文件夹项目,在把这个文件夹传入给parent,这样proc文件就生成在了你创建的目录项下了.NULL就表示直接创建.
最后一个file_operations就是该文件的操作函数了.我们通过一个结构体来定义.

static const struct file_operations hello_proc_fops = {
  .owner = THIS_MODULE,
  .open = hello_proc_open,
  .read = seq_read,
  .llseek = seq_lseek,
  .release = single_release,
};

想看完整结构在linux/include/linux/fs.h中.
下面三个基本不会变,主要是有一个.open和.write,分别记录文件被读取和写入时的动作.

static int hello_proc_show(struct seq_file *m, void *v) {
  seq_printf(m, "Hello proc!\n");
  return 0;
}

static int hello_proc_open(struct inode *inode, struct  file *file) {
  return single_open(file, hello_proc_show, NULL);
}

先用seq_file对象打开文件,再使用seq_file中定义的标准输出的方法输出字符.
至于这个seq_file是个司马东西,大致就是虽然以前就有proc系统的存在,但是在数据大小使用方面很有局限性,于是某人就想了这个方法,用迭代器的形式迭代遍历元素,比如你有一个结构体的数组,就可以用pos来记录迭代的位置.
一个很典型的例子就是/proc/device,如果你cat这个文件就会打印出所有的设备名.看下源代码

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

static int devinfo_show(struct seq_file *f, void *v)
{
    int i = *(loff_t *) v;

    if (i < CHRDEV_MAJOR_HASH_SIZE) {
        if (i == 0)
            seq_puts(f, "Character devices:\n");
        chrdev_show(f, i);
    }
#ifdef CONFIG_BLOCK
    else {
        i -= CHRDEV_MAJOR_HASH_SIZE;
        if (i == 0)
            seq_puts(f, "\nBlock devices:\n");
        blkdev_show(f, i);
    }
#endif
    return 0;
}

static void *devinfo_start(struct seq_file *f, loff_t *pos)
{
    if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
        return pos;
    return NULL;
}

static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
{
    (*pos)++;
    if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE))
        return NULL;
    return pos;
}

static void devinfo_stop(struct seq_file *f, void *v)
{
    /* Nothing to do */
}

static const struct seq_operations devinfo_ops = {
    .start = devinfo_start,
    .next  = devinfo_next,
    .stop  = devinfo_stop,
    .show  = devinfo_show
};

static int devinfo_open(struct inode *inode, struct file *filp)
{
    return seq_open(filp, &devinfo_ops);
}

static const struct file_operations proc_devinfo_operations = {
    .open       = devinfo_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = seq_release,
};

static int __init proc_devices_init(void)
{
    proc_create("devices", 0, NULL, &proc_devinfo_operations);
    return 0;
}
module_init(proc_devices_init);

devinfo_ops中记录着迭代的操作,顺序时start->show->next->show….一直到结束调用stop.在next中每次把*pos++记录循环的次数,然后返回给static int devinfo_show(struct seq_file *f, void *v)中的v.
当然如果数据够小也可以直接用for进行循环,这样就和我们平时写的没什么区别了.

之后写个Makefile编译成模块.

SOURCE = procfs.c

obj-m += procfs.o
proc-objs := $(SOURCE:.c=.o)

all:
        make -C /usr/src/kernels/$(shell uname -r)/build M=$(PWD) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

如果说找不到目录的话请检查下/usr/src/kernels/$(shell uname -r)/build指向的地址再把上面替换调(神tm内核版本和kernel-headers版本是不一样的.)

[root@localhost proc]# insmod procfs.ko
[root@localhost proc]# cat /proc/
[root@localhost proc]# cat /proc/hello_proc 
Hello proc!

有兴趣可以读下https://github.com/jesstess/ldd4/blob/master/scull/main.c,写的方法比较全.
结束结束.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值