Linux мониторинг изменения файлов
Библиотека сайта rus-linux.net
libinotifytools , которая позволяет с легкостью задействовать интерфейс, предоставляемый подсистемой Inotify.
Мы будем использовать операционную систему Ubuntu 11.10. Установка Inotify-tools в ней не займёт много времени. Что касается других дистрибутивов (последних версий), то рассматриваемый пакет утилит доступен из репозиториев для openSUSE 12.1, Debian 6.x, Arch и других.
Запустите терминал или перейдите в консоль, а затем дайте команду:
$ sudo apt-get install inotify-tools
Кстати, если вы обратите внимание, то увидите, что, помимо inotify-tools будет установлен пакет — libinotifytools0. Это та самая библиотека, о которой мы говорили выше, и которая необходима для работы inotify-tools.
Работаем с Inotify-tools
В пакет inotify-tools входят следующие утилиты: inotifywatch и inotifywait . inotifywatch — эта утилита, которая дает представление о том, какую информацию можно получить с помощью подсистемы Inotify, а также осуществляет сбор статистической информации о соответствующих событиях файловой системы (открытие файлов, удаление и т. д. — далее, в этом контексте будут иметься ввиду события Inotify).
Рассмотрим на примерах, как это работает. Откройте терминал и дайте команду:
После чего вы увидите на экране примерно следующее (см. рис. 1)
Рисунок 1. inotifywatch в процессе работы
Это означает, что inotifywatch успешно запущен и осуществляет рекурсивный (опция «-r») сбор информации о действиях с файловой системой в домашнем каталоге текущего пользователя. Например, запустим браузер Mozilla Firefox и закроем его. Далее нажмём в терминале «Ctrl»+»C», чтобы остановить inotifywatch . В итоге мы увидим примерно следующее (см. рис. 2, для увеличения щелкните по рисунку мышкой).
Рисунок. 2. Вывод Inotifywatch
В этом выводе вы можете увидеть к каким файлам обращался Mozilla Firefox во время своей работы.
При помощи опции «-e» можно добиться более гибкого вывода информации от inotifywatch . Так, например, нам необходимо узнать какие файлы или каталоги во время своей работы открывает Mozilla Firefox. Дадим следующую команду:
После этого, запустим Mozilla Firefox, поработаем в нем, а затем закроем. Далее остановим в терминале, как в прошлый раз («Ctrl»+»C»), и работу самой утилиты inotifywatch . В выводе мы уже увидим все лишь три «колонки» — total, open и filename (см. рис. 3).
Рисунок 3. Вывод inotifywatch при использовании опции «-e»
Воспользовавшись справкой для данной утилиты, вы можете увидеть, что inotifywatch способна собирать информацию о довольно большом количестве событий. Получить справку по inotifywatch можно с помощью соответствующего руководства man ( man inotifywatch ), а также указав перед данной командой опцию — «-h».
Итак, inotifywatch не отображает статистику о событиях файловой системы сразу. Но, что делать когда необходимо получать информацию о событиях сразу, как они начинают происходить. Во общем, осуществлять мониторинг. В этом нам поможет вторая утилита из пакета Inotify-tools — inotifywait .
где опция «-m» — указывает осуществлять мониторинг событий, без этой опции inotifywait прекратит работу после первого события; опция «-r» — указывает осуществлять рекурсивный сбор информации о действиях с файловой системой.
А запустив Mozilla Firefox, вы увидите все файлы, к которым обращается браузер, а также, действия, которые он с ними осуществляет (создание временных файлов, обращение к внутренним базам данных sqlite и т.д.).
Для получения справки по работе с inotifywait воспользуйтесь соответствующей страницей руководств, а также используйте опцию «-h».
Заключение
inotify-tools удобный инструмент мониторинга событий файловой системы. Кроме того, в ситуация, когда необходимо получить сведения о файлах и каталогах, к которым обращается та или иная программа, inotify-tools может стать лучшим решением, т. к. имеет небольшой объем и мало зависимостей, а также является интерфейсом для подсистемы ядра — Inotify.
Источники и дополнительные материалы:
2. Проект Inotify-tools на GitHub — https://github.com/rvoicilas/inotify-tools/;
3. Исходный код libinotifytools — https://github.com/rvoicilas/inotify-tools/tree/master/libinotifytools/src;
4. Сайт посвященный libinotifytools — http://inotify-tools.sourceforge.net/api/index.html;
5. К. Вервлоесем. Inotify: Следим за системой // Linux Format. — N 1. — 2011. — с. 80 — 83.
Отслеживание изменений в директории с помощью Inotify
Столкнулся с задачей, где необходимо было отслеживать в ОС Linux изменение файла в директории на чистом С++. Так как чистый С++, QtCreator с его QFileSystemWatcher сразу отпадал, из-за того что необходимо было подключать QObject. В итоге решил пользоваться линуксовой функцией Inotify.
Inotify позволяет через файловый дескриптор наблюдать за директорией или файлом, отслеживая их события. Все события ввода-вывода ссылаются на открытый файл с использованием файлового дескриптора. Файловый дескриптор представляет собой целое число типа int.
Итак, работа типичной программы мониторинга организована следующим образом:
- С помощью inotify_init() открываем файловый дескриптор
- Добавляем одно или несколько событий для наблюдений
- Ожидаем добавленное событие
- Обрабатываем события, после чего снова начинаем ждать в бесконечном цикле
- При отсутствии активных наблюдений или при получении определенного сигнала файловый дескриптор закрывается, выполняется очистка и программа завершает работу.
inotify_init() инициализирует новый экземпляр inotify и возвращает файловый дескриптор. На данный момент используется более новый системный вызов inotify_init1(int flags). Если используется флаг 0 или флаги вообще не указаны, то
inotify_init1(int flags) будет работать как inotify_init(). Так же используются другие флаги:
IN_NONBLOCK – устанавливает файловый дескриптор в неблокирующий режим.
IN_CLOEXEC – устанавливает флаг закрытия при выполнении.
Системный вызов 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; >
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.