目录
c++
下列程序能够监控单文件和目录
NegativeMjark/fanotify: A simple fanotify example for watching events on a filesystem. (github.com)
另外一个
#define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */ #include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/fanotify.h>
#include <unistd.h>
/* Read all available fanotify events from the file descriptor 'fd'. */
static void
handle_events(int fd) {
const struct fanotify_event_metadata * metadata;
struct fanotify_event_metadata buf[200];
ssize_t len;
char path[PATH_MAX];
ssize_t path_len;
char procfd_path[PATH_MAX];
struct fanotify_response response;
/* Loop while events can be read from fanotify file descriptor. */
for (;;) {
/* Read some events. */
len = read(fd, buf, sizeof(buf));
if (len == -1 && errno != EAGAIN) {
perror("read");
exit(EXIT_FAILURE);
}
/* Check if end of available data reached. */
if (len <= 0)
break;
/* Point to the first event in the buffer. */
metadata = buf;
/* Loop over all events in the buffer. */
while (FAN_EVENT_OK(metadata, len)) {
/* Check that run-time and compile-time structures match. */
if (metadata -> vers != FANOTIFY_METADATA_VERSION) {
fprintf(stderr,
"Mismatch of fanotify metadata version.\n");
exit(EXIT_FAILURE);
}
/* metadata->fd contains either FAN_NOFD, indicating a
queue overflow, or a file descriptor (a nonnegative
integer). Here, we simply ignore queue overflow. */
if (metadata -> fd >= 0) {
/* Handle open permission event. */
if (metadata -> mask & FAN_OPEN_PERM) {
printf("FAN_OPEN_PERM: ");
/* Allow file to be opened. */
response.fd = metadata -> fd;
response.response = FAN_DENY;
write(fd, & response, sizeof(response));
}
/* Handle closing of writable file event. */
if (metadata -> mask & FAN_CLOSE_WRITE)
printf("FAN_CLOSE_WRITE: ");
/* Retrieve and print pathname of the accessed file. */
snprintf(procfd_path, sizeof(procfd_path),
"/proc/self/fd/%d", metadata -> fd);
path_len = readlink(procfd_path, path,
sizeof(path) - 1);
if (path_len == -1) {
perror("readlink");
exit(EXIT_FAILURE);
}
path[path_len] = '\0';
printf("File %s\n", path);
/* Close the file descriptor of the event. */
close(metadata -> fd);
}
/* Advance to next event. */
metadata = FAN_EVENT_NEXT(metadata, len);
}
}
}
int
main(int argc, char * argv[]) {
char buf;
int fd, poll_num;
nfds_t nfds;
struct pollfd fds[2];
/* Check mount point is supplied. */
if (argc != 2) {
fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
exit(EXIT_FAILURE);
}
printf("Press enter key to terminate.\n");
/* Create the file descriptor for accessing the fanotify API. */
fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
O_RDONLY | O_LARGEFILE);
if (fd == -1) {
perror("fanotify_init");
exit(EXIT_FAILURE);
}
/* Mark the mount for:
- permission events before opening files
- notification events after closing a write-enabled
file descriptor. */
if (fanotify_mark(fd, FAN_MARK_ADD,
FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
argv[1]) == -1) {
perror("fanotify_mark");
exit(EXIT_FAILURE);
}
/* Prepare for polling. */
nfds = 2;
fds[0].fd = STDIN_FILENO; /* Console input */
fds[0].events = POLLIN;
fds[1].fd = fd; /* Fanotify input */
fds[1].events = POLLIN;
/* This is the loop to wait for incoming events. */
printf("Listening for events.\n");
while (1) {
poll_num = poll(fds, nfds, -1);
if (poll_num == -1) {
if (errno == EINTR) /* Interrupted by a signal */
continue; /* Restart poll() */
perror("poll"); /* Unexpected error */
exit(EXIT_FAILURE);
}
if (poll_num > 0) {
if (fds[0].revents & POLLIN) {
/* Console input is available: empty stdin and quit. */
while (read(STDIN_FILENO, & buf, 1) > 0 && buf != '\n')
continue;
break;
}
if (fds[1].revents & POLLIN) {
/* Fanotify events are available. */
handle_events(fd);
}
}
}
printf("Listening for events stopped.\n");
exit(EXIT_SUCCESS);
}
golang
s3rj1k/go-fanotify: Golang fanotify example (github.com)
package main
import (
"bufio"
"encoding/binary"
"flag"
"fmt"
"golang.org/x/sys/unix"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
)
const markFlags = unix.FAN_MARK_ADD
const markMask = unix.FAN_ONDIR | unix.FAN_MOVED_FROM | unix.FAN_MOVED_TO | unix.FAN_CREATE | unix.FAN_DELETE | unix.FAN_MODIFY
func main() {
var path string
flag.StringVar(&path, "path", "/root/test/kubelet", "")
flag.Parse()
//初始化返回fd
fd, initErr := unix.FanotifyInit(
unix.FAN_CLOEXEC| //在进程执行exec系统调用时关闭此打开的文件描述符
unix.FAN_CLASS_NOTIF| //仅通知
unix.FAN_UNLIMITED_QUEUE| //取消队列限制
unix.FAN_UNLIMITED_MARKS, //取消mark限制
uint(os.O_RDONLY| //只读
unix.O_LARGEFILE| //支持大于2G的文件
unix.O_CLOEXEC, //在进程执行exec系统调用时关闭此打开的文件描述符
))
if initErr != nil {
log.Fatalf("1%v\n", initErr)
}
fmt.Println(path)
markErr := unix.FanotifyMark(
fd, unix.FAN_MARK_ADD, //mark加入
//unix.FAN_MARK_MOUNT, //mark pathname
unix.FAN_CLOSE_WRITE|unix.FAN_EVENT_ON_CHILD,
unix.AT_FDCWD, //如果pathname为空,mark当前目录
path,
)
if markErr!= nil {
log.Fatalf("2%v\n", markErr)
}
for {
event := new(unix.FanotifyEventMetadata)
defer unix.Close(int(event.Fd))
readErr := binary.Read(
bufio.NewReader(os.NewFile(uintptr(fd), "")),
binary.LittleEndian,
event,
)
if readErr != nil {
log.Fatalf("3%v\n", readErr)
}
if event.Vers != unix.FANOTIFY_METADATA_VERSION {
if err := unix.Close(fd); err != nil {
log.Fatalf("%v\n", markErr)
}
log.Fatalf("4%v\n", "versionErr")
}
exepath, exepatherr := os.Readlink(fmt.Sprintf("/proc/%d/exe", event.Pid))
if exepatherr!=nil {
log.Fatalf("9%v\n", exepatherr)
}
cwd, cwderr := os.Readlink(fmt.Sprintf("/proc/%d/cwd", event.Pid))
if cwderr!=nil {
log.Fatalf("9%v\n", cwderr)
}
cmd ,cmderr := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", event.Pid))
if cmderr != nil {
log.Fatalf("7%v\n", cmderr)
}
//stat ,staterr := ioutil.ReadFile(fmt.Sprintf("/proc/%d/status", event.Pid))
//if staterr != nil {
// log.Fatalf("8%v\n", staterr)
//}
if int(event.Pid) == os.Getpid() {
closeErr := unix.Close(int(event.Fd))
if closeErr != nil {
log.Fatalf("5%v\n", closeErr)
}
}
path, pathErr := os.Readlink(filepath.Join("/proc/self/fd", strconv.FormatUint(uint64(event.Fd), 10)))
if pathErr != nil {
log.Fatalf("6%v\n", pathErr)
}
fmt.Printf("CWD: %s EXEPATH: %s CMDLINE: %s PID:%d %s \n",cwd, exepath, string(cmd), event.Pid, path)
//fmt.Println(string(stat))
}
}