Inotify одноразовое решение - PullRequest
       32

Inotify одноразовое решение

1 голос
/ 18 октября 2019

У меня есть программа, которая использует inotify.

Она начинает наблюдать за каталогом создаваемого файла. Когда это происходит, программа читает содержимое, а затем удаляет файл.

Затем пользователь запускает действие, которое снова создает тот же файл. Однако inotify не видит, что файл был создан во второй раз, и файл не обрабатывается.

Код выглядит следующим образом:

fileCreated = false;
m_wd1 = inotify_add_watch( m_fd, "/tmp", IN_CREATE );
if( m_wd1 == -1 )
{
}
else
{
    while( true )
    {
        poll_num = poll( &fds, nfds, -1 );
        if( poll_num == -1 )
        {
            if( errno == EINTR )
                continue;
            syslog( LOG_ERR, "Fail to run poll" );
            result = 1;
        }
        else if( poll_num > 0 && ( fds.revents & POLLIN ) )
        {
            syslog( LOG_DEBUG, "Polling is successful" );
            for( ;; )
            {
                len = read( m_fd, buf, sizeof( buf ) );
                if( len == -1 && errno != EAGAIN )
                {
                    syslog( LOG_ERR, "Failure to read the inotify event" );
                    result = 1;
                    break;
                }
                for( ptr = buf; ptr < buf + len; ptr += sizeof( struct inotify_event ) + event->len )
                {
                    event = (const struct inotify_event *) ptr;
                    if( event->mask & IN_CREATE )
                    {
                        std::string name( event->name );
                        if( name == "scan_results" )
                        {
                            fileCreated = true;
                            break;
                        }
                    }
                }
                if( fileCreated || result )
                    break;
            }
        }
        if( fileCreated )
        {
            std::ifstream log( "scan_results" );
            if( log.rdstate()  & std::ifstream::failbit ) != 0 )
            {
            }
            else
            {
            }
            log.close();
            if( remove( "scan_results" ) != 0 )
            {
                syslog( LOG_ERR, "Failed to remove the file" );
            }
            else
            {
                syslog( LOG_DEBUG, "File deleted successfully" );
            }
        }
        fileCreated = false;

Цикл while () выполняется только один раз,Когда действие происходит во второй раз, я вижу сообщение "Опрос успешен".

Должен ли я добавить IN_MODIFY в качестве маски для inotify?

Если это имеет значение - этот код выполняется внутри std ::нить.

Ответы [ 3 ]

0 голосов
/ 18 октября 2019

Я не вижу точно, что не так с вашим кодом, так как вы не предоставили mcve , но просмотр каталога должен дать вам все подписанные события для каталога, пока вы не перестанете их читать.

Вот пример использования inotify для просмотра каталога ...

#include <iostream>

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

int main(int argc, char *argv[]) {

  const int ifd = inotify_init();
  const int iwd = inotify_add_watch(ifd, "/tmp/inotify", IN_CREATE);

  char buf[4096];

  while (read(ifd, buf, sizeof(buf)) > 0) {

    const struct inotify_event* ie = (const struct inotify_event*) buf;

    std::cout << ie->name << std::endl;
  }

  return 0;
}

(jason@pi) [4868] ~/tmp touch /tmp/inotify/foo
(jason@pi) [4880] ~/tmp touch /tmp/inotify/bar
(jason@pi) [4881] ~/tmp rm /tmp/inotify/foo
(jason@pi) [4882] ~/tmp touch /tmp/inotify/foo

(jason@pi) [4879] ~/tmp ./so
foo
bar
foo
0 голосов
/ 19 октября 2019

Оказывается, что опрос и чтение inotify не являются поточно-ориентированными.

Поэтому, чтобы преодолеть это, я должен был добавить inotify_init() к каждому потоку. Так что теперь у каждого потока есть собственный дескриптор файла inotify. И теперь, похоже, программа работает.

Спасибо всем за чтение и за помощь.

0 голосов
/ 18 октября 2019

Ну, у меня есть ответ, он не короткий, а прямо со страницы man 7 inotify, ссылки на которую приведены выше в комментариях. Ваши два нерешенных вопроса из сужения ваших вопросов в комментариях:

  1. , если я позвоню remove() по файлу - означает ли это, что часы в каталоге для создания файла будут удалены? ;и
  2. если это правда, можете ли вы дать мне какой-нибудь псевдокод для обхода?

Ответ на (1): Да , но часы могут бытьперерабатывается, в результате чего следующий файл / каталог, которому он назначен, потенциально может прочитать ожидающие запросы для файла / каталога, который был закрыт / удален:

When a watch descriptor is removed by calling inotify_rm_watch(2) (or
because a watch file is deleted or the filesystem that contains it is
unmounted), ...

(предостережение о необходимости)

            ... any pending unread events for that watch descriptor
remain available to read.  As watch descriptors are subsequently
allocated with inotify_add_watch(2), the kernel cycles through the
range of possible watch descriptors (0 to INT_MAX) incrementally.
When allocating a free watch descriptor, no check is made to see
whether that watch descriptor number has any pending unread events in
the inotify queue.  Thus, it can happen that a watch descriptor is
reallocated even when pending unread events exist for a previous
incarnation of that watch descriptor number, with the result that the
application might then read those events and interpret them as
belonging to the file associated with the newly recycled watch
descriptor.  In practice, the likelihood of hitting this bug may be
extremely low, since it requires that an application cycle through
INT_MAX watch descriptors, release a watch descriptor while leaving
unread events for that watch descriptor in the queue, and then
recycle that watch descriptor.  For this reason, and because there
have been no reports of the bug occurring in real-world applications,
as of Linux 3.15, no kernel changes have yet been made to eliminate
this possible bug.

(я сомневаюсь, что у вас когда-нибудь будет столько открытых часов)

В ответ на второй вопрос псевдокод будет просто проверять маска для:

IN_DELETE_SELF
        Watched file/directory was itself deleted.  (This event
        also occurs if an object is moved to another filesystem,
        since mv(1) in effect copies the file to the other
        filesystem and then deletes it from the original filesys‐
        tem.)  In addition, an IN_IGNORED event will subsequently
        be generated for the watch descriptor.

Таким образом, вы можете проверить с помощью маски IN_DELETE_SELF или IN_IGNORED, удален ли просматриваемый файл / каталог.

...