从内核空间中的STDIN读取数据

时间:2015-04-02 17:20:08

标签: kernel freebsd system-calls

我正在尝试为FreeBSD 9.3.0编写内核模块,我想在其中使用read Syscall。我已经包含了相应的标题(以及其他标题):

#include<sys/sysproto.h>
#include<sys/unistd.h>
#include<sys/types.h>
#include<sys/uio.h>
#include<sys/cdefs.h>

但是当我运行make时,我收到以下错误:

  
    

隐式声明函数read

  

我还查看了所述标题的源文件,并搜索了sys/syssys/kern中的很多源代码树,寻找所述函数,但我无法找到它。 注意:我可以成功使用同一程序中的printf系统调用。(没有read调用编译)

更新:文档实际上声明包含unistd.h。但是那个在C标准库中,我不能在内核中使用它。所以问题变成了这个,我还有其他什么选择? (我试图从STDIN读取)

1 个答案:

答案 0 :(得分:3)

我同意@qarma认为在内核空间中代表用户进程执行读取有点奇怪 - 用户空间应该发出自己的读取调用,特别是因为所有的安全检查和处理当您在内核模式下运行时,策略检查不在窗口,以及进程记帐,统计等。内核模式在处理数据和访问时需要非常小心。

有更好的方法可以将数据输入和输出内核模块。 This post on the FreeBSD forums提到一个:

  

如果您想了解如何正确处理驱动程序中的文件,   看看pf(4)如何使用用户空间助手程序pfctl(8)来实现   读取配置文件并将其转换为二进制数据   然后通过/ dev / pf将结果提供给内核驱动程序   设备

或者,您可以使用用户模式程序将数据从磁盘/等加载到某个缓冲区并执行ioctl以获取数据;但是,读/写/ dev / MyDriver端点可能更好。

如果您确实发现自己需要完全按照您的要求进行操作,那么相同的帖子表明内核的至少某些部分写入文件系统 - 进程coredumper - 帖子指向kern/kern_sig.c as一个例子:

static int
coredump(struct thread *td)
{
    struct proc *p = td->td_proc;
    struct ucred *cred = td->td_ucred;
    struct vnode *vp;
    struct flock lf;
    struct vattr vattr;
    int error, error1, locked;
    struct mount *mp;
    char *name;         /* name of corefile */
    off_t limit;
    int compress;

...
    error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, compress, &vp, &name);

coredump调用corefile_open打开文件,将其作为输出vpvname,其中vp是指向vnode对象的指针。

深入研究corefile_open,我们看到:

static int
corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td,
    int compress, struct vnode **vpp, char **namep)
{
    struct nameidata nd;
    struct sbuf sb;
    const char *format;
    char *hostname, *name;
    int indexpos, i, error, cmode, flags, oflags;

...

    flags = O_CREAT | FWRITE | O_NOFOLLOW;
    NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, td);
    error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred, NULL);
...
    NDFREE(&nd, NDF_ONLY_PNBUF);
    *vpp = nd.ni_vp;

注意对vn_open_cred的调用 - 完成后,我们可以使用刚刚初始化的nd.ni_vp变量来获取我们的vnode指针。请注意对NDINIT和NDFREE的调用。

如果您愿意,可以挖掘更多内容 - vfs_cnops.c包含vn_open_cred的实现,可能看起来很熟悉:

int
vn_open_cred(struct nameidata *ndp, int *flagp, int cmode, u_int vn_open_flags,
    struct ucred *cred, struct file *fp)
{
    struct vnode *vp;
    struct mount *mp;
    struct thread *td = ndp->ni_cnd.cn_thread;
    struct vattr vat;
    struct vattr *vap = &vat;
    int fmode, error;

... lots of setup ...

    error = vn_open_vnode(vp, fmode, cred, td, fp);

你有它 - vn_open_vnode终于完成了真正的工作。

你最好的选择可能是vn_open_cred