Kernel 在内核空间中从STDIN读取数据

Kernel 在内核空间中从STDIN读取数据,kernel,freebsd,system-calls,Kernel,Freebsd,System Calls,我正试图为FreeBSD 9.3.0编写一个内核模块,我想在其中使用read系统调用。我已包括适当的标题(除其他外): #包括 #包括 #包括 #包括 #包括 但是,当我运行make时,会出现以下错误: 函数的隐式声明read 我还查看了上述标题的源文件,并在sys/sys和sys/kern中搜索了大量源代码树,以查找上述函数,但我找不到它。 注意:我可以从同一个程序成功使用printfsystemcall。(编译时没有read调用) 更新:文档实际声明包括unistd.h。但是这是在C标准库

我正试图为
FreeBSD 9.3.0
编写一个内核模块,我想在其中使用
read
系统调用。我已包括适当的标题(除其他外):

#包括
#包括
#包括
#包括
#包括
但是,当我运行make时,会出现以下错误:

函数的隐式声明
read

我还查看了上述标题的源文件,并在
sys/sys
sys/kern
中搜索了大量源代码树,以查找上述函数,但我找不到它。 注意:我可以从同一个程序成功使用
printf
systemcall。(编译时没有
read
调用)


更新:文档实际声明包括
unistd.h
。但是这是在C标准库中,我不能在内核中使用它。所以问题变成了,我还有什么其他的选择?(我试着从
STDIN
)读取我同意@qarma的观点,即代表用户进程在内核空间执行读取有点奇怪-用户空间应该发出自己的读取调用,特别是当您在内核模式下运行时,所有的安全检查和进程策略检查都在窗口之外,以及进程记帐、统计等。内核模式在处理数据和访问时需要格外小心

有很多更好的方法可以将数据进出内核模块。提到一个:

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

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

如果您真的发现自己需要完全按照您的要求去做,那么同一篇文章指出至少内核的某些部分会写入文件系统-进程coredumpper-文章指向
kern/kern_sig.c
,例如:

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\u open
打开文件,将其作为输出
vp
vname
,其中
vp
是指向vnode对象的指针

深入到
corefile\u 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\u open\u cred
——完成后,我们可以使用新初始化的
nd.ni\u vp
变量来获取我们的vnode指针。注意对NDINIT和NDFREE的调用

如果需要,您可以深入了解更多-
vfs\u cnops.c
包含
vn\u open\u 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\u open\u cred

您正在尝试做一些非常奇怪的事情。在内核中调用
read
的目的是什么?您是否代表用户这样做?数据将被放入userland缓冲区吗?是的,数据将被发送到userland。(这是一个赋值)如果您想做的是在数据到达用户的应用程序之前从用户的tty设备读取数据,那么编写一个行规程可能会更容易。
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);