printf("cookie =%4d; ", i->cookie);
printf("mask = ");
if (i->mask & IN_ACCESS) printf("IN_ACCESS ");
if (i->mask & IN_ATTRIB) printf("IN_ATTRIB ");
if (i->mask & IN_CLOSE_NOWRITE) printf("IN_CLOSE_NOWRITE ");
if (i->mask & IN_CLOSE_WRITE) printf("IN_CLOSE_WRITE ");
if (i->mask & IN_CREATE) printf("IN_CREATE ");
if (i->mask & IN_DELETE) printf("IN_DELETE ");
if (i->mask & IN_DELETE_SELF) printf("IN_DELETE_SELF ");
if (i->mask & IN_IGNORED) printf("IN_IGNORED ");
if (i->mask & IN_ISDIR) printf("IN_ISDIR ");
if (i->mask & IN_MODIFY) printf("IN_MODIFY ");
if (i->mask & IN_MOVE_SELF) printf("IN_MOVE_SELF ");
if (i->mask & IN_MOVED_FROM) printf("IN_MOVED_FROM ");
if (i->mask & IN_MOVED_TO) printf("IN_MOVED_TO ");
if (i->mask & IN_OPEN) printf("IN_OPEN ");
if (i->mask & IN_Q_OVERFLOW) printf("IN_Q_OVERFLOW ");
if (i->mask & IN_UNMOUNT) printf("IN_UNMOUNT ");
printf("\n");
if (i->len > 0)
printf(" name = %s\n", i->name);
}
#define BUF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1))
int
main(int argc, char *argv[])
{
int inotifyFd, wd, j;
char buf[BUF_LEN];
ssize_t numRead;
char *p;
struct inotify_event *event;
if (argc < 2 || strcmp(argv[1], "-help") == 0)
usageErr("%s pathname… \n", argv[0]);
if (inotifyFd == -1)
errExit("inotify_init");
for (j = 1; j < argc; j++) {
if (wd == -1)
errExit("inotify_add_watch");
printf("Watching %s using wd %d\n", argv[j], wd);
}
for (;;) { /* Читать события вечно */
if (numRead == 0)
fatal("read() из inotify fd вернула 0!");
if (numRead == -1)
errExit("read");
printf("Read %ld bytes from inotify fd\n", (long) numRead);
/* Обработка всех событий из буфера, переданного read() */
for (p = buf; p < buf + numRead;) {
displayInotifyEvent(event);
p += sizeof(struct inotify_event) + event->len;
}
}
exit(EXIT_SUCCESS);
}
inotify/demo_inotify.c
Программа из листинга 19.1 выполняет следующие шаги:
• использует функцию inotify_init() для создания файлового дескриптора inotify
• задействует функцию inotify_add_watch() для добавления элемента списка наблюдения для каждого из файлов, перечисленных в аргументах командной строки программы
• выполняет бесконечный цикл, который:
• читает буфер событий из файлового дескриптора inotify
• вызывает функцию для displayInotifyEvent() отображения содержимого каждой структуры inotify_event в буфере
Следующая сессия оболочки демонстрирует применение программы в листинге 19.1. Мы запускаем экземпляр программы, работающей в фоновом режиме и осуществляющей мониторинг двух каталогов:
$./demo_inotify dir1 dir2 &
[1] 5386
Watching dir1 using wd 1
Watching dir2 using wd 2
Затем запускаем выполнение команд, генерирующих события в двух каталогах. Начинаем с создания файла с помощью команды cat(1):
$ cat > dir1/aaa
Read 64 bytes from inotify fd
wd = 1; mask = IN_CREATE
name = aaa
wd = 1; mask = IN_OPEN
name = aaa
Вышеприведенный вывод, созданный фоновой программой, показывает, что функция read() передала буфер, содержащий два события. Мы продолжим вводом некой информации в файл и завершающего
Hello world
Read 32 bytes from inotify fd
wd = 1; mask = IN_MODIFY
name = aaa
Read 32 bytes from inotify fd
wd = 1; mask = IN_CLOSE_WRITE
name = aaa
Затем мы переименуем файл с переносом в другой каталог под наблюдением. Это приведет к генерации двух событий: одного для каталога, из которого файл переносится (дескриптор наблюдения 1) и второго — для каталога, в который файл будет перенесен (дескриптор наблюдения 2):
$ mv dir1/aaa dir2/bbb
Read 64 bytes from inotify fd
wd = 1; cookie = 548; mask = IN_MOVED_FROM
name = aaa
wd = 2; cookie = 548; mask = IN_MOVED_TO
name = bbb
Значения полей cookie обоих событий совпадают, что позволяет приложению связать их.
При создании подкаталога в одном из наблюдаемых каталогов маска генерируемого при этом события содержит бит IN_ISDIR, показывающий, что субъект события является каталогом:
$ mkdir dir2/ddd
Read 32 bytes from inotify fd
wd = 1; mask = IN_CREATE IN_ISDIR
name = ddd
На данном этапе важно повторить, что мониторинг inotify не является рекурсивным. Если бы приложению потребовалось осуществлять мониторинг событий в только что созданном каталоге, то ему нужно было бы совершить еще один вызов inotify_add_watch() с указанием путевого имени данного подкаталога.
Наконец, мы удаляем один из наблюдаемых подкаталогов:
$ rmdir dir1
Read 32 bytes from inotify fd
wd = 1; mask = IN_DELETE_SELF
wd = 1; mask = IN_IGNORED
Последнее событие, IN_IGNORED, было сгенерировано для информирования приложения о том, что ядро удалило данный элемент из списка наблюдения.