From d500c062da155e96b603b3e2bcfbd25f4d1f55ef Mon Sep 17 00:00:00 2001
From: shangfan <45649554+sf1999817@users.noreply.github.com>
Date: Tue, 7 Jan 2025 18:31:32 +0800
Subject: [PATCH] reset open (#954)

Signed-off-by: shangfan <45649554+sf1999817@users.noreply.github.com>
---
 .../src/backend/fs/fs_watcher/bpf/open.bpf.c  | 111 ++++++++++------
 .../fs/fs_watcher/include/fs_watcher.h        |  11 +-
 .../backend/fs/fs_watcher/src/fs_watcher.c    | 121 +++++++++---------
 3 files changed, 140 insertions(+), 103 deletions(-)

diff --git a/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c b/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c
index 5824bb774..60e11158a 100644
--- a/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c
+++ b/MagicEyes/src/backend/fs/fs_watcher/bpf/open.bpf.c
@@ -1,18 +1,19 @@
-#define BPF_NO_GLOBAL_DATA
 #include <vmlinux.h>
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
 #include <bpf/bpf_core_read.h>
 #include "fs_watcher.h"
 
-#define TASK_COMM_LEN 100
-#define path_size 256
+char LICENSE[] SEC("license") = "GPL";
+
+#define O_CREAT  0x0200  // 手动定义 O_CREAT 标志的常量值
+#define O_WRONLY    01  /* open for writing only */
 
 struct {
 	__uint(type, BPF_MAP_TYPE_HASH);
 	__uint(max_entries, 1024);
 	__type(key, pid_t);
-	__type(value, char[TASK_COMM_LEN]);
+	__type(value, struct event_open);
 } data SEC(".maps");
 
 struct {
@@ -20,52 +21,84 @@ struct {
 	__uint(max_entries, 256 * 1024);
 } rb SEC(".maps"); // 环形缓冲区
 
-
 SEC("tracepoint/syscalls/sys_enter_openat")
 int do_syscall_trace(struct trace_event_raw_sys_enter *ctx)
 {
-	struct event_open *e;
-    char comm[TASK_COMM_LEN];
-    bpf_get_current_comm(&comm,sizeof(comm));
-	e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
-	if (!e)
-		return 0;
+	struct event_open e = {};
+	pid_t pid = bpf_get_current_pid_tgid() >> 32;
+	e.pid = pid;
+	e.dfd = ctx->args[0];// 目录文件描述符
+	bpf_probe_read_user_str(e.filename, sizeof(e.filename), (const char *)ctx->args[1]);  // 文件路径
+ 	e.flags = ctx->args[2];  // 打开标志
+	
+	// 如果包含 O_CREAT 标志,则标记为文件创建
+	if (e.flags & O_CREAT || (e.flags & O_WRONLY) ) {
+        e.is_created = true;
+    } else {
+        e.is_created = false;
+    }
+
+	bpf_map_update_elem(&data,&pid,&e,BPF_ANY);
+	return 0;
+}
 
-	char filename[path_size];
-	struct task_struct *task = (struct task_struct *)bpf_get_current_task(),
-			   *real_parent;
-	if (task == NULL) {
-		bpf_printk("task\n");
-		bpf_ringbuf_discard(e, 0);
+// 跟踪文件描述符分配过程
+SEC("kprobe/get_unused_fd_flags")
+int kprobe_get_unused_fd_flags(struct pt_regs *ctx){
+	pid_t pid = bpf_get_current_pid_tgid() >> 32;
+	struct event_open *e = bpf_map_lookup_elem(&data,&pid);
+	if(!e){
+		bpf_printk("get_unused_fd_flags is failed to found fd\n");
 		return 0;
 	}
-	int pid = bpf_get_current_pid_tgid() >> 32, tgid;
-
-    bpf_map_update_elem(&data, &pid, &comm, BPF_ANY);
-
-	int ppid = BPF_CORE_READ(task, real_parent, tgid);
 
-	bpf_probe_read_str(e->path_name_, sizeof(e->path_name_),
-			   (void *)(ctx->args[1]));
+	//获取分配的文件描述符
+    e->fd = PT_REGS_RC(ctx);
 
-	bpf_printk("path name: %s,pid:%d,ppid:%d\n", e->path_name_, pid, ppid);
+	bpf_map_update_elem(&data,&pid,e,BPF_ANY);
+	return 0;
+}
 
-	struct fdtable *fdt = BPF_CORE_READ(task, files, fdt);
-	if (fdt == NULL) {
-		bpf_printk("fdt\n");
-		bpf_ringbuf_discard(e, 0);
+// 跟踪 openat 系统调用的退出
+SEC("tracepoint/syscalls/sys_exit_openat")
+int do_syscall_exit(struct trace_event_raw_sys_exit *ctx)
+{
+	pid_t pid = bpf_get_current_pid_tgid() >> 32;
+	struct event_open *e = bpf_map_lookup_elem(&data,&pid);
+	if(!e){
+		bpf_printk("sys_exit_openat is failed to found fd\n");
 		return 0;
 	}
 
-	unsigned int i = 0, count = 0, n = BPF_CORE_READ(fdt, max_fds);
-	bpf_printk("n:%d\n", n);
-
-	e->n_ = n;
-	e->pid_ = pid;
-
-	bpf_ringbuf_submit(e, 0);
-
+	e->ret = ctx->ret;
+
+	 // 分配 ringbuf 空间
+    struct event_open *new_e = bpf_ringbuf_reserve(&rb, sizeof(*new_e), 0);
+    if (!new_e) {
+        return 0;  // 如果分配失败,提前返回
+    }
+
+	//复制数据
+	new_e->dfd = e->dfd;
+	new_e->flags = e->flags;
+	new_e->fd = e->fd;
+	new_e->ret =e->ret;
+	new_e->is_created = e->is_created;
+	new_e->pid = e->pid;
+
+	// 手动读取文件路径,确保不超过最大长度,并添加 '\0' 结束符
+    int filename_len = 0;
+    while (filename_len < sizeof(new_e->filename) - 1) {
+        char c = 0;
+        // 读取路径中的每个字符
+        bpf_probe_read(&c, sizeof(c), e->filename + filename_len);
+        if (c == '\0') break;  // 如果遇到 null 字符就停止读取
+        new_e->filename[filename_len++] = c;
+    }
+    // 确保字符串以 '\0' 结束
+    new_e->filename[filename_len] = '\0';
+	bpf_printk("Opening file: %s, pid: %d, flags: %d\n", new_e->filename, pid, e->flags);
+
+	bpf_ringbuf_submit(new_e, 0);
 	return 0;
 }
-
-char LICENSE[] SEC("license") = "GPL";
\ No newline at end of file
diff --git a/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h b/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h
index 8c9cc1cdb..ed049ab13 100644
--- a/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h
+++ b/MagicEyes/src/backend/fs/fs_watcher/include/fs_watcher.h
@@ -6,10 +6,13 @@
 #define TASK_COMM_LEN 16
 
 struct event_open {
-	int pid_;
-	char path_name_[path_size];
-	int n_;
-    char comm[TASK_COMM_LEN];
+    pid_t pid;
+    int dfd;
+    char filename[path_size];
+    int flags;
+    int fd;    // 文件描述符
+    int ret;   // 系统调用返回值
+    bool is_created;  // 标记文件是否创建
 };
 
 /*read*/
diff --git a/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c b/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c
index beef03c45..9a6ef6c85 100644
--- a/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c
+++ b/MagicEyes/src/backend/fs/fs_watcher/src/fs_watcher.c
@@ -5,6 +5,7 @@
 #include <time.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <errno.h>
 #include <string.h>
 #include <sys/resource.h>
 #include <bpf/libbpf.h>
@@ -14,6 +15,7 @@
 #include <inttypes.h>
 #include <linux/fs.h>
 #include <errno.h>
+#include <fcntl.h>  // 包含文件打开标志宏
 #include <argp.h>
 #include "fs/fs_watcher/open.skel.h"
 #include "fs/fs_watcher/read.skel.h"
@@ -105,7 +107,6 @@ static struct env{
     bool disk_io_visit;
     bool block_rq_issue;
     bool CacheTrack;
-    pid_t pid;
 }env = {
     .open = false,
     .read = false,
@@ -113,7 +114,6 @@ static struct env{
     .disk_io_visit = false,
     .block_rq_issue = false,
     .CacheTrack = false,
-    .pid = -1,
 };
 
 static const struct argp_option opts[] = {
@@ -123,7 +123,6 @@ static const struct argp_option opts[] = {
     {"disk_io_visit", 'd', 0, 0, "Print disk I/O visit report"},
     {"block_rq_issue", 'b', 0, 0, "Print block I/O request submission events. Reports when block I/O requests are submitted to device drivers."},
     {"CacheTrack", 't' , 0 ,0 , "WriteBack dirty lagency and other information"},
-    {"pid", 'p', "PID", 0, "Specify pid number when report weite. Only support for write report now"},
     {0} // 结束标记,用于指示选项列表的结束
 };
 
@@ -142,19 +141,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) {
         env.block_rq_issue = true;break;
         case 't':
         env.CacheTrack = true;break;
-        case 'p':
-        if (arg) {
-            env.pid = atoi(arg);
-            if (env.pid <= 0) {
-                fprintf(stderr, "Invalid PID value: %s\n", arg);
-                argp_usage(state);
-            }
-        } else {
-            fprintf(stderr, "-p option requires an argument\n");
-            argp_usage(state);
-        }
-        break;
-        default:
+        default: 
             return ARGP_ERR_UNKNOWN;
     }
     return 0;
@@ -244,38 +231,65 @@ int main(int argc,char **argv){
     }
 }
 
+const char* flags_to_str(int flags) {
+    static char str[256];
+    str[0] = '\0';  // 清空字符串
+    
+    if (flags & O_RDONLY)   strcat(str, "O_RDONLY ");
+    if (flags & O_WRONLY)   strcat(str, "O_WRONLY ");
+    if (flags & O_RDWR)     strcat(str, "O_RDWR ");
+    if (flags & O_CREAT)    strcat(str, "O_CREAT ");
+    if (flags & O_EXCL)     strcat(str, "O_EXCL ");
+    if (flags & O_TRUNC)    strcat(str, "O_TRUNC ");
+    if (flags & O_APPEND)   strcat(str, "O_APPEND ");
+    if (flags & O_NOFOLLOW) strcat(str, "O_NOFOLLOW ");
+    if (flags & O_CLOEXEC)  strcat(str, "O_CLOEXEC ");
+    if (flags & O_NONBLOCK) strcat(str, "O_NONBLOCK ");
+    if (flags & O_SYNC)     strcat(str, "O_SYNC ");
+    if (flags & O_DSYNC)    strcat(str, "O_DSYNC ");
+    if (flags & O_RSYNC)    strcat(str, "O_RSYNC ");
+    if (flags & O_DIRECTORY) strcat(str, "O_DIRECTORY ");
+    
+    // 条件编译部分:如果系统定义了 O_NOATIME 和 O_PATH
+#ifdef O_NOATIME
+    if (flags & O_NOATIME)  strcat(str, "O_NOATIME ");
+#endif
+
+#ifdef O_PATH
+    if (flags & O_PATH)     strcat(str, "O_PATH ");
+#endif
+    
+    // 如果没有匹配到标志,返回 "Unknown"
+    if (str[0] == '\0') {
+        return "Unknown";
+    }
+    
+    return str;
+}
+
 static int handle_event_open(void *ctx, void *data, size_t data_sz)
 {
-	struct event_open *e = (struct event_open *)data;
-	char *filename = strrchr(e->path_name_, '/');
-	++filename;
-
-	char fd_path[path_size];
-	char actual_path[path_size];
-    char comm[TASK_COMM_LEN];
-	int i = 0;
-    int map_fd = *(int *)ctx;//传递map得文件描述符
-
-
-	for (; i < e->n_; ++i) {
-		snprintf(fd_path, sizeof(fd_path), "/proc/%d/fd/%d", e->pid_,
-			 i);
-		ssize_t len =
-			readlink(fd_path, actual_path, sizeof(actual_path) - 1);
-		if (len != -1) {
-			actual_path[len] = '\0';
-			int result = strcmp(e->path_name_, actual_path);
-			if (result == 0) {
-                if(bpf_map_lookup_elem(map_fd,&e->pid_,&comm)==0){
-                    printf("%-60s %-8d %-8d %-8s\n",
-				       e->path_name_, i,e->pid_,comm);
-                }else{
-                    fprintf(stderr, "Failed to lookup value for key %d\n", e->pid_);
-                    }
-
-			    }
-		    }
-	    }
+    const struct event_open *e = data;
+	struct tm *tm;
+	char ts[32];
+	time_t t;
+
+	time(&t);
+	tm = localtime(&t);
+	strftime(ts, sizeof(ts), "%H:%M:%S", tm);
+    const char *ret_str;
+    // 如果返回值是负数,则是错误码,使用 strerror
+    if (e->ret < 0) {
+        ret_str = strerror(-e->ret);  // 负数表示错误码
+    } else {
+        // 正数表示文件描述符,直接打印文件描述符
+        ret_str = "Success";  // 如果是文件描述符,表示成功
+    }
+
+    const char *flags_str = flags_to_str(e->flags);
+
+    printf("%-8s %-8d %-8d %-100s %-8s %-8d %-8s %-8s\n", 
+           ts, e->dfd, e->pid,e->filename, flags_str, e->fd, ret_str, e->is_created ? "true" : "false");
 	return 0;
 }
 
@@ -352,7 +366,7 @@ static int process_open(struct open_bpf *skel_open){
 
     LOAD_AND_ATTACH_SKELETON_MAP(skel_open,open);
 
-    printf("%-60s %-8s %-8s %-8s\n","filenamename","fd","pid","comm");
+    printf("%-8s %-8s %-8s %-100s %-8s %-8s %-8s %-8s\n", "TIME","dfd","PID", "filename", "flags", "fd", "ret", "is_created");
     POLL_RING_BUFFER(rb, 1000, err);
 
 open_cleanup:
@@ -381,22 +395,9 @@ static int process_read(struct read_bpf *skel_read){
 static int process_write(struct write_bpf *skel_write){
     int err;
     struct ring_buffer *rb;
-    int arg_index = 0;
-
-    struct dist_args d_args = {-1};
-
 
     LOAD_AND_ATTACH_SKELETON(skel_write,write);
 
-    d_args.pid = env.pid;
-    struct bpf_map *arg_map = bpf_object__find_map_by_name((const struct bpf_object *)*(skel_write->skeleton->obj), "args_map");
-    err = bpf_map__update_elem(arg_map, &arg_index, sizeof(arg_index), &d_args, sizeof(d_args), BPF_ANY);
-
-    if (err < 0) {
-        fprintf(stderr, "ERROR: failed to update args map\n");
-        goto write_cleanup;
-    }
-
     printf("%-8s    %-8s    %-8s    %-8s    %-8s\n","ds","inode_number","pid","real_count","count");
     POLL_RING_BUFFER(rb, 1000, err);