xref: /aosp_15_r20/external/bcc/tools/old/filegone.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# filegone    Trace why file gone (deleted or renamed).
5*387f9dfdSAndroid Build Coastguard Worker#             For Linux, uses BCC, eBPF. Embedded C.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: filegone [-h] [-p PID]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# 08-Nov-2022 Curu. modified from filelife
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
14*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
15*387f9dfdSAndroid Build Coastguard Workerimport argparse
16*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Worker# arguments
19*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
20*387f9dfdSAndroid Build Coastguard Worker    ./filegone           # trace all file gone events
21*387f9dfdSAndroid Build Coastguard Worker    ./filegone -p 181    # only trace PID 181
22*387f9dfdSAndroid Build Coastguard Worker"""
23*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
24*387f9dfdSAndroid Build Coastguard Worker    description="Trace why file gone (deleted or renamed)",
25*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
26*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
27*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
28*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
29*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
30*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
31*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
32*387f9dfdSAndroid Build Coastguard Workerdebug = 0
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Worker# define BPF program
35*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
36*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
37*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h>
38*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Workerstruct data_t {
41*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
42*387f9dfdSAndroid Build Coastguard Worker    u8 action;
43*387f9dfdSAndroid Build Coastguard Worker    char comm[TASK_COMM_LEN];
44*387f9dfdSAndroid Build Coastguard Worker    char fname[DNAME_INLINE_LEN];
45*387f9dfdSAndroid Build Coastguard Worker    char fname2[DNAME_INLINE_LEN];
46*387f9dfdSAndroid Build Coastguard Worker};
47*387f9dfdSAndroid Build Coastguard Worker
48*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events);
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Worker// trace file deletion and output details
51*387f9dfdSAndroid Build Coastguard Worker#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)
52*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
53*387f9dfdSAndroid Build Coastguard Worker#else
54*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct user_namespace *ns, struct inode *dir, struct dentry *dentry)
55*387f9dfdSAndroid Build Coastguard Worker#endif
56*387f9dfdSAndroid Build Coastguard Worker{
57*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Worker    FILTER
60*387f9dfdSAndroid Build Coastguard Worker
61*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {};
62*387f9dfdSAndroid Build Coastguard Worker    struct qstr d_name = dentry->d_name;
63*387f9dfdSAndroid Build Coastguard Worker    if (d_name.len == 0)
64*387f9dfdSAndroid Build Coastguard Worker        return 0;
65*387f9dfdSAndroid Build Coastguard Worker
66*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&data.comm, sizeof(data.comm));
67*387f9dfdSAndroid Build Coastguard Worker    data.pid = pid;
68*387f9dfdSAndroid Build Coastguard Worker    data.action = 'D';
69*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read(&data.fname, sizeof(data.fname), d_name.name);
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker    return 0;
74*387f9dfdSAndroid Build Coastguard Worker}
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker// trace file rename
77*387f9dfdSAndroid Build Coastguard Worker#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)
78*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct inode *old_dir, struct dentry *old_dentry,
79*387f9dfdSAndroid Build Coastguard Workerstruct inode *new_dir, struct dentry *new_dentry)
80*387f9dfdSAndroid Build Coastguard Worker{
81*387f9dfdSAndroid Build Coastguard Worker#else
82*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct renamedata *rd)
83*387f9dfdSAndroid Build Coastguard Worker{
84*387f9dfdSAndroid Build Coastguard Worker    struct dentry *old_dentry = rd->old_dentry;
85*387f9dfdSAndroid Build Coastguard Worker    struct dentry *new_dentry = rd->new_dentry;
86*387f9dfdSAndroid Build Coastguard Worker#endif
87*387f9dfdSAndroid Build Coastguard Worker
88*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker    FILTER
91*387f9dfdSAndroid Build Coastguard Worker
92*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {};
93*387f9dfdSAndroid Build Coastguard Worker    struct qstr s_name = old_dentry->d_name;
94*387f9dfdSAndroid Build Coastguard Worker    struct qstr d_name = new_dentry->d_name;
95*387f9dfdSAndroid Build Coastguard Worker    if (s_name.len == 0 || d_name.len == 0)
96*387f9dfdSAndroid Build Coastguard Worker        return 0;
97*387f9dfdSAndroid Build Coastguard Worker
98*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&data.comm, sizeof(data.comm));
99*387f9dfdSAndroid Build Coastguard Worker    data.pid = pid;
100*387f9dfdSAndroid Build Coastguard Worker    data.action = 'R';
101*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read(&data.fname, sizeof(data.fname), s_name.name);
102*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read(&data.fname2, sizeof(data.fname), d_name.name);
103*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker    return 0;
106*387f9dfdSAndroid Build Coastguard Worker}
107*387f9dfdSAndroid Build Coastguard Worker"""
108*387f9dfdSAndroid Build Coastguard Worker
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Workerdef action2str(action):
111*387f9dfdSAndroid Build Coastguard Worker    if chr(action) == 'D':
112*387f9dfdSAndroid Build Coastguard Worker        action_str = "DELETE"
113*387f9dfdSAndroid Build Coastguard Worker    else:
114*387f9dfdSAndroid Build Coastguard Worker        action_str = "RENAME"
115*387f9dfdSAndroid Build Coastguard Worker    return action_str
116*387f9dfdSAndroid Build Coastguard Worker
117*387f9dfdSAndroid Build Coastguard Workerif args.pid:
118*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER',
119*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }' % args.pid)
120*387f9dfdSAndroid Build Coastguard Workerelse:
121*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER', '')
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
124*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
125*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
126*387f9dfdSAndroid Build Coastguard Worker        exit()
127*387f9dfdSAndroid Build Coastguard Worker
128*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
129*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
130*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink")
131*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rmdir", fn_name="trace_unlink")
132*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rename", fn_name="trace_rename")
133*387f9dfdSAndroid Build Coastguard Worker
134*387f9dfdSAndroid Build Coastguard Worker# header
135*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-7s %-16s %6s %s" % ("TIME", "PID", "COMM", "ACTION", "FILE"))
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker# process event
138*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size):
139*387f9dfdSAndroid Build Coastguard Worker    event = b["events"].event(data)
140*387f9dfdSAndroid Build Coastguard Worker    action_str = action2str(event.action)
141*387f9dfdSAndroid Build Coastguard Worker    file_str = event.fname.decode('utf-8', 'replace')
142*387f9dfdSAndroid Build Coastguard Worker    if action_str == "RENAME":
143*387f9dfdSAndroid Build Coastguard Worker        file_str = "%s > %s" % (file_str, event.fname2.decode('utf-8', 'replace'))
144*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-7d %-16s %6s %s" % (strftime("%H:%M:%S"), event.pid,
145*387f9dfdSAndroid Build Coastguard Worker        event.comm.decode('utf-8', 'replace'), action_str, file_str))
146*387f9dfdSAndroid Build Coastguard Worker
147*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event)
148*387f9dfdSAndroid Build Coastguard Workerwhile 1:
149*387f9dfdSAndroid Build Coastguard Worker    try:
150*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
151*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
152*387f9dfdSAndroid Build Coastguard Worker        exit()
153