Files
org-roamings/20220106214423-inotify.org

4.1 KiB

Inotify

Présentation

Mécanisme du noyan Linux fournissant des notifications concernant le système de fichiers.

Exemples

C++

#include <cstring>
#include <iostream>
#include <fstream>

#include <sys/stat.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <poll.h>

static void onInotify(int fd)
{
    std::cout << "onInotify(" << fd << ")" << std::endl;
    bool finished = false;
    while (!finished)
    {
        struct inotify_event event;
        const ssize_t        len = read(fd, &event, sizeof(event));
        if (len == -1 && errno != EAGAIN)
        {
            std::cout << "!read " << strerror(errno);
            finished = true;
        }
        // If the nonblocking read() found no events to read, then
        // it returns -1 with errno set to EAGAIN.
        // Nothing to read here, exit the loop.
        if (len <= 0)
        {
            finished = true;
        }
        else
        {
            // Print event type.
            if (event.mask & IN_OPEN)
            {
                std::cout << "IN_OPEN: ";
            }
            if (event.mask & IN_CLOSE_NOWRITE)
            {
                std::cout << "IN_CLOSE_NOWRITE: ";
            }
            if (event.mask & IN_CLOSE_WRITE)
            {
                std::cout << "IN_CLOSE_WRITE: ";
            }
            // Print the name of the file.
            if (event.len)
            {
                std::cout << event.name << std::endl;
            }
            // Print type of filesystem object.
            if (event.mask & IN_ISDIR)
            {
                std::cout << " [directory]" << std::endl;
            }
            else
            {
                std::cout << " [file]" << std::endl;
            }
        }
    }
}

int main(int argc, char** argv)
{
    const std::string filename = "/tmp/dummy";

    // Make sure the filename exists.
    struct stat buffer;
    if (stat(filename.c_str(), &buffer) != 0)
    {
        std::cout << filename << " doesn't exists... create it." << std::endl;
        std::ofstream dummy(filename);
    }

    const int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
    if (fd < 0)
    {
        std::cout << "Unable to init inotify: " << strerror(errno) << std::endl;
        exit(EXIT_FAILURE);
    }

    // Trigger on open and close events.
    const int wd = inotify_add_watch(fd, filename.c_str(), IN_OPEN | IN_CLOSE);
    if (wd == -1)
    {
        std::cout << "Cannot watch '" << filename << "': " << strerror(errno) << std::endl;
        close(fd);
        exit(EXIT_FAILURE);
    }

    // Prepare for pooling.
    const nfds_t  nfds = 2;
    struct pollfd fds[2];
    // Console input
    fds[0].fd     = STDIN_FILENO;
    fds[0].events = POLLIN;
    // Inotify input
    fds[1].fd     = fd;
    fds[1].events = POLLIN;

    // Wait for events and/or terminal input.
    std::cout << "Listening for events." << std::endl;
    bool stop  = false;
    bool error = false;
    while (!stop)
    {
        const int poll_num = poll(fds, nfds, -1);
        if (poll_num == -1)
        {
            if (errno == EINTR)
            {
                continue;
            }
            std::cout << "poll" << std::endl;
            error = stop = true;
        }
        else if (poll_num > 0)
        {
            if (fds[0].revents & POLLIN)
            {
                // Console input is available. Empty stdin and quit.
                char buf;
                while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
                {
                    continue;
                }
                std::cout << "Stopping resquested..." << std::endl;
                break;
            }
            if (fds[1].revents & POLLIN)
            {
                // Inotify events are available.
                onInotify(fd);
            }
        }
    }
    std::cout << "Listening for events stopped." << std::endl;

    /* Close inotify file descriptor. */
    close(fd);

    exit(EXIT_SUCCESS);
}

Références

  • inotify(7) — Linux manual page]]