监控目录并捕获操作文件的程序信息

监控目录并捕获操作文件的程序信息

/*
 * 文件名: file_monitor.c
 * 作者: wanghongwei
 * 日期: 2024年9月28日
 * 版本: 1.0
 * 描述: 监控目录并捕获操作文件的程序信息
 * 使用方式: ./file_monitor <directory_to_monitor>
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/inotify.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <sys/select.h>

#define EVENT_SIZE  (sizeof(struct inotify_event))
#define BUF_LEN     (1024 * (EVENT_SIZE + 16))
#define LOG_FILE_PATH "file_monitor.log"
#define COMMAND_FORMAT "lsof %s/%s 2>/dev/null | tail -n 1 | awk '{print $1, $2, $3}'"

int running = 1;
FILE *logfile;

// 日志记录函数
void log_event(const char *event, const char *file_name, const char *directory) {
    char buffer[1024];
    char user[64] = "unknown";
    char pid[16] = "unknown";
    char command[256] = "unknown";

    // 构造命令并获取文件信息
    snprintf(buffer, sizeof(buffer), COMMAND_FORMAT, directory, file_name);
    FILE *cmd = popen(buffer, "r");
    if (cmd && fgets(buffer, sizeof(buffer), cmd) != NULL) {
        // 解析文件信息
        int fields_read = sscanf(buffer, "%255s %15s %63s", command, pid, user);
        // 移除换行符
        user[strcspn(user, "\n")] = 0;
        pid[strcspn(pid, "\n")] = 0;
        command[strcspn(command, "\n")] = 0;

        // 检查是否成功读取了所有字段
        if (fields_read != 3) {
            // 如果没有读取到所有字段,可以选择记录错误或保持原样
        }
    }
    if (cmd) pclose(cmd);

	// 记录日志
    if (logfile) {
        time_t now = time(NULL);
        char time_str[64]; // 使用固定的时间字符串大小
        strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&now));

        fprintf(logfile, "[%s] [USER: %s, PID: %s, COMMAND: %s] %s: %s\n",
                time_str, user, pid, command, file_name, event);
        fflush(logfile); // 刷新缓冲区
    }
}

// 信号处理函数
void signal_handler(int signo) {
    if (signo == SIGINT || signo == SIGTERM) {
        running = 0;
    }
}

// 主函数
int main(int argc, char *argv[]) {
    // 参数检查
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <directory_to_monitor>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int fd, wd;
    char buffer[BUF_LEN];

    // 打开日志文件
    logfile = fopen(LOG_FILE_PATH, "a");
    if (!logfile) {
        perror("Failed to open log file");
        exit(EXIT_FAILURE);
    }

    // 设置信号处理
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);

    // 初始化inotify
    fd = inotify_init();
    if (fd < 0) {
        perror("inotify_init");
        fclose(logfile);
        exit(EXIT_FAILURE);
    }

    // 添加目录监视
    wd = inotify_add_watch(fd, argv[1], IN_CREATE | IN_MODIFY | IN_DELETE | IN_MOVE | IN_MOVE_SELF);
    if (wd == -1) {
        perror("inotify_add_watch");
        fclose(logfile);
        close(fd);
        exit(EXIT_FAILURE);
    }

    printf("Monitoring directory: %s\n", argv[1]);

    // 监视事件循环
    while (running) {
        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(fd, &read_fds);

        // 使用 select 等待事件
        int retval = select(fd + 1, &read_fds, NULL, NULL, NULL);
        if (retval < 0) {
            perror("select");
            break;
        }

        if (FD_ISSET(fd, &read_fds)) {
            int length = read(fd, buffer, BUF_LEN);
            if (length < 0) {
                perror("read");
                break;
            }

            // 处理所有事件
            int i = 0;
            while (i < length) {
                struct inotify_event *event = (struct inotify_event *)&buffer[i];

                if (event->len) {
				    // 根据事件类型记录日志
                    if (event->mask & IN_CREATE) {
                        log_event("File created", event->name, argv[1]);
                    } else if (event->mask & IN_MODIFY) {
                        log_event("File modified", event->name, argv[1]);
                    } else if (event->mask & IN_DELETE) {
                        log_event("File deleted", event->name, argv[1]);
                    } else if (event->mask & IN_MOVE) {
                        log_event("File moved", event->name, argv[1]);
                    } else if (event->mask & IN_MOVE_SELF) {
                        log_event("Directory moved", event->name, argv[1]);
                    }
                }
                i += EVENT_SIZE + event->len;
            }
        }
    }

    // 清理资源
    inotify_rm_watch(fd, wd);
    close(fd);
    fclose(logfile);
    printf("Exiting gracefully.\n");
    return 0;
}

使用

# 编译程序
gcc -o file_monitor file_monitor.c
# 运行程序
nohup ./file_monitor /var/log/ &
# 查看进程
ps -ef | grep file_monitor | grep -v grep
# 停止进程
ps -ef | grep file_monitor | grep -v grep | awk '{print $2}' | xargs kill
posted @ 2024-09-28 12:18  wanghongwei-dev  阅读(4)  评论(0编辑  收藏  举报