如何在Linux上创build一个自定义的文件描述符

我想创build一个文件,其描述符将具有一些可定制的行为。 特别是,我想创build一个文件描述符,当写入时,会在每一行的前面加上进程的名称和pid(也许是时间),但我可以想象做其他事情会很有用。

我不想改变写程序 – 一方面,我希望它可以在我系统上的所有程序上运行,甚至是shell / perl / etc。 脚本,如果不是不可能改变一切的源代码是不切实际的。

请注意,在这种情况下pipe道是不行的,因为当写入进程fork() s时,新创build的subprocess共享fd,并且在pipe道的读取结束时与父进程不可区分。

有办法可以做,但我认为他们很笨拙:

  1. 创build一个内核模块来创build这样的fds。 例如,你可以打开一些/dev/customfd然后指示模块进行一些转换等,或者把数据发送到用户空间或者套接字等等。
  2. 使用LD_PRELOAD将覆盖fd操作函数,并在“特殊”fd上执行这些操作。

但是,这两种方法都非常费力,所以我想知道是否有更好的方法,或者任何基础设施(如现成的图书馆)都会有所帮助。

我更喜欢一个不涉及内核变化的解决scheme,但如果有必要,我已经准备好接受它们。

只是一个想法:FUSE会是一个答案吗?

你有很多选择,正如你所提到的使用LD_PRELOAD封装write()/ read()函数是一个好方法。

我建议你使用unix ptrace(2)来捕获所需的系统调用,并将参数传递给你自己的函数。

例如:

 #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <linux/user.h> #include <sys/syscall.h> /* For SYS_write etc */ int main() { pid_t child; long orig_eax, eax; long params[3]; int status; int insyscall = 0; child = fork(); if(child == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl("/bin/ls", "ls", NULL); } else { while(1) { wait(&status); if(WIFEXITED(status)) break; orig_eax = ptrace(PTRACE_PEEKUSER, child, 4 * ORIG_EAX, NULL); if(orig_eax == SYS_write) { if(insyscall == 0) { /* Syscall entry */ insyscall = 1; params[0] = ptrace(PTRACE_PEEKUSER, child, 4 * EBX, NULL); params[1] = ptrace(PTRACE_PEEKUSER, child, 4 * ECX, NULL); params[2] = ptrace(PTRACE_PEEKUSER, child, 4 * EDX, NULL); printf("Write called with " "%ld, %ld, %ld\n", params[0], params[1], params[2]); } else { /* Syscall exit */ eax = ptrace(PTRACE_PEEKUSER, child, 4 * EAX, NULL); printf("Write returned " "with %ld\n", eax); insyscall = 0; } } ptrace(PTRACE_SYSCALL, child, NULL, NULL); } } return 0; }