2009-05-18 47 views
10

我有一堆流量和數據處理應用程序,我偶爾需要監視,這意味着我需要知道他們讀取了哪些文件。這主要是爲了幫助包裝測試用例,但在調試時也很有用。如何檢測Linux中的文件訪問?

有沒有辦法以這種方式運行可執行文件,生成這樣的列表?

我對此有兩種思想:

  1. 有,我可以調用命令,並且命令調用我的應用程序。一些沿着GDB的路線。我調用GDB,給它一個可執行文件的路徑,一些參數和GDB爲我調用它。也許有些東西類似於告訴我如何使用系統資源。
  2. 也許更有趣(但不必要的副路徑)解決方案。
    1. 創建庫名爲libc.so,它實現的fopen(和其他一些)
    2. 變化LD_LIBRARY_PATH在新圖書館
    3. 點使真正的libc.so的複製和重命名的fopen(nepof,也許)在編輯器中
    4. 我的程序庫加載副本並根據需要調用重命名的函數以提供fopen功能。
    5. 調用應用程序,然後調用我的代理服務器fopen。

替代#1肯定是最好的一個,但意見如何做#2更容易也歡迎。

+0

另請參閱http://stackoverflow.com/q/2972765/119790 – 2011-02-10 17:32:05

回答

13

一種選擇是使用strace的:

strace -o logfile -eopen yourapp 

這將記錄所有文件的公開活動,但它會施加可能很重要的表現懲罰。它具有易於使用的優點。

另一種選擇是使用LD_PRELOAD。這對應於您的選項#2。其基本思路是做這樣的事情:

#define _GNU_SOURCE 
#include <stdio.h> 
#include <dlfcn.h> 

int open(const char *fn, int flags) { 
    static int (*real_open)(const char *fn, int flags); 

    if (!real_open) { 
     real_open = dlsym(RTLD_NEXT, "open"); 
    } 

    fprintf(stderr, "opened file '%s'\n", fn); 
    return real_open(fn, flags); 
} 

然後用建:

gcc -fPIC -shared -ldl -o preload-example.so preload-example.c 

而且具有如運行程序:

$ LD_PRELOAD=$PWD/preload-example.so cat /dev/null 
opened file '/dev/null' 

這有少得多的開銷。

但是請注意,有文件打開其他入口點 - 例如,fopen()函數,了openat(),或許多遺留兼容性入口點之一:

00000000000747d0 g DF .text  000000000000071c GLIBC_2.2.5 _IO_file_fopen 
0000000000068850 g DF .text  000000000000000a GLIBC_2.2.5 fopen 
000000000006fe60 g DF .text  00000000000000e2 GLIBC_2.4 open_wmemstream 
00000000001209c0 w DF .text  00000000000000ec GLIBC_2.2.5 posix_openpt 
0000000000069e50 g DF .text  00000000000003fb GLIBC_2.2.5 _IO_proc_open 
00000000000dcf70 g DF .text  0000000000000021 GLIBC_2.7 __open64_2 
0000000000068a10 g DF .text  00000000000000f5 GLIBC_2.2.5 fopencookie 
000000000006a250 g DF .text  000000000000009b GLIBC_2.2.5 popen 
00000000000d7b10 w DF .text  0000000000000080 GLIBC_2.2.5 __open64 
0000000000068850 g DF .text  000000000000000a GLIBC_2.2.5 _IO_fopen 
00000000000d7e70 w DF .text  0000000000000020 GLIBC_2.7 __openat64_2 
00000000000e1ef0 g DF .text  000000000000005b GLIBC_2.2.5 openlog 
00000000000d7b10 w DF .text  0000000000000080 GLIBC_2.2.5 open64 
0000000000370c10 g DO .bss  0000000000000008 GLIBC_PRIVATE _dl_open_hook 
0000000000031680 g DF .text  0000000000000240 GLIBC_2.2.5 catopen 
000000000006a250 g DF .text  000000000000009b GLIBC_2.2.5 _IO_popen 
0000000000071af0 g DF .text  000000000000026a GLIBC_2.2.5 freopen64 
00000000000723a0 g DF .text  0000000000000183 GLIBC_2.2.5 fmemopen 
00000000000a44f0 w DF .text  0000000000000088 GLIBC_2.4 fdopendir 
00000000000d7e70 g DF .text  0000000000000020 GLIBC_2.7 __openat_2 
00000000000a3d00 w DF .text  0000000000000095 GLIBC_2.2.5 opendir 
00000000000dcf40 g DF .text  0000000000000021 GLIBC_2.7 __open_2 
00000000000d7b10 w DF .text  0000000000000080 GLIBC_2.2.5 __open 
0000000000074370 g DF .text  00000000000000d7 GLIBC_2.2.5 _IO_file_open 
0000000000070b40 g DF .text  00000000000000d2 GLIBC_2.2.5 open_memstream 
0000000000070450 g DF .text  0000000000000272 GLIBC_2.2.5 freopen 
00000000000318c0 g DF .text  00000000000008c4 GLIBC_PRIVATE __open_catalog 
00000000000d7b10 w DF .text  0000000000000080 GLIBC_2.2.5 open 
0000000000067e80 g DF .text  0000000000000332 GLIBC_2.2.5 fdopen 
000000000001e9b0 g DF .text  00000000000003f5 GLIBC_2.2.5 iconv_open 
00000000000daca0 g DF .text  000000000000067b GLIBC_2.2.5 fts_open 
00000000000d7d60 w DF .text  0000000000000109 GLIBC_2.4 openat 
0000000000068850 w DF .text  000000000000000a GLIBC_2.2.5 fopen64 
00000000000d7d60 w DF .text  0000000000000109 GLIBC_2.4 openat64 
00000000000d6490 g DF .text  00000000000000b6 GLIBC_2.2.5 posix_spawn_file_actions_addopen 
0000000000121b80 g DF .text  000000000000008a GLIBC_PRIVATE __libc_dlopen_mode 
0000000000067e80 g DF .text  0000000000000332 GLIBC_2.2.5 _IO_fdopen 

您可能需要掛鉤所有這些都是爲了完整性 - 至少,沒有以_作爲前綴的應該被吸引。特別是,一定要單獨掛接fopen,因爲從fopen()到open()的libc內部調用未被LD_PRELOAD庫掛鉤。

類似的警告適用於strace - 也有'openat'系統調用,並且根據您的架構,可能還有其他傳統系統調用。但並不像LD_PRELOAD鉤子那樣多,所以如果你不介意性能問題,這可能是一個更簡單的選擇。

4
man strace 

例如(假設2343是進程ID):

# logging part 
strace -p 2343 -ff -o strace_log.txt 

# displaying part 
grep ^open strace_log.txt 
2

我用的是一樣的東西:

strace -o file.txt ./command 

然後,您可以

cat file.txt | grep open 

把所有該程序打開的文件列表。