Skip to content

Commit a6160df

Browse files
committed
tools/filegone: Support file path
Support for file paths using path_helpers. For example: $ realpath . /home/sdb/Git/bcc/build $ touch a.out && sleep 0.2 && mv a.out b.out && sleep 0.2 && rm b.out $ sudo ./filegone.py -P TIME PID COMM ACTION FILE 21:22:37 58683 mv RENAME /home/sdb/Git/bcc/build/a.out > /home/sdb/Git/bcc/build/b.out 21:22:37 58685 rm DELETE /home/sdb/Git/bcc/build/b.out Signed-off-by: Rong Tao <[email protected]>
1 parent 0cf1865 commit a6160df

File tree

2 files changed

+77
-10
lines changed

2 files changed

+77
-10
lines changed

tools/filegone.py

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# 08-Nov-2022 Curu. modified from filelife
1212
# 19-Nov-2022 Rong Tao Check btf struct field instead of KERNEL_VERSION macro.
1313
# 05-Nov-2023 Rong Tao Support rename/unlink failed situation.
14+
# 01-Jul-2025 Rong Tao Support file path
1415

1516
from __future__ import print_function
1617
from bcc import BPF
@@ -20,6 +21,7 @@
2021
# arguments
2122
examples = """examples:
2223
./filegone # trace all file gone events
24+
./filegone -P # show file path
2325
./filegone -p 181 # only trace PID 181
2426
"""
2527
parser = argparse.ArgumentParser(
@@ -28,6 +30,8 @@
2830
epilog=examples)
2931
parser.add_argument("-p", "--pid",
3032
help="trace this PID only")
33+
parser.add_argument("-P", "--path", action="store_true",
34+
help="show file path")
3135
parser.add_argument("--ebpf", action="store_true",
3236
help=argparse.SUPPRESS)
3337
args = parser.parse_args()
@@ -37,21 +41,33 @@
3741
bpf_text = """
3842
#include <uapi/linux/ptrace.h>
3943
#include <linux/fs.h>
44+
#include <linux/fs_struct.h>
4045
#include <linux/sched.h>
46+
#ifdef FULLPATH
47+
INCLUDE_FULL_PATH_H
48+
INCLUDE_PATH_HELPERS_BPF_H
49+
#endif
4150
4251
struct data_t {
4352
u32 pid;
4453
u8 action;
4554
char comm[TASK_COMM_LEN];
46-
char fname[DNAME_INLINE_LEN];
47-
char fname2[DNAME_INLINE_LEN];
55+
u32 path_depth, path_depth2;
56+
#ifdef FULLPATH
57+
FULL_PATH_FIELD(fname);
58+
FULL_PATH_FIELD(fname2);
59+
#else
60+
char fname[NAME_MAX];
61+
char fname2[NAME_MAX];
62+
#endif
4863
};
4964
5065
struct entry_t {
5166
u32 pid;
5267
u8 action;
5368
struct {
5469
char name[DNAME_INLINE_LEN];
70+
struct dentry *dentry;
5571
} old, new;
5672
};
5773
@@ -79,6 +95,7 @@
7995
8096
entry.pid = pid;
8197
entry.action = 'D';
98+
entry.old.dentry = dentry;
8299
get_dentry_name((char **)&entry.old.name, dentry);
83100
84101
currentry.update(&tid, &entry);
@@ -103,7 +120,9 @@
103120
* Couldn't get new and old dentry name in trace_return(), because you'll
104121
* get new-name for old.
105122
*/
123+
entry.old.dentry = old_dentry;
106124
get_dentry_name((char **)&entry.old.name, old_dentry);
125+
entry.new.dentry = new_dentry;
107126
get_dentry_name((char **)&entry.new.name, new_dentry);
108127
109128
currentry.update(&tid, &entry);
@@ -138,9 +157,33 @@
138157
139158
bpf_probe_read(&data->fname, sizeof(data->fname), entry->old.name);
140159
160+
data->path_depth = data->path_depth2 = 0;
141161
if (entry->action == 'R')
142162
bpf_probe_read(&data->fname2, sizeof(data->fname2), entry->new.name);
143163
164+
#ifdef FULLPATH
165+
struct task_struct *task;
166+
struct fs_struct *fs;
167+
struct vfsmount *cwd_vfsmnt;
168+
169+
task = (struct task_struct *)bpf_get_current_task_btf();
170+
bpf_probe_read_kernel(&fs, sizeof(fs), &task->fs);
171+
bpf_probe_read_kernel(&cwd_vfsmnt, sizeof(cwd_vfsmnt), &fs->pwd.mnt);
172+
if (data->fname[0] != '/') {
173+
data->path_depth = 1;
174+
bpf_dentry_full_path(data->fname + NAME_MAX, NAME_MAX, MAX_ENTRIES - 1,
175+
entry->old.dentry->d_parent, cwd_vfsmnt,
176+
&data->path_depth);
177+
}
178+
179+
if (entry->action == 'R' && data->fname2[0] != '/') {
180+
data->path_depth2 = 1;
181+
bpf_dentry_full_path(data->fname2 + NAME_MAX, NAME_MAX, MAX_ENTRIES - 1,
182+
entry->new.dentry->d_parent, cwd_vfsmnt,
183+
&data->path_depth2);
184+
}
185+
#endif
186+
144187
events.ringbuf_submit(data, sizeof(*data));
145188
return 0;
146189
}
@@ -192,6 +235,17 @@ def action2str(action):
192235
bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_old)
193236
bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_1)
194237

238+
if args.path:
239+
bpf_text = "#define FULLPATH\n" + bpf_text
240+
241+
with open(BPF._find_file("full_path.h".encode("utf-8"))) as fileobj:
242+
progtxt = fileobj.read()
243+
bpf_text = bpf_text.replace('INCLUDE_FULL_PATH_H', progtxt)
244+
245+
with open(BPF._find_file("path_helpers.bpf.c".encode("utf-8"))) as fileobj:
246+
progtxt = fileobj.read()
247+
bpf_text = bpf_text.replace('INCLUDE_PATH_HELPERS_BPF_H', progtxt)
248+
195249
# NOTE: After bpf_text modification
196250
if debug or args.ebpf:
197251
print(bpf_text)
@@ -214,10 +268,20 @@ def action2str(action):
214268
def print_event(cpu, data, size):
215269
event = b["events"].event(data)
216270
action_str = action2str(event.action)
217-
file_str = event.fname.decode('utf-8', 'replace')
218-
if action_str == "RENAME":
219-
file2_str = event.fname2.decode('utf-8', 'replace')
220-
file_str = "%s > %s" % (file_str, file2_str)
271+
if args.path:
272+
import os
273+
import sys
274+
sys.path.append(os.path.dirname(sys.argv[0]))
275+
from path_helpers import get_full_path
276+
file_str = get_full_path(event.fname, event.path_depth)
277+
if action_str == "RENAME":
278+
file2_str = get_full_path(event.fname2, event.path_depth2)
279+
file_str = "%s > %s" % (file_str, file2_str)
280+
else:
281+
file_str = event.fname.decode('utf-8', 'replace')
282+
if action_str == "RENAME":
283+
file2_str = event.fname2.decode('utf-8', 'replace')
284+
file_str = "%s > %s" % (file_str, file2_str)
221285
print("%-8s %-7d %-16s %6s %s" % (strftime("%H:%M:%S"), event.pid,
222286
event.comm.decode('utf-8', 'replace'), action_str, file_str))
223287

tools/filegone_example.txt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@ For example:
1313

1414
USAGE message:
1515

16-
usage: filegone.py [-h] [-p PID]
16+
# ./filegone -h
17+
usage: filegone.py [-h] [-p PID] [-P]
1718

1819
Trace why file gone (deleted or renamed)
1920

20-
optional arguments:
21-
-h, --help show this help message and exit
22-
-p PID, --pid PID trace this PID only
21+
options:
22+
-h, --help show this help message and exit
23+
-p, --pid PID trace this PID only
24+
-P, --path show file path
2325

2426
examples:
2527
./filegone # trace all file gone events
28+
./filegone -P # show file path
2629
./filegone -p 181 # only trace PID 181

0 commit comments

Comments
 (0)