监控目录并捕获操作文件的程序信息
监控目录并捕获操作文件的程序信息
/*
* 文件名: 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
作者:wanghongwei
版权声明:本作品遵循<CC BY-NC-ND 4.0>版权协议,商业转载请联系作者获得授权,非商业转载请附上原文出处链接及本声明。