123 lines
4.7 KiB
C
123 lines
4.7 KiB
C
// gcc -O2 -Wall -Wextra -o main main.c
|
|
|
|
#define _GNU_SOURCE
|
|
#include <sys/fanotify.h> // <-- прототипы fanotify_*
|
|
#include <sys/epoll.h>
|
|
#include <sys/uio.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <limits.h> // PATH_MAX
|
|
|
|
#ifndef AT_FDCWD
|
|
# include <fcntl.h>
|
|
#endif
|
|
|
|
/* Настройки из твоего D-кода */
|
|
#define INIT_FLAGS (FAN_CLASS_PRE_CONTENT | FAN_CLOEXEC | FAN_NONBLOCK)
|
|
#define EVENT_FLAGS (O_RDONLY | O_LARGEFILE | O_CLOEXEC)
|
|
#define BASE_FLAGS (FAN_MARK_ADD)
|
|
#define PERM_MASK (FAN_OPEN_PERM | FAN_ACCESS_PERM | FAN_OPEN_EXEC_PERM | FAN_OPEN | FAN_CLOSE_WRITE)
|
|
#define BUF_SZ (64 * 1024)
|
|
|
|
/* Простой лог */
|
|
static void log_line(const char *s) {
|
|
struct iovec v[2];
|
|
static const char nl = '\n';
|
|
v[0].iov_base = (void*)s; v[0].iov_len = strlen(s);
|
|
v[1].iov_base = (void*)&nl; v[1].iov_len = 1;
|
|
writev(STDERR_FILENO, v, 2);
|
|
}
|
|
|
|
static ssize_t fd_path(int fd, char *buf, size_t cap) {
|
|
char linkpath[64];
|
|
int m = snprintf(linkpath, sizeof(linkpath), "/proc/self/fd/%d", fd);
|
|
if (m <= 0 || (size_t)m >= sizeof(linkpath)) return -1;
|
|
ssize_t r = readlink(linkpath, buf, cap - 1);
|
|
if (r >= 0) buf[r] = '\0';
|
|
return r;
|
|
}
|
|
|
|
int main(void) {
|
|
int fan = fanotify_init(INIT_FLAGS, EVENT_FLAGS);
|
|
if (fan == -1) { perror("fanotify_init"); return 1; }
|
|
|
|
/* метим /tmp и /home как файловые системы */
|
|
if (fanotify_mark(fan, BASE_FLAGS | FAN_MARK_FILESYSTEM, PERM_MASK, AT_FDCWD, "/tmp") == -1) {
|
|
perror("fanotify_mark(/tmp)"); return 1;
|
|
}
|
|
if (fanotify_mark(fan, BASE_FLAGS | FAN_MARK_FILESYSTEM, PERM_MASK, AT_FDCWD, "/home") == -1) {
|
|
perror("fanotify_mark(/home)"); return 1;
|
|
}
|
|
|
|
int ep = epoll_create1(EPOLL_CLOEXEC);
|
|
if (ep == -1) { perror("epoll_create1"); return 1; }
|
|
|
|
struct epoll_event ev = { .events = EPOLLIN | EPOLLONESHOT };
|
|
ev.data.u64 = 1; /* тег */
|
|
if (epoll_ctl(ep, EPOLL_CTL_ADD, fan, &ev) == -1) { perror("epoll_ctl ADD"); return 1; }
|
|
|
|
char *buf = malloc(BUF_SZ);
|
|
if (!buf) { perror("malloc"); return 1; }
|
|
|
|
log_line("fanomon: started (watching /tmp and /home)");
|
|
|
|
for (;;) {
|
|
struct epoll_event out;
|
|
int n = epoll_wait(ep, &out, 1, -1);
|
|
if (n == -1) { if (errno == EINTR) continue; perror("epoll_wait"); break; }
|
|
|
|
if ((out.events & EPOLLIN) && out.data.u64 == 1) {
|
|
for (;;) {
|
|
ssize_t len = read(fan, buf, BUF_SZ);
|
|
if (len == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) break;
|
|
if (len <= 0) break;
|
|
|
|
struct fanotify_event_metadata *meta;
|
|
for (meta = (struct fanotify_event_metadata*)buf;
|
|
FAN_EVENT_OK(meta, len);
|
|
meta = FAN_EVENT_NEXT(meta, len)) {
|
|
|
|
if (meta->vers != FANOTIFY_METADATA_VERSION) { log_line("metadata version mismatch"); continue; }
|
|
if (meta->mask & FAN_Q_OVERFLOW) { log_line("queue overflow"); continue; }
|
|
|
|
/* Быстро отвечаем на PERM-события */
|
|
if (meta->mask & (FAN_OPEN_PERM | FAN_ACCESS_PERM | FAN_OPEN_EXEC_PERM)) {
|
|
struct fanotify_response resp = { .fd = meta->fd, .response = FAN_ALLOW };
|
|
if (write(fan, &resp, sizeof(resp)) == -1) perror("fanotify_response");
|
|
}
|
|
|
|
/* Лёгкий лог пути (после ответа) */
|
|
if (meta->fd >= 0) {
|
|
char path[PATH_MAX];
|
|
if (fd_path(meta->fd, path, sizeof(path)) >= 0) {
|
|
char line[PATH_MAX + 16];
|
|
const char *tag =
|
|
(meta->mask & FAN_OPEN) ? "OPEN " :
|
|
(meta->mask & FAN_CLOSE_WRITE) ? "CLOSEW" :
|
|
(meta->mask & FAN_ACCESS_PERM) ? "APERM " :
|
|
(meta->mask & FAN_OPEN_PERM) ? "OPERM " :
|
|
(meta->mask & FAN_OPEN_EXEC_PERM) ? "XPERM " : "EVENT ";
|
|
snprintf(line, sizeof(line), "%s %s", tag, path);
|
|
log_line(line);
|
|
}
|
|
close(meta->fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Реарм ONE_SHOT */
|
|
ev.events = EPOLLIN | EPOLLONESHOT;
|
|
ev.data.u64 = 1;
|
|
if (epoll_ctl(ep, EPOLL_CTL_MOD, fan, &ev) == -1) { perror("epoll_ctl MOD"); break; }
|
|
}
|
|
}
|
|
|
|
free(buf);
|
|
close(ep);
|
|
close(fan);
|
|
return 0;
|
|
}
|