1

如果我尝试通过同一进程将某些内容登录到文件中,我的系统就会挂起。

实际上,我想用 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] = '\0';

                    close(metadata->fd);

                    char szLog[256] = {'\0'};
                    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] = {'\0'};
        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);
    }

4

1 回答 1

1

那是一个无限循环!

考虑您收到通知(由于一些外部更改)并希望将其写入同一个文件系统。因此,它会生成另一个通知(由于日志记录)。你想写新的通知。这导致另一个通知。所以这是一个无限循环。

您应该使用另一个已安装的文件系统来记录或仅监视特定路径。

于 2019-11-24T07:22:09.287 回答