在linux内核程序中支持proc文件系统

来源:互联网 发布:淘宝进口税要买家交吗 编辑:程序博客网 时间:2024/06/06 09:34

以前老大老是教我说proc文件其实就是内存中的文件。其实是linux提供的一个内核借口,可以方便的让用户和linux内核进行通讯的一种方式。 很多内核程序也都使用了这个功能,想你运行 cat /proc/cpuinfo查看cpu信息或者cat /proc/version查看系统版本的时候,都是用到了这个功能。

widebright@widebright-desktop:~$ cat /proc/cpuinfo
widebright@widebright-desktop:~$ cat /proc/version
Linux version 2.6.24-18-generic (buildd@terranova) (gcc version 4.2.3 (Ubuntu 4.2.3-2ubuntu7)) #1 SMP Wed May 28 20:27:26 UTC 2008

 

我刚好看到篇相关的文章,就试了一下,你也很想知道这种功能是怎么实现的吧。


在我上次的那个hello world 的简单驱动 的例子上修改一下
--------- hello.c文件内容-------------


#include <linux/module.h>    /* module */
#include <linux/kernel.h>    /* 内核 */
#include <linux/proc_fs.h>    /* proc 文件系统必须的*/


#define procfs_name "widebright" /*这样定义之后,最后的文件就是 /proc/widebright */

/**
* 这个结构是用来定义 /proc 文件的
*
*/
struct proc_dir_entry *Our_Proc_File;

/* 如果用户想读我们定义的proc文件,这个函数将得到调用.
*
* 参数说明
* =========
* 1. 要写东西进去的缓存区
* 2. 字符串的指针的指针. 如果你不想使用内核分配的缓存,这个也许是有用的
*
* 3. 现在的文件偏移位置,就是文件指针位置
* 4. 第一个参数指定的缓存区的大小
* 5. 向这里写入 "1" 表示 EOF.
* 6. 指想一块数据的指针 (如果一个read操作同时读写多个 /proc 文件的
*    时候有用
*
* 函数的返回值
* ======================
* 返回 0 表示文件已经读到末尾 (end of file)
* 返回 负数 表示错误发生
*
* 更多信息
* ====================
* 在内核源代码的以下位置有个使用的例子
   <kernel source
* directory>/fs/proc/array.c.
*
* 在linux 环境下可以方便是使用grep来直接查看源代码,如果我们不确定某些
* 东西如何使用的华,开源就是方便
*/
int
procfile_read(char *buffer,
          char **buffer_location,
          off_t offset, int buffer_length, int *eof, void *data)
{
    int ret;
   
    printk(KERN_INFO "procfile_read (/proc/%s) called/n", procfs_name);
   
    /*
    * 这里我们把所有的数据,一次性的写入缓存空间了。
    * 所以用户读操作的时候最多只能读一次了。
    *    注意:一定要在某个时候返回0,不然系统的读操作,会一直读
         * 下去,无限的循环下去就会出错。
    */
    if (offset > 0) {
        /* 完成搜索数据的写入了, 返回 0 */
        ret = 0;
    } else {
        /* 填充缓冲区,返回写入的内容长度 */
        ret = sprintf(buffer, "widebright is here ,haha!/n");
    }

    return ret;
}
/*
int procfile_write(struct file *file, const char *buffer, unsigned long count,
           void *data)
{
    获取缓存大小
    procfs_buffer_size = count;
    if (procfs_buffer_size > PROCFS_MAX_SIZE ) {
        procfs_buffer_size = PROCFS_MAX_SIZE;
    }
   
    复制数据
    if ( copy_from_user(procfs_buffer, buffer, procfs_buffer_size) ) {
        return -EFAULT;
    }
   
    return procfs_buffer_size;
}

*/

int init_module()
{
    Our_Proc_File = create_proc_entry(procfs_name, 0644, NULL);
   
    if (Our_Proc_File == NULL) {
        remove_proc_entry(procfs_name, &proc_root);
        printk(KERN_ALERT "Error: Could not initialize /proc/%s/n",
               procfs_name);
        return -ENOMEM;
    }
        /*如果你想出来用户写入的数据,还可以设置Our_Proc_File->write_proc 项*/
    Our_Proc_File->read_proc = procfile_read;
    Our_Proc_File->owner     = THIS_MODULE;
    Our_Proc_File->mode     = S_IFREG | S_IRUGO;
    Our_Proc_File->uid     = 0;
    Our_Proc_File->gid     = 0;
    Our_Proc_File->size     = 37;

    printk(KERN_INFO "/proc/%s created/n", procfs_name);   
    return 0;    /* everything is ok */
}

void cleanup_module()
{
    remove_proc_entry(procfs_name, &proc_root);
    printk(KERN_INFO "/proc/%s removed/n", procfs_name);
}

-----Makefile 文件内容-----------------
# If KERNELRELEASE is defined, we've been invoked from the

# kernel build system and can use its language.

ifneq ($(KERNELRELEASE),)

    obj-m := hello.o

# Otherwise we were called directly from the command

# line; invoke the kernel build system.

else

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build

    PWD := $(shell pwd)

default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

------------------------------

编译和测试:

root@widebright-desktop:/home/widebright/桌面/驱动学习# make
make -C /lib/modules/2.6.24-18-generic/build M=/home/widebright/桌面/驱动学习 modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.24-18-generic'
CC [M] /home/widebright/桌面/驱动学习/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC      /home/widebright/桌面/驱动学习/hello.mod.o
LD [M] /home/widebright/桌面/驱动学习/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.24-18-generic'
widebright@widebright-desktop:~/桌面/驱动学习$ su root
口令:
root@widebright-desktop:/home/widebright/桌面/驱动学习# insmod hello.ko
root@widebright-desktop:/home/widebright/桌面/驱动学习# ls /proc
1     4092 4558 4974 5044 7351         fs            self
118   41    4560 4978 5048 7383         interrupts    slabinfo
119   4137 4567 4983 5049 7653         iomem         stat
120   4205 4606 4988 5053 7654         ioports       swaps
1364 4253 4615 4991 5054 7876         irq           sys
1368 4255 4616 4997 5061 84           kallsyms      sysrq-trigger
1375 4277 4627 4998 5064 acpi         kcore         sysvipc
1378 4293 4630 5     5067 buddyinfo    key-users     timer_list
161   4307 4633 5000 5072 bus          kmsg          timer_stats
2     4320 4675 5006 5074 cgroups      loadavg       tty
2298 4340 4676 5009 5102 cmdline      locks         uptime
2502 4341 4679 5012 5111 cpuinfo      meminfo       version
2706 4380 4685 5018 5114 crypto       misc          version_signature
3     44    4740 5020 5124 devices      modules       vmcore
3916 4454 4754 5023 6     diskstats    mounts        vmstat
3917 4473 4835 5026 7     dma          net           widebright
3922 4476 4914 5030 7058 driver       pagetypeinfo zoneinfo
3925 4477 4916 5034 7328 execdomains partitions
3927 45    4917 5038 7330 fb           sched_debug
4     4549 4966 5039 7331 filesystems scsi
可以看到/proc目录下已经有 widebright 这个文件了,
root@widebright-desktop:/home/widebright/桌面/驱动学习# cat /proc/widebright
widebright is here ,haha!
root@widebright-desktop:/home/widebright/桌面/驱动学习# rmmod hello.ko


初始代码是从
The Linux Kernel Module Programming Guide       http://linux.die.net/lkmpg/
复制过来的。
关于proc文件系统的更多信息,你也可以参考那里。
那是个linux 内核学习的文档,还讲到了其他内容,初学linux内核的人可以看一下,写的蛮好的!