linux下的 Proc 文件系统

本文深入探讨了Proc文件系统的工作原理,包括其目录结构、文件特性及内核描述符。并通过实例展示了如何创建Proc目录下的文件和目录,以及如何通过自定义函数实现读写操作。

Proc文件系统是一种在用户态检查内核状态的机制。在proc下一般有如下子目录和文件:

Apm:高级电源管理信息

Bus:总线以及总线上的设备

Devices:可用的设备信息

Driver:已经启用的驱动程序

Interrupts:中断信息

Ioports:端口使用信息

Version:内核版本

 

上面的文件都具有如下特点:

1)  每个文件都有严格的权限(可读、可写、)

2)  可以用文本编辑器读取

3)  不仅可以有文件,也可以有子目录

4)  可以自己编写程序添加一个/proc目录下的文件

5)  文件的内容是动态创建的,并不存在于磁盘上

 

有关proc的文件在内核的描述符如下:

 

struct proc_dir_entry {

unsigned int low_ino;

unsigned short namelen;

const char *name;

mode_t mode;

nlink_t nlink;

uid_t uid;

gid_t gid;

loff_t size;

const struct inode_operations *proc_iops;

/*

 * NULL ->proc_fops means "PDE is going away RSN" or

 * "PDE is just created". In either case, e.g. ->read_proc won't be

 * called because it's too late or too early, respectively.

 *

 * If you're allocating ->proc_fops dynamically, save a pointer

 * somewhere.

 */

const struct file_operations *proc_fops;

struct proc_dir_entry *next, *parent, *subdir;

void *data;

read_proc_t *read_proc;

write_proc_t *write_proc;

atomic_t count;             /* use count */

int pde_users;  /* number of callers into module in progress */

spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */

struct completion *pde_unload_completion;

struct list_head pde_openers; /* who did ->open, but not ->release */

};

 

涉及到的函数:

 

int read_proc (char *buff, char ** stat, off_t off, int count, int *eof, void *data)

buff:把要返回给用户信息填写在buff里,最大不能超过PAGE_SIZE

stat:一般不使用

off:偏移量

count:用户要取的字节数

eof: 读取到文件尾,是需要将*eof设置为1

data:一般不用

 

int  write_proc (struct file *file, const char *buffer, unsigned long count, void *data)

file:一般不使用

buffer:待写的数据所在的位置

count:待写数据大小

data: 一般不使用

 

创建proc文件:

 

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

                              struct proc_dir_entry *parent)

name:要创建的文件名字

mode:要创建文件的属性,默认为07555

parent:这个文件的父目录

 

 

   创建目录:

struct proc_dir_entry *proc_mkdir(const char *name,

              struct proc_dir_entry *parent)

 

name:要创建的目录名

parent:这个目录的父目录

 

测试用例:

 

#include <linux/kernel.h>  
#include <linux/module.h>  
#include <linux/proc_fs.h>  
#include <linux/init.h>  
#include <asm/uaccess.h>  
#include <linux/sched.h>  

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Proc Module");
MODULE_ALIAS("proc module");

#define MAX_LENGTH 	64  
#define MAX_RECORD  5 	 
#define F_NAME 	"pid"  
#define D_NAME 	"tst"  
#define P_NAME 	"/proc/" D_NAME "/" F_NAME 

typedef struct {
    pid_t pid;
    char comm[TASK_COMM_LEN];
} pidcomm_t;
static int bufPos = 0;
pidcomm_t pidcommBuf[MAX_RECORD];

static struct proc_dir_entry *pid_entry;  
static struct proc_dir_entry *dir_entry;  

static int  pid_write (struct file *file, const char __user *buffer, 
                        unsigned long count, void *data)  
{     
	struct task_struct *_process;  
    char pid_buffer[MAX_LENGTH];
	unsigned long pid_buffer_size = count;  

    if (pid_buffer_size > MAX_LENGTH)  
 	    pid_buffer_size = MAX_LENGTH;   
    
    memset(pid_buffer, 0, MAX_LENGTH);
 	if (copy_from_user (pid_buffer, buffer, pid_buffer_size))  
  		return -EFAULT;  
  	
 	for_each_process (_process) {  
  		char _tmp[MAX_LENGTH];  
 		sprintf (_tmp, "%d\n", _process->pid);  
 		if (!strcmp (_tmp, pid_buffer)) {
  			printk ("<1> The EXE file is: %20s \n", _process->comm);  
            pidcommBuf[bufPos].pid = _process->pid;
            memset(pidcommBuf[bufPos].comm, 0, TASK_COMM_LEN);
            strcpy(pidcommBuf[bufPos].comm, _process->comm);
            bufPos = bufPos==MAX_RECORD-1 ? 0: bufPos+1;
        }
 	}  
 	return pid_buffer_size;  
}  
    
static int pid_read (char *page, char **start, off_t off, 
                        int count, int *eof, void *data)  
{  
    int i, ret, len = 0;
    char *pos = page;
    
    if (off > 0) {
        *eof = 1;
        return 0;
    }

    ret = sprintf(pos, "PID\tCOMMAND\n");
    len += ret;
    pos += ret;
    for (i=0; i<MAX_RECORD; i++) {
        if (0==pidcommBuf[i].pid) 
            break;
        ret = sprintf(pos, "%d\t%s\n", pidcommBuf[i].pid, 
                                        pidcommBuf[i].comm);
        len += ret;
        pos += ret;
    }
 	return len;  
}  

static int __init  pid_init (void)  
{  
	dir_entry = proc_mkdir(D_NAME, NULL);
 	if (!dir_entry) {
 		printk(KERN_ERR "Can't create /proc/" D_NAME "\n");
   		return -ENOMEM;
    }
 	pid_entry = create_proc_entry (F_NAME, 0666, dir_entry);  
 	if (!pid_entry) {  
  		remove_proc_entry (F_NAME, dir_entry);  
		printk (KERN_ERR P_NAME " created failed\n");  
  		return -ENOMEM;  
 	}  
	pid_entry->read_proc = pid_read;  
 	pid_entry->write_proc = pid_write;  
  	printk ("<1> create " P_NAME " SUCCESSFULLY.\n");  
     
  	return 0;  
}  
 
static void __exit pid_exit (void)  
{  
	remove_proc_entry (F_NAME, dir_entry);  
	remove_proc_entry (D_NAME, NULL);  
 	printk ("<1> Exit.\n");    
}  
   
module_init (pid_init);  
module_exit (pid_exit);  


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值