fanotify用例

文章展示了使用C++和Golang通过fanotifyAPI来监控文件系统事件的代码示例,包括文件打开权限和可写文件关闭事件的处理。在C++示例中,程序读取fanotify事件并响应,而在Golang版本中,程序同样监听事件并获取进程信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

c++ 

golang


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))


	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信安成长日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值