1 proc 简介
1)/proc
Linux内核提供的一种通过/proc系统文件,可在运行时访问内核内部数据结构、改变内核设置机制。
Proc是一种伪文件系统,只在内存中存在,不占用外村空间。以文件系统访问形式向外提供接口。
2)proc_dir_entry 结构
structproc_dir_entry {
….
void*data;
read_proc_t *read_proc;
write_proc_t *write_proc;
structlist_head pde_openers; /* who did->open, but not ->release */
};
说明:该结构保存有文件属性等内容,管理proc文件,还有两个读/写函数指针,需要手动设置。其原型为:
typedef int (read_proc_t)(char *page, char **start,off_t off,
int count, int *eof, void *data);
typedef int(write_proc_t)(struct file *file, const char __user *buffer,
unsigned long count, void *data);
2 proc驱动相关函数
1)创建目录
externstruct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
structproc_dir_entry *parent);
2)创建文件
staticinline struct proc_dir_entry *create_proc_read_entry(const char *name,
mode_tmode, struct proc_dir_entry *base,
read_proc_t*read_proc, void * data)
3)读写文件
typedef int(read_proc_t)(char *page, char **start, off_t off,
int count, int *eof, void *data);
page:用户接收数据空间的首地址;
offset:接收数据空间的相对于首地址的偏移量(单位:字节);
count:请求读的数据长度
eof:反馈是否已到所读数据的末尾位置
data:用户传入的数据
typedef int(write_proc_t)(struct file *file, const char __user *buffer,
unsigned long count, void *data);
file:
待写的文件指针
buffer:
用户空间首地址, __user:用户态的地址空间
count:
申请写操作的数据长度
data:
额外的参数传入,扩展用
4)remove_proc_entry(flag, dir);
参数:
Flag读写权限
Dir 为删除的目录
5)内核态与用户态的数据交换
不能用用户态的: memcpy, strcpy等
拷贝到用户空间
copy_to_user(void__user *to, const void* from, unsigned long n);
从用户空间读入
copy_from_user(void*to,void __user *from, unsigned long n);
注:返回值为未被复制的字节数
3 应用实例
static struct proc_dir_entry *prwd_dir=NULL,*prwd_rdonly=NULL,
*prwd_rdwr=NULL;
//proc_dir_entry类型用于指代proc文件和proc目录
static char sbufRO[100]="A test string for readonly!\n";
static char sbufRW[100]="";//用于存用户所写数据
static int prwd_rdonly_read(char *page,char **start,off_t offset,int count,int *eof,void *data){
sprintf(page,"%s",sbufRO); *eof=1; return strlen(sbufRO);
}
//可读可读文件的读服务接口,参数参考上文
static int prwd_rdwr_read(char *page,char **start,off_t offset,int count,int *eof,void *data){
int len=strlen(sbufRW);
if(len<=offset){
printk("No data for reading in sbufRW!\n");
return 0;//0没有数据可读;-1表示不允许读;>0表示读到的数据总长度
}
if(len-offset<count)count=len-offset;
memcpy(page+offset,sbufRW+offset,count);
//offset有值,则表明之前的数据已读,只要eof不为1,系统就会重调调用本读服务接口函数
//注意要加上offset,不然会覆盖用户接收数据的空间里已接收到的数据
if(len<=offset+count)*eof=1;
return offset+count;//总长度
}
static int prwd_rdwr_write(struct file* filep,const char __user *buffer,unsigned long count,void *data){
unsigned long cnt=count;
if(cnt>=sizeof(sbufRW))cnt=sizeof(sbufRW)-1;//留一个'\0'空间
if(copy_from_user(sbufRW,buffer,cnt)){
printk("Failure to copy all data from user space!\n");
return -1;
}
sbufRW[cnt]='\0';
return cnt;
}
static int __init func_init(void){
printk(K "Entry %s!\n",__FUNCTION__);
prwd_dir=proc_mkdir("proc_rw",NULL);
//创建proc目录,原型:proc_mkdir(待建目录名,上层已存在的目录路径)<--NULL表示默认的"/proc"
//proc目录不需要专门指写读/写操作函数<--跟普通目录差不多
if(!prwd_dir){
printk(K "Can not create dir:/proc/proc_rw!\n");
goto failure_create_dir;
}
printk(K "Success to create dir:/proc/proc_rw!\n");
prwd_rdonly=create_proc_read_entry("rdonly",0400,prwd_dir,prwd_rdonly_read,NULL);
//创建proc只读文件,原型:create_proc_read_entry(待建文件名,读写权限,上层目录,读服务接口函数名,数据接口<将被读出的数据指针>)
if(!prwd_rdonly){
printk(K "Can not create dir:/proc/proc_rw/rdonly!\n");
goto failure_create_file_rdonly;
}
printk(K "Success to create dir:/proc/proc_rw/rdonly!\n");
prwd_rdwr=create_proc_entry("rdwr",0666,prwd_dir);
//创建可读写的proc文件,原型:create_proc_entry(待建文件名,读写权限,上层目录)
if(!prwd_rdwr){
printk(K "Can not create dir:/proc/proc_rw/rdwr!\n");
goto failure_create_file_rdwr;
}
printk(K "Success to create dir:/proc/proc_rw/rdwr!\n");
prwd_rdwr->read_proc=prwd_rdwr_read;
prwd_rdwr->write_proc=prwd_rdwr_write;
//对于create_proc_entry来说,没有专门参数用于绑定读/写服务接口函数<--需要通过所返回的PROC文件对象的read_proc/write_proc函数指针成员来额外绑定
return 0;//加载成功
failure_create_file_rdwr:
remove_proc_entry("rdwr",prwd_dir);
failure_create_file_rdonly:
remove_proc_entry("rdonly",prwd_dir);
failure_create_dir:
remove_proc_entry("proc_rw",NULL);
//删除proc文件/目录实体,原型:remove_proc_entry(待删文件或目录名,上层目录路径);
return -1;//加载失败
}
static void __exit func_exit(void){
printk(K "Entry %s!\n",__FUNCTION__);
remove_proc_entry("rdwr",prwd_dir);
remove_proc_entry("rdonly",prwd_dir);
remove_proc_entry("proc_rw",NULL);
}
module_init(func_init);
module_exit(func_exit);