Мониторинг файлов в папке linux

Best way to monitor file system changes in linux

I’m looking at building a file system sync utility that monitors file system activity, but it appears that some of the file system monitoring features in the linux kernel are obsolete or not fully featured. What my research as found dnotify came first with notification has the features of notifying for delete,modify,access,attribs,create,move can determine file descriptor, however is now out dated by inotify and fanotify inotify came out second with notification has the features of notifying access, modify, attrib, close, move, delete, create, etc however it does not give you a file descriptor or process and will be outdated by fanotify fanotify is the latest which informs of access, modify, close, but does not inform of delete or attribs, but does provide file descriptor I need a way of determining the process (e.g. from fd) and things like delete, modify, attribs, etc in order to sync everything, any suggestions? Unfortunately dnotify seems the best but most out-dated

3 Answers 3

You should use a library instead of inotify and friends — something like FAM or Gamin (it’s the same API for both). This will make your program portable to other Unixes.

There’s a good lib providing file descriptors or process with inotify. It has his own C API and the inotifywatch util (good for scripts), all in inotify-tools package.

I strongly disagree that fanotify will outdate inotify.

FAM and gamin are very good server/client options. Both of them use inotify as first option over the outdated dnotify and polls. I prefer gamin.

Источник

Отслеживание изменений в директории с помощью Inotify

Столкнулся с задачей, где необходимо было отслеживать в ОС Linux изменение файла в директории на чистом С++. Так как чистый С++, QtCreator с его QFileSystemWatcher сразу отпадал, из-за того что необходимо было подключать QObject. В итоге решил пользоваться линуксовой функцией Inotify.

Inotify позволяет через файловый дескриптор наблюдать за директорией или файлом, отслеживая их события. Все события ввода-вывода ссылаются на открытый файл с использованием файлового дескриптора. Файловый дескриптор представляет собой целое число типа int.

Итак, работа типичной программы мониторинга организована следующим образом:

  1. С помощью inotify_init() открываем файловый дескриптор
  2. Добавляем одно или несколько событий для наблюдений
  3. Ожидаем добавленное событие
  4. Обрабатываем события, после чего снова начинаем ждать в бесконечном цикле
  5. При отсутствии активных наблюдений или при получении определенного сигнала файловый дескриптор закрывается, выполняется очистка и программа завершает работу.

inotify_init() инициализирует новый экземпляр inotify и возвращает файловый дескриптор. На данный момент используется более новый системный вызов inotify_init1(int flags). Если используется флаг 0 или флаги вообще не указаны, то
inotify_init1(int flags) будет работать как inotify_init(). Так же используются другие флаги:
IN_NONBLOCK – устанавливает файловый дескриптор в неблокирующий режим.
IN_CLOEXEC – устанавливает флаг закрытия при выполнении.

Читайте также:  Linux include config h

Системный вызов inotify_and_watch(int fd, const char *pathname, uint32_t mask) добавляет новый элемент в список наблюдения для объекта inotify, ссылка на который осуществляется с помощью файлового дескриптора. Аргумент mask добавляет тип событий, которые должны мониториться файловым дескриптором. Рассмотрим флаги событий, за которыми можно наблюдать:

IN_ACCESS — Файл был прочитан (read())
IN_ATTRIB — Метаданные файла изменены
IN_CLOSE_WRITE — Файл был открыт для записи, а потом закрыт
IN_CLOSE_NOWRITE — Файл был открыт для записи, а потом закрыт
IN_CREATE — Файл/каталог создан внутри наблюдаемого каталога
IN_DELETE — Файл/каталог удален из наблюдаемого каталога
IN_DELETE_SELF — Наблюдаемый файл/каталог был удален
IN_MODIFY — Файл был изменен
IN_MOVE_SELF — Наблюдаемый файл/каталог был перемещен
IN_MOVED_FROM — Наблюдаемый файл/каталог был перемещен из наблюдаемого каталога
IN_MOVED_TO — Наблюдаемый файл/каталог был перемещен в наблюдаемый каталог
IN_OPEN — Файл был открыт
IN_ALL_EVENTS — Сокращение для всех вышеперечисленных событий ввода
IN_MOVE — Сокращение для IN_MOVED_FROM | IN_MOVED_TO
IN_CLOSE — Сокращение для IN CLOSE WRITE | IN CLOSE NOWRITE
IN_DONT_FОLLOW — He разыменовывать символьную ссылку (начиная с Linux 2.6.15)
IN_MASK_ADD — Добавить события в маску текущего элемента списка наблюдения для файла pathname
IN_ONESHOT — Наблюдать для файла pathname только одно событие
IN_ONLYDIR — Ошибка, если pathname не каталог (начиная с Linux 2.6.15)

Для удаления события из списка наблюдаемых событий используется функция inotify_rm_watch().

Функция read() читает данные из буфера об одном или нескольких событиях.

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

Итак рассмотрим листинг программы. В программе будем отслеживать изменения, происходящие в директории по абсолютному пути «home/user/dev». Отслеживаемые события это закрытие файла и его изменение.

#define MAX_EVENTS 1024 /*Максимальное кличество событий для обработки за один раз*/ #define LEN_NAME 16 /*Будем считать, что длина имени файла не превышает 16 символов*/ #define EVENT_SIZE ( sizeof (struct inotify_event) ) /*размер структуры события*/ #define BUF_LEN ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*буфер для хранения данных о событиях*/ int main(int argc, char *argv[]) < int length, i = 0, wd; int fd; char buffer[BUF_LEN]; /* Инициализация Inotify*/ fd = inotify_init1(0); if ( fd < 0 ) < perror( "Couldn't initialize inotify"); >const char path[] = "/home/user/dev"; /* добавим наблюдение для директории*/ wd = inotify_add_watch(fd, path, IN_CLOSE | IN_MODIFY); if (wd == -1) < printf("Couldn't add watch to %s\n",path); >else < printf("Watching:: %s\n",path); >while(1) < i = 0; /* высчитываем размер файлового дескриптора*/ length = read( fd, buffer, BUF_LEN ); if ( length < 0 ) < perror( "read" ); >while ( i < length ) < struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ]; if ( event->len ) < if ( event->mask & IN_CLOSE) < if (event->mask & IN_ISDIR) printf( "The directory %s was closed.\n", event->name ); else printf( "The file %s was closed with WD %d\n", event->name, event->wd ); > if ( event->mask & IN_MODIFY) < if (event->mask & IN_ISDIR) printf( "The directory %s was modified.\n", event->name ); else printf( "The file %s was modified with WD %d\n", event->name, event->wd ); > i += EVENT_SIZE + event->len; > > > /* Освобождение ресурсов*/ inotify_rm_watch( fd, wd ); close( fd ); return 0; > 

Источник

Читайте также:  Make boot flash linux

MNorin.com

Блог про Linux, Bash и другие информационные технологии

Inotify в bash: ловим изменения файловой системы

Inotify в bash: ловим изменения файловой системы

Inotify — это подсистема ядра Linux, которая позволяет отслеживать изменения файловых систем. Использование этой подсистемы позволяет выполнять определенные действия в том случае если вы создали файл, что-то в него записали, открыли, закрыли, удалили и так далее. Использование этого механизма позволяет избавиться от необходимости вставлять в скрипты проверки с таймаутами при помощи команды sleep. Это упрощает логику скрипта, поскольку нам нужно просто ждать информацию об изменениях файловой системы, а при получении информации о том, что что-то изменилось, выполнить необходимые действия. Давайте рассмотрим пример скрипта, использующего inotify.

Программы inotifywait и inotifywatch

Эти программы как раз и помогут нам обеспечить необходимый функционал отслеживания изменений файловой системы. В Debian и Ubuntu они входят в пакет inotify-tools. Установка пакета:

apt-get install inotify-tools

Как работает inotifywatch

Программа inotifywatch собирает статистику доступа к файловой системе при помощи inotify. По окончании работы программа выводит статистическую информацию в виде таблицы, включающей информацию об общем количестве событий, о количестве событий каждого типа и файле, для которого произошло событие. У неё есть ряд параметров, которые можно использовать для изменения параметров работы программы.

Типы событий для отслеживания:

access Отслеживаемый файл или файл в отслеживаемой директории был прочитан
modify Отслеживаемый файл или файл в отслеживаемой директории был записан
attrib Метаданные отслеживаемого файла или файла в отслеживаемой директории были изменены. Сюда включаются изменения времени доступа и изменения, права доступа, расширенные атрибуты и так далее.
close_write Отслеживаемый файл или файл в отслеживаемой директории был закрыт после открытия его в режиме записи. Это не говорит о том, что в файл были записаны какие-то данные.
close_nowrite Отслеживаемый файл или файл в отслеживаемой директории был закрыт после открытия в режиме только для чтения
close Отслеживаемый файл или файл в отслеживаемой директории был закрыт, при этом неважно, в каком режиме он был открыт. Имейте в виду, что это событие рализовано просто прослушиванием обоих событий close_write и close_nowrite, поэтому все события будут выведены именно как одно из них, а не как CLOSE. Этот тип скорее как сокращение для двух других типов событий
open Отслеживаемый файл или файл в отслежваемой директории был открыт
moved_to Файл или директория были перемещены в отслеживаемую директорию. Это событие возникает даже в том случае, когда файл был перемещен в пределах одной и той же директории
moved_from Файл или директория были перемещены из отслеживаемой директории. Это событие возникает даже в том случае, когда файл был перемещен в пределах одной и той же директории
move Файл или директория были перемещены из отслеживаемой директории или в неё. Это событие реализовано аналогично событию CLOSE, то есть, скорее как псевдоним для двух типов событий, moved_to и moved_from,поэтому все события будут выведены именно как одно из них, а не как MOVE
move_self Отслеживаемый файл или директорию были перемещены. После возникновения этого события файл или директория больше не отслеживается.
create Файл или директория были созданы в отслеживаемой директории
delete Файл или директория были удалены из отслеживаемой директории
delete_self Отслеживаемый файл или директория были удалены. После этого события файл или директория больше не отслеживается. Обратите внимание, что это событие может произойти, даже если оно явно не слушалось.
unmount Файловая система, накоторой находится отслеживаемый файл или директория, была отмонтирована. Поле возникновения этого события файл или директория перестает отслеживаться.Обратите внимание, что это событие может произойти, даже если оно явно не слушалось.
Читайте также:  Клонирование виртуальной машины astra linux

Пример работы программы inotifywatch:

$ inotifywatch -r -t 300 /var/cache Establishing watches. Finished establishing watches, now collecting statistics. total attrib open moved_to filename 182 1 1 180 /var/cache/apt/archives/ 1 0 1 0 /var/cache/apt/

Как работает inotifywait

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

Параметры inotifywait очень похожи на параметры inotifywatch:

События, которые отслеживаются, точно такие же, как для программы inotifywatch.

Пример работы программы inotifywait:

$ inotifywait /var/cache Setting up watches. Watches established. /var/cache/ OPEN,ISDIR apt

Пишем скрипт, который использует inotify

Прежде всего определимся с условиями задачи, которую нам предстоит решить. Есть некоторые директории, куда пользователи загружают файлы (пусть это будут домашние директории пользователей, /home/ИМЯ-ПОЛЬЗОВАТЕЛЯ). Иногда пользователи эти файлы удаляют, поэтому нам нужно отслеживать изменения и при появлении новых файлов (или новых версий уже существующих файлов) копировать их в директорию /backup/ИМЯ-ПОЛЬЗОВАТЕЛЯ.

Для реализации нам нужно отслеживать изменения файловой системы, на которой находится директория /home, определять, что произошло событие закрытия файла после записи в него, получать директорию, в которой произошло закрытие файла, имя самого файла, определять имя директории, в которую планируется копировать файл, создавать её, если она еще не существует, и, собственно, копировать этот файл в эту директорию.

#!/bin/bash SRC_DIR="/home" DST_DIR="/backup" # Функция, которая будет выполнять необходимые действия # В нашем случае копировать в другую директорию make_action()< # Получаем директорию назначения DIR_TO_COPY_TO=$/$> # Создаем ее, если ее еще не существует mkdir -p $DIR_TO_COPY_TO # Копируем файл cp $1$2 $DIR_TO_COPY_TO > IFS=' ' # Отслеживаем закрытие файлов после записи # Получаем вывод в нужном нам формате inotifywait -e close_write --format '%w %f' -m -r $SRC_DIR |\ ( while read do # Получаем имя директории DIR=$(echo $REPLY | cut -f 1 -d' ') # Получаем имя файла FILE=$(echo $REPLY | cut -f 2 -d' ') # Передаем имена директории и файла в функцию make_action $DIR $FILE done )

Как видите, всё достаточно просто. Если необходимо работать с файлами, имена которых содержат пробелы, вы можете использовать параметр «—csv» и разделять поля по запятой, а не по пробелу, как в примере, или добавить какой-то другой символ в строку шаблона вывода. Основной принцип работы при этом не изменится.

Похожие посты:

Источник

Оцените статью
Adblock
detector