Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #62, ЯНВАРЬ 2006 г.

Ядерная слежка

Alexander S. Salieff

Спецвыпуск: Хакер, номер #062, стр. 062-056-3


struct inotify_event event;

read(fd, &event, 16);

event.filename = calloc(1, event.len+1);

read(fd, event.filename, event.len);

Сам механизм передачи событий через файл устройства позволяет создавать экономичные системы с использованием демультиплексоров наподобие poll и select. Пофайловая нотификация позволяет следить за изменением контента ФС точнее, чем в случае с dnotify. При этом модель inotify так же проста, как и модель dnotify, поэтому даже начинающий программист получает эти механизмы как эффективный инструмент. После того как отпадет надобность в нотификации, сними ее с помощью ioctl:

ioctl(fd, INOTIFY_IGNORE, &wd);

Kqueue

Dnotify и inotify — исключительно linux'овые механизмы. В различных же BSD-системах и, в частности, во freeBSD подобные задачи решаются с помощью механизма kqueue — ядерных событийных очередей. Для активации этого механизма необходимо получить дескриптор ядерной очереди следующим образом:

int kq = kqueue();

Далее. Приступаем к регистрации событий. Структура, описывающая событие, заполняется с помощью специального макроса и затем регистрируется. Для регистрации событий в вызове kevent массив событийных структур и его длина помещаются как второй и третий аргумент. Одноименность структуры kevent и функции kevent вносит некоторую путаницу, но стандарт языков C и C++ этого не запрещает:

int fd = open("myfile", O_RDONLY);

struct kevent ke;

EV_SET(&ke, fd, EVFILT_VNODE, EV_ADD, NOTE_DELETE | NOTE_RENAME, 0, NULL);

kevent(kq, &ke, 1, NULL, 0, NULL);

Набор возможных флагов и дополнительных атрибутов, используемых при заполнении события, достаточно широк. Я не стану приводить его здесь. Если заинтересуешься, обращайся к официальной документации и заголовочным файлам системы.

После регистрации можно переходить к ожиданию событий. Это делается с помощью того же вызова kevent, только теперь массив событий и его длина помещаются как четвертый и пятый аргумент:

if (kevent(kq, NULL, 0, &ke, 1, NULL)==-1) error_and_exit();

После получения события приступим к его анализу. Структура события содержит различные данные, но в данном случае нас интересует значение фильтра события и флагов фильтра:

if (ke.filter==EVFILT_VNODE && (ke.fflags&NOTE_DELETE)) MyNotify("File was deleted!");

else if (ke.filter==EVFILT_VNODE && (ke.fflags&NOTE_RENAME)) MyNotify("File was renamed!");

Механизм kqueue так же эффективен и несложен для реализации взаимодействия с ним в своей программе. Он достаточно часто используется в специфичных BSD-приложениях.

FAM скрывает детали

Вышеописанные системы нотификации, безусловно, хороши, но только в нативной среде использования. И dnotify, и inotify являются механизмами ядра Linux. К примеру, во freebsd для подобных целей используется kqueue, а в каких-то системах, за неимением лучшего, это делается пофайловым перебором. Конечному прикладному программисту хотелось бы иметь унифицированный интерфейс, который позволял бы получать эффективную нотификацию изменения контента ФС и при этом скрывал детали реализации. И такой интерфейс есть — это демон FAM (File Alteration Monitor), который изначально зародился на платформе SGI IRIX, а сегодня активно используется во многих UNIX-дистрибутивах, в том числе Linux, freebsd и sunos/solaris. Библиотека libfam, с одной стороны, предоставляет программисту унифицированные платформонезависимые методы, с другой, скрывает в себе реализацию методов для конкретной платформы. Реализация в виде архитектуры клиент-сервер тоже подразумевает сокрытие деталей реализации сервера от клиента, но мы не будем рассматривать самостоятельное общение с сервером, так как пользоваться стандартной библиотекой несколько проще. Первичная концепция данной системы — создание объекта соединения с FAM-сервером:

Назад на стр. 062-056-2  Содержание  Вперед на стр. 062-056-4