fanotify:是否可以通过同一进程监视整个文件系统并在监视的文件系统中写入少量 logs/config?
fanotify: is it possible to monitor whole filesystem and write few logs/config in monitored filesystem by same process?
如果我尝试通过同一进程在文件中记录某些内容,我的系统会挂起。
实际上我想用 fanotify 监视整个文件系统 ("/") 并且还想记录错误以防 "/tmp" 中出现任何错误,但它会导致系统挂起。
请查找以下代码:
#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>
#include <string.h>
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, (void *) &buf, sizeof(buf));
if (len == -1 && errno != EAGAIN)
{
system("echo 'Read error' >> /tmp/fanotify.txt");
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)
{
system("echo 'Mismatch of fanotify metadata version' >> /tmp/fanotify.txt");
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)
{
//Allow file to be opened
response.fd = metadata->fd;
response.response = FAN_ALLOW;
write(fd, &response,sizeof(struct fanotify_response));
system("echo 'FAN_OPEN_PERM:' >> /tmp/fanotify.txt");
}
//Handle closing of writable file event
if (metadata->mask & FAN_CLOSE_WRITE)
{
system("echo 'FAN_CLOSE_WRITE:' >> /tmp/fanotify.txt");
}
//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)
{
system("echo 'readlink error' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
path[path_len] = '[=11=]';
close(metadata->fd);
char szLog[256] = {'[=11=]'};
snprintf(szLog, sizeof(szLog), "echo 'File %s' >> /tmp/fanotify.txt", path);
system(szLog);
//Close the file descriptor of the event
}
//Advance to next event
metadata = FAN_EVENT_NEXT(metadata, len);
}
}
}
这是我调用的主函数 handle_events
int
main(int argc, char *argv[])
{
char buf;
int fd, poll_num;
nfds_t nfds;
struct pollfd fds[2];
char szMountCommand[1024] = {'[=12=]'};
uint64_t uiMask = FAN_OPEN_PERM | FAN_CLOSE_WRITE | FAN_EVENT_ON_CHILD;
//Check mount point is supplied
if (argc != 2) {
fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
exit(EXIT_FAILURE);
}
system("echo 'Press enter key to terminate' >> /tmp/fanotify.txt");
//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) {
system("echo 'fanotify_init failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
/* Mark the mount for:
- permission events before opening files
- notification events after closing a write-enabled
file descriptor */
snprintf(szMountCommand, sizeof(szMountCommand), "mount --bind %s %s", argv[1], argv[1]);
system(szMountCommand);
if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, uiMask, 0, argv[1]) == -1)
{
system("echo 'fanotify_mark failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
system("echo 'Monitoring:' >> /tmp/fanotify.txt");
//Prepare for polling
nfds = 2;
//Console input
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
//Fanotify input
fds[1].fd = fd;
fds[1].events = POLLIN;
//This is the loop to wait for incoming events
system("echo 'Listening for events:' >> /tmp/fanotify.txt");
while (1) {
poll_num = poll(fds, nfds, -1);
if (poll_num == -1) {
if (errno == EINTR) //Interrupted by a signal
continue; // Restart poll()
system("echo 'poll failed.' >> /tmp/fanotify.txt");
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);
}
}
}
system("echo 'Listening for events stopped.' >> /tmp/fanotify.txt");
exit(EXIT_SUCCESS);
}
这是一个无限循环!
假设您收到通知(由于某些外部更改)并希望将其写入同一文件系统。因此,它会生成另一个通知(由于日志记录)。你想写新的通知。这会导致另一个通知。所以这是一个无限循环。
您应该使用另一个已安装的文件系统来记录或仅监视特定路径。
如果我尝试通过同一进程在文件中记录某些内容,我的系统会挂起。
实际上我想用 fanotify 监视整个文件系统 ("/") 并且还想记录错误以防 "/tmp" 中出现任何错误,但它会导致系统挂起。
请查找以下代码:
#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>
#include <string.h>
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, (void *) &buf, sizeof(buf));
if (len == -1 && errno != EAGAIN)
{
system("echo 'Read error' >> /tmp/fanotify.txt");
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)
{
system("echo 'Mismatch of fanotify metadata version' >> /tmp/fanotify.txt");
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)
{
//Allow file to be opened
response.fd = metadata->fd;
response.response = FAN_ALLOW;
write(fd, &response,sizeof(struct fanotify_response));
system("echo 'FAN_OPEN_PERM:' >> /tmp/fanotify.txt");
}
//Handle closing of writable file event
if (metadata->mask & FAN_CLOSE_WRITE)
{
system("echo 'FAN_CLOSE_WRITE:' >> /tmp/fanotify.txt");
}
//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)
{
system("echo 'readlink error' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
path[path_len] = '[=11=]';
close(metadata->fd);
char szLog[256] = {'[=11=]'};
snprintf(szLog, sizeof(szLog), "echo 'File %s' >> /tmp/fanotify.txt", path);
system(szLog);
//Close the file descriptor of the event
}
//Advance to next event
metadata = FAN_EVENT_NEXT(metadata, len);
}
}
}
这是我调用的主函数 handle_events
int
main(int argc, char *argv[])
{
char buf;
int fd, poll_num;
nfds_t nfds;
struct pollfd fds[2];
char szMountCommand[1024] = {'[=12=]'};
uint64_t uiMask = FAN_OPEN_PERM | FAN_CLOSE_WRITE | FAN_EVENT_ON_CHILD;
//Check mount point is supplied
if (argc != 2) {
fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
exit(EXIT_FAILURE);
}
system("echo 'Press enter key to terminate' >> /tmp/fanotify.txt");
//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) {
system("echo 'fanotify_init failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
/* Mark the mount for:
- permission events before opening files
- notification events after closing a write-enabled
file descriptor */
snprintf(szMountCommand, sizeof(szMountCommand), "mount --bind %s %s", argv[1], argv[1]);
system(szMountCommand);
if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, uiMask, 0, argv[1]) == -1)
{
system("echo 'fanotify_mark failed.' >> /tmp/fanotify.txt");
exit(EXIT_FAILURE);
}
system("echo 'Monitoring:' >> /tmp/fanotify.txt");
//Prepare for polling
nfds = 2;
//Console input
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
//Fanotify input
fds[1].fd = fd;
fds[1].events = POLLIN;
//This is the loop to wait for incoming events
system("echo 'Listening for events:' >> /tmp/fanotify.txt");
while (1) {
poll_num = poll(fds, nfds, -1);
if (poll_num == -1) {
if (errno == EINTR) //Interrupted by a signal
continue; // Restart poll()
system("echo 'poll failed.' >> /tmp/fanotify.txt");
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);
}
}
}
system("echo 'Listening for events stopped.' >> /tmp/fanotify.txt");
exit(EXIT_SUCCESS);
}
这是一个无限循环!
假设您收到通知(由于某些外部更改)并希望将其写入同一文件系统。因此,它会生成另一个通知(由于日志记录)。你想写新的通知。这会导致另一个通知。所以这是一个无限循环。
您应该使用另一个已安装的文件系统来记录或仅监视特定路径。