c - 获取一个与内核中的任何内容都不相关的唯一文件描述符

标签 c linux mocking

我正在寻找一种方法来为与任何特定内容无关的进程获取唯一的文件描述符。它必须是一个唯一的整数,内核不会为其创建等效的文件描述符。

到目前为止,我只是打开 /dev/null 以获得唯一的文件描述符编号。我想知道是否有人知道实现此目的的更好方法(例如,某种“create_fd()”系统调用)。

最佳答案

您可以创建一个模块并通过 ioctl() 或使用 proc 文件添加模拟文件描述符创建。文件描述符表仅存在于管理员模式(在内核中)。我不明白如何在不创建新内核模块或重用恰好可以执行您想要的操作的情况下保留它。

参见 fdtable.h在内核源代码和files_struct在 task_struct(进程描述符)中获取详细信息。

这是一个可以做你想做的事情的 proc 文件系统模块。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>

#define procfs_name "always_fail"

struct proc_dir_entry *proc_file;

int procfile_read(char *buffer,
          char **buffer_location,
          off_t offset, int buffer_length, int *eof, void *data)
{   
    printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);

    return -1;
}

int init_module()
{
    proc_file = create_proc_entry(procfs_name, 0644, NULL);

    if (proc_file == NULL) {
        remove_proc_entry(procfs_name, &proc_root);
        printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
               procfs_name);
        return -ENOMEM;
    }

    proc_file->read_proc     = procfile_read;
    proc_file->owner         = THIS_MODULE;
    proc_file->mode          = S_IFREG | S_IRUGO;
    proc_file->uid           = 0;
    proc_file->gid           = 0;
    proc_file->size          = 0;

    printk(KERN_INFO "/proc/%s created\n", procfs_name);    
    return 0;
}

void cleanup_module()
{
    remove_proc_entry(procfs_name, &proc_root);
    printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}

阅读时应该打印类似这样的内容:

cat /proc/always_fail
cat: /proc/always_fail: File descriptor in bad state

另一种 hackish 方法是简单地使用 /dev/net/tun 假设你有它。它会在读取和写入时失败,但不会在打开时失败。

证明:

$ sudo strace cat /dev/net/tun 
execve("/bin/cat", ["cat", "/dev/net/tun"], [/* 18 vars */]) = 0
brk(0)                                  = 0x24c5000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fed22000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=128879, ...}) = 0
mmap(NULL, 128879, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f83fed02000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1848024, ...}) = 0
mmap(NULL, 3961912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f83fe73a000
mprotect(0x7f83fe8f8000, 2093056, PROT_NONE) = 0
mmap(0x7f83feaf7000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f83feaf7000
mmap(0x7f83feafd000, 17464, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f83feafd000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fed01000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fecff000
arch_prctl(ARCH_SET_FS, 0x7f83fecff740) = 0
mprotect(0x7f83feaf7000, 16384, PROT_READ) = 0
mprotect(0x60a000, 4096, PROT_READ)     = 0
mprotect(0x7f83fed24000, 4096, PROT_READ) = 0
munmap(0x7f83fed02000, 128879)          = 0
brk(0)                                  = 0x24c5000
brk(0x24e6000)                          = 0x24e6000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7220496, ...}) = 0
mmap(NULL, 7220496, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f83fe057000
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
**open("/dev/net/tun", O_RDONLY)          = 3**
fstat(3, {st_mode=S_IFCHR|S_ISVTX|0666, st_rdev=makedev(10, 200), ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
**read(3, 0x24c7000, 65536)               = -1 EBADFD (File descriptor in bad state)**
write(2, "cat: ", 5cat: )                    = 5
write(2, "/dev/net/tun", 12/dev/net/tun)            = 12
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fed21000
read(4, "# Locale name alias data base.\n#"..., 4096) = 2570
read(4, "", 4096)                       = 0
close(4)                                = 0
munmap(0x7f83fed21000, 4096)            = 0
open("/usr/share/locale/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": File descriptor in bad state", 30: File descriptor in bad state) = 30
write(2, "\n", 1
)                       = 1
**close(3)                                = 0**
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?
eric@ideapad:~$ sudo strace cat /dev/net/tun 
execve("/bin/cat", ["cat", "/dev/net/tun"], [/* 18 vars */]) = 0
brk(0)                                  = 0x109f000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3db000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=128879, ...}) = 0
mmap(NULL, 128879, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fdc6d3bb000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1848024, ...}) = 0
mmap(NULL, 3961912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fdc6cdf3000
mprotect(0x7fdc6cfb1000, 2093056, PROT_NONE) = 0
mmap(0x7fdc6d1b0000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7fdc6d1b0000
mmap(0x7fdc6d1b6000, 17464, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d1b6000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3ba000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3b8000
arch_prctl(ARCH_SET_FS, 0x7fdc6d3b8740) = 0
mprotect(0x7fdc6d1b0000, 16384, PROT_READ) = 0
mprotect(0x60a000, 4096, PROT_READ)     = 0
mprotect(0x7fdc6d3dd000, 4096, PROT_READ) = 0
munmap(0x7fdc6d3bb000, 128879)          = 0
brk(0)                                  = 0x109f000
brk(0x10c0000)                          = 0x10c0000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7220496, ...}) = 0
mmap(NULL, 7220496, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fdc6c710000
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
open("/dev/net/tun", O_RDONLY)          = 3
fstat(3, {st_mode=S_IFCHR|S_ISVTX|0666, st_rdev=makedev(10, 200), ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, 0x10a1000, 65536)               = -1 EBADFD (File descriptor in bad state)
write(2, "cat: ", 5cat: )                    = 5
write(2, "/dev/net/tun", 12/dev/net/tun)            = 12
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3da000
read(4, "# Locale name alias data base.\n#"..., 4096) = 2570
read(4, "", 4096)                       = 0
close(4)                                = 0
munmap(0x7fdc6d3da000, 4096)            = 0
open("/usr/share/locale/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": File descriptor in bad state", 30: File descriptor in bad state) = 30
write(2, "\n", 1
)                       = 1
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?

关于c - 获取一个与内核中的任何内容都不相关的唯一文件描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16704545/

相关文章:

c - 如何在到达给定断点之前自动打印 GDB 中的每一行?

Linux 外壳 : why is "open" required in this telnet command

c# - 无法在单元测试项目中使用 ConfigurationManager

python - 隔离依赖于初始化程序的测试的好方法

python - 如何模拟从函数导入但不存在于 sys.path 中的模块?

c - 为什么这个C程序会崩溃?

c - 为什么每次迭代时冒泡排序都不能正确打印?

c++ - 下面的数组和指针示例背后的逻辑是什么?

php - 从日期值为 xxxx-xx-xx 的 sql 值中选择年份

python - 以编程方式设置文件写入速率