免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3699 | 回复: 7
打印 上一主题 下一主题

[求助]内核模块:读写新建/proc/中的文件,代码分享与编译错误 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-08-27 16:34 |只看该作者 |倒序浏览
5可用积分
我有一个问题,就是编写了一个操作/proc下文件的模块程序,首先在/proc下面建立一个文件然后普通用户可读取,超级用户可读可写。
程序代码见下面。
主要的问题有两个:
1)在static int module_permission(struct inode *inode, int op, struct nameidata *foo)中的判断语句:
if(op == 4 || (op == 2 && current->euid == 0))
编译的时候报错说是:
procfs2.c|92| error: dereferencing pointer to incomplete type

2)在int init_module()中的如下语句:
        int rv;
        rv = 0;
编译的时候警告是:
procfs2.c|134| warning: ISO C90 forbids mixed declarations and code

第一个错误,我已经确定是current->euid引起的了,查了网上的资料说current返回一个task_struct,在linux/sched.h中,我到这个文件下面也没有找到这个结构体,我的内核版本是2.6.24-19的Ubuntu 8.04.主要目的就是要获得当前运行的有效用户ID,但是不知道为什么就是不行。我把current->euid去掉就可以,但是就违反了编程序的初衷了。哪位高手朋友能够帮我想些办法,我在此谢谢了!!

第二个错误,我也不太清楚,虽然是个警告,但是我还是希望能有朋友帮我看看,谢谢!!


/*程序功能:在/proc中创建一个文件,允许读写,普通用户能够读,超级用户能够写*/
/*kernel*/
#include <linux/kernel.h>
/*module*/
#include <linux/module.h>
/*procfs*/
#include <linux/proc_fs.h>
/*get_user and put_user*/
#include <asm/uaccess.h>


/*这里我们保持上次接收到的消息,证明我们能够处理我们的输入*/
#define MESSAGE_LENGTH 80
static char Message[MESSAGE_LENGTH];
static struct proc_dir_entry *Our_Proc_File;

#define PROC_ENTRY_FILENAME "rw_test"

/*函数功能:相当于读取数据到用户空间
&nbsp;* 关于参数:
&nbsp;* filp:可以查看/usr/src/linux-headers-2.6.24-19-generic/include/linux
&nbsp;* buffer:用于填充数据的buffer,读取的数据最后就应该存放到这里面
&nbsp;* length:buffer的长度
&nbsp;* */

static ssize_t module_output(struct file *filp,&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char *buffer,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t length,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loff_t * offset)
{
&nbsp;&nbsp;&nbsp;&nbsp;static int finished = 0;
&nbsp;&nbsp;&nbsp;&nbsp;/*读取的字节数目*/
&nbsp;&nbsp;&nbsp;&nbsp;int i;
&nbsp;&nbsp;&nbsp;&nbsp;char message[MESSAGE_LENGTH + 30];

&nbsp;&nbsp;&nbsp;&nbsp;/*返回零表示文件的结尾,否则进程会继续从我们这里读取从而陷入死循环*/
&nbsp;&nbsp;&nbsp;&nbsp;if (finished)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;finished = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;/*使用put_user把数据从内核内存空间拷贝到进程内存空间
&nbsp;&nbsp;&nbsp;&nbsp; * 顺便指出:get_user进行相反的操作。
&nbsp;&nbsp;&nbsp;&nbsp; * */

&nbsp;&nbsp;&nbsp;&nbsp;sprintf(message, "Last input:%s", Message);
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i < length && message[i]; i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;put_user(message[i], buffer + i);

&nbsp;&nbsp;&nbsp;&nbsp;/*注意,这里我们假设消息的大小小于len,如果超过了,那么就会截取接收。
&nbsp;&nbsp;&nbsp;&nbsp; * 在实际中,如果消息的大小小于len,我们会返回len,并且在第二此调用的时候
&nbsp;&nbsp;&nbsp;&nbsp; * 开始由len+1开始填充消息字节*/

&nbsp;&nbsp;&nbsp;&nbsp;finished = 1;

&nbsp;&nbsp;&nbsp;&nbsp;/*返回读取的字节数目*/
&nbsp;&nbsp;&nbsp;&nbsp;return i;
}

/*写文件的函数,将要写入的数据(在buffer里面)存放到Message里面。*/
static ssize_t
module_input(struct file *filp, const char *buff, size_t len, loff_t * off)
{
&nbsp;&nbsp;&nbsp;&nbsp;int i;

&nbsp;&nbsp;&nbsp;&nbsp;/*把输入存放在Message(全局)数组中,这样module_output以后能够使用它*/
&nbsp;&nbsp;&nbsp;&nbsp;for (i = 0; i < MESSAGE_LENGTH - 1 && i < len; i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get_user(Message[i], buff + i);

&nbsp;&nbsp;&nbsp;&nbsp;Message[i] = '\0';
&nbsp;&nbsp;&nbsp;&nbsp;return i;
}

/*这个函数用来决定是否允许一个指定的操作。
&nbsp;* 如果允许那么返回0,否则返回非零(并且根据数值决定为什么不被允许)
&nbsp;* 操作包含如下的值:
&nbsp;* 0 -执行(在我们的例子里,执行这个文件没有什么意义)
&nbsp;* 2 -写入(写入到内核的模块当中)
&nbsp;* 4 -读取(从内核模块读取数据)
&nbsp;*
&nbsp;* 这里的函数是实际执行文件权限检查的。ls -l返回的权限仅供参考,并且可在这覆盖
&nbsp;* */


static int module_permission(struct inode *inode, int op, struct nameidata *foo)
{
&nbsp;&nbsp;&nbsp;&nbsp;/*我们允许每一个人从我们的模块中读取,但是只有root用户才能够写它*/
&nbsp;&nbsp;&nbsp;&nbsp;/*不知道为什么这里有许多的错误??????*/
&nbsp;&nbsp;&nbsp;&nbsp;/*倒是在include/asm-x86/current.h中看到了current是一宏定义调用get_current*/
&nbsp;&nbsp;&nbsp;&nbsp;/*就是task_struct,定义在linux/sched.h*/
&nbsp;&nbsp;&nbsp;&nbsp;/*100||010&&euid==0,表示如果是读,或者是超级用户写。但是这句话报错
&nbsp;&nbsp;&nbsp;&nbsp; * 主要current->euid有错,所以不用它了,以后慢慢解决。*/

&nbsp;&nbsp;&nbsp;&nbsp;if(op == 4 || (op == 2 && current->euid == 0))
&nbsp;&nbsp;&nbsp;&nbsp;//if(op == 4 || op == 2)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;

&nbsp;&nbsp;&nbsp;&nbsp;/*如果是其他的情况,那么就会拒绝访问*/
&nbsp;&nbsp;&nbsp;&nbsp;return -EACCES;
}

/*打开文件,我们不用关心它,但也需要注意我们需要用它来增加模块的引用次数*/
int module_open(struct inode *inode, struct file *file)
{
&nbsp;&nbsp;&nbsp;&nbsp;try_module_get(THIS_MODULE);
&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}

/*关闭文件,需要用它来减少模块的引用次数*/
int module_close(struct inode *inode, struct file *file)
{
&nbsp;&nbsp;&nbsp;&nbsp;module_put(THIS_MODULE);
&nbsp;&nbsp;&nbsp;&nbsp;return 0;
}

/*文件的操作*/
static struct file_operations File_Ops_4_Our_Proc_File = {
&nbsp;&nbsp;&nbsp;&nbsp;.read = module_output,
&nbsp;&nbsp;&nbsp;&nbsp;.write = module_input,
&nbsp;&nbsp;&nbsp;&nbsp;.open = module_open,
&nbsp;&nbsp;&nbsp;&nbsp;.release = module_close,
};

/*节点的操作,
&nbsp;* 这里设置了权限控制相关的函数,当然还有其他关于节点的函数,
&nbsp;* 不过如果我们不设置其它函数应该就只是空值
&nbsp;* */

static struct inode_operations Inode_Ops_4_Our_Proc_File = {
&nbsp;&nbsp;&nbsp;&nbsp;.permission = module_permission,
};

/*模块初始化*/
int init_module()
{
&nbsp;&nbsp;&nbsp;&nbsp;printk("<1>hello init!\n");
&nbsp;&nbsp;&nbsp;&nbsp;int rv;
&nbsp;&nbsp;&nbsp;&nbsp;rv = 0;
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File = create_proc_entry(PROC_ENTRY_FILENAME, 0644, NULL);
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->owner = THIS_MODULE;
&nbsp;&nbsp;&nbsp;&nbsp;/*使用前面定义的节点相关操作(集合)*/
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->proc_iops = &Inode_Ops_4_Our_Proc_File;
&nbsp;&nbsp;&nbsp;&nbsp;/*使用前面定义的文件相关操作(集合)
&nbsp;&nbsp;&nbsp;&nbsp; * 在前一个例子中,由于定义的操作只有读,所以它可以这样定义:
&nbsp;&nbsp;&nbsp;&nbsp; * Our_Proc_File->read_proc = procfile_read;
&nbsp;&nbsp;&nbsp;&nbsp; * */

&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->proc_fops = &File_Ops_4_Our_Proc_File;
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->mode = S_IFREG | S_IRUGO | S_IWUSR;
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->uid = 0;
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->gid = 0;
&nbsp;&nbsp;&nbsp;&nbsp;Our_Proc_File->size = 80;

&nbsp;&nbsp;&nbsp;&nbsp;if (Our_Proc_File == NULL)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rv = -ENOMEM;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_INFO "Error: Could not initialize /proc/test\n");
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;return rv;
}

/*模块卸载*/
void cleanup_module()
{
&nbsp;&nbsp;&nbsp;&nbsp;remove_proc_entry(PROC_ENTRY_FILENAME, &proc_root);
&nbsp;&nbsp;&nbsp;&nbsp;printk("<1>bye bye!\n");
}

最佳答案

查看完整内容

这个是纯C语言编程的警告。也就是说ISO C90不允许在函数中间位置定义变量,所有变量都必须在函数最开始定义。你这里先有了printk,然后再定义变量,所以报警了。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
2 [报告]
发表于 2009-08-27 16:34 |只看该作者
编译的时候警告是:
procfs2.c|134| warning: ISO C90 forbids mixed declarations and code


这个是纯C语言编程的警告。也就是说ISO C90不允许在函数中间位置定义变量,所有变量都必须在函数最开始定义。

    printk("<1>hello init!\n");
    int rv;

你这里先有了printk,然后再定义变量,所以报警了。

论坛徽章:
0
3 [报告]
发表于 2009-08-27 17:10 |只看该作者
补充一下,在linux/sched.h中我找到了相关的定义,
然后我在程序的开头包含了
#include <linux/sched.h>
这样就解决了第一个问题,
所以现在还有第2个问题没有解决,为什么有那个警告?
答对了可有5分啊^_^

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
4 [报告]
发表于 2009-08-28 11:42 |只看该作者
第一个错误,我已经确定是current->euid引起的了,

确定一下你当前版本中current结构体的定义。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
5 [报告]
发表于 2009-08-28 11:47 |只看该作者
int init_module()
{
    printk("<1>hello init!\n");
    int rv;
    rv = 0;

改成以下就可以了
int init_module()
{
    int rv;
    printk("<1>hello init!\n");

    rv = 0;

论坛徽章:
0
6 [报告]
发表于 2009-09-02 15:30 |只看该作者
原帖由 Godbach 于 2009-8-27 16:34 发表


这个是纯C语言编程的警告。也就是说ISO C90不允许在函数中间位置定义变量,所有变量都必须在函数最开始定义。


你这里先有了printk,然后再定义变量,所以报警了。

谢谢,按照你说的,我改了,然后编译之后就好用了,多谢指教!!

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
7 [报告]
发表于 2009-09-02 15:31 |只看该作者
原帖由 vaqeteart 于 2009-9-2 15:30 发表

谢谢,按照你说的,我改了,然后编译之后就好用了,多谢指教!!


呵呵,不客气。共同学习。

论坛徽章:
0
8 [报告]
发表于 2009-09-02 16:23 |只看该作者
感觉 file_operations 操作起来很麻烦,要一堆结构……
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP