什么会导致 "regular" 类型的文件在 Linux 中不可读以及如何识别它

What can cause a "regular" type file not to be readable in Linux and how to identify this

我正在遍历我的整个文件系统,使用诸如幻数之类的标识符来寻找某些类型的文件。

我偶然发现了一些应该是 "regular" (DT_REG) 类型的文件,但是文件无法读取(read 系统调用returns 错误 38 - 系统调用未实现)。这些文件名为 "alloc_calls",位于“/sys/kernel/slab/:d-xxxxxxx/”(其中 xxxxxxx 是一个类似于 0001024 的数字)。
这是其中一个文件的 ls -lfilecat 的输出:

root@VMint:/# ls -l /sys/kernel/slab/:d-0001024/alloc_calls
-r-------- 1 root root 4096 Aug  8 18:55 /sys/kernel/slab/:d-0001024/alloc_calls
root@VMint:/# file /sys/kernel/slab/:d-0001024/alloc_calls
/sys/kernel/slab/:d-0001024/alloc_calls: ERROR: cannot read /sys/kernel/slab/:d-0001024/alloc_calls' (Function not implemented)
root@VMint:/# cat /sys/kernel/slab/:d-0001024/alloc_calls
cat: '/sys/kernel/slab/:d-0001024/alloc_calls': Function not implemented

我写了一些 C 代码来证明这一点:

#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
void main()
{
    char buf;
    int fd = open("/sys/kernel/slab/:d-0001024/alloc_calls", 0);
    perror("open");
    read(fd, &buf, 1);
    perror("read");
    printf("fd: %d, errno: %d\n",fd, errno);
}

执行这段代码得到:

# gcc ./enosys.c -o enosys
# c_test sudo ./enosys           
open: Success
read: Function not implemented
fd: 3, errno: 38

普通文件怎么会是root无法读取的呢?另外,如何识别此类文件?

/proc/sys 中的文件很神奇。它们不是真正的文件——当您读写它们时,您实际上是在读写各种内核数据结构。 (mount 命令将显示它们都是挂载的文件系统,类型分别为 procsysfs。)

对于任何存在于这些目录中的任何 "file",这意味着存在一个内核数据结构,有人认为以这种方式公开它可能有用。为了进行公开,必须设置不同的代码来实现 read() 从数据结构中获取,而 write() 存储到它。

因此,对于以这种方式公开的给定内核数据结构,如果某人实际所做的是在特定数据结构上实现(比如说)写而不是读,您会看到这样的结果。

当您调用 read() 时实际发生的是内核查找文件系统,也许还有您正在读取的单个文件,应该使用 read 的哪个设备相关实现对于那个文件。如果没有,则错误是(很自然地)ENOSYS "syscall not implemented".

Also, how can I identify such files?

我怀疑有办法!但在 /proc/sys 之外,它可能永远不会发生。无论如何,您可能希望从任何像这样的自动搜索中排除 /proc/sys -- 那里有很多魔法,所以当您开始不加选择地阅读文件时,可能会发生很多奇怪的事情。