Monitoreo de eventos en sistemas de archivos con inotify

Monitoreo eficiente y efectivo de eventos en sistemas de archivos en el kernel 2.6

Utilice inotify cuando necesite monitorear eventos en sistemas de archivos en Linux® de modo eficaz, preciso y asincrónico. Úselo para monitorear en el espacio del usuario la seguridad, la performance, u otros aspectos. (OEl 10 de septiembre de 2010, el código descargable de muestra para este artículo se actualizó para corregir una edición tipográfica)

Ian Shields, Senior Programmer, IBM

author photo - Ian ShieldsIan Shields trabaja en múltiples proyectos Linux para la zona Linux de developerWorks. Es Senior Programmer de IBM en el Research Triangle Park (RTP), Carolina del Norte. Ingresó a IBM en Canberra, Australia, como Systems Engineer en 1973, y desde entonces se dedica a sistemas de comunicaciones y computación ubicua en Montreal, Canadá, y en el RTP de Carolina del Norte. Es propietario de numerosas patentes y publicó diversos trabajos. Tiene una diplomatura en Matemática Pura y Filosofía de la Universidad Nacional de Australia. Es Máster y Doctor en Ciencias de la Computación de la Universidad Estatal de Carolina del Norte. Para contactar a Ian, escríbale a: ishields@us.ibm.com.



21-01-2011 (Primera publicación 21-01-2011)

Conéctese con Ian

Ian es uno de nuestros autores más populares y exitosos. Navegue en all of Ian's articles en developerWorks. Consulte Ian's profile y conéctese con él, con otros autores y con otros lectores en My developerWorks.

Estoy en deuda con Eli Dow de IBM, quien escribió una versión anterior de este artículo, previamente a la integración final de inotify en el kernel (núcleo) de Linux. El código de muestra disponible en la sección Download se basa particularmente bastante en el código de muestra original de Eli.

Presentación de inotify

El monitoreo de eventos en sistemas de archivos es esencial para muchos tipos de programas, desde los administradores de archivos hasta las herramientas de seguridad. A partir de kernel 2.6.13 de Linux, Linux ha incluido inotify, el cual permite que un programa de monitoreo abra un sólo descriptor de archivos y vea en uno o más archivos o directorios un conjunto específico de eventos, como los atributos open, close, move/rename, delete, create o change. Se han realizado algunas mejoras en kernels posteriores, así que verifique el nivel de su kernel antes de contar con estas características.

En este artículo, aprenderá cómo utilizar las funciones de inotify en una aplicación de monitoreo simple. Descargue el código de muestra y compílelo en su sistema para realizar una exploración más profunda.


Un poco de historia

Antes de inotify existía dnotify. Desafortunadamente, dnotify tenía limitaciones que hacían que los usuarios desearan algo mejor. Algunas de las ventajas de inotify son:

  • Inotify utiliza un único descriptor de archivos, mientras que en dnotify se debe abrir un descriptor de archivos por cada directorio que intenta ver para realizar modificaciones. Esto puede resultar muy caro cuando se monitorean varios directorios a la vez, y hasta puede exceder el límite de descriptores de archivos por proceso.
  • El descriptor de archivos utilizado por inotify se obtiene usando una llamada al sistema y no tiene un dispositivo o archivo relacionado. Con dnotify, el descriptor de archivos sujeta el directorio, previniendo que el dispositivo de respaldo se desmonte, un problema típico de los medios desmontables. Con inotify, un archivo o directorio monitoreado en un sistema de archivos que es desmontado genera un evento, y el reloj desaparece automáticamente.
  • Inotify puede monitorear archivos o directorios. Dnotify monitorea directorios, por lo cual los programadores debían hacer que las estructuras stat o una estructura de datos equivalente reflejen los archivos en los directorios monitoreados, luego comparar aquellos con el estado actual después de ocurrido un evento para saber que sucedió con la entrada en el directorio.
  • Como se señaló anteriormente, inotify utiliza un descriptor de archivos, permitiendo a los programadores utilizar funciones select o poll estándares para monitorear los eventos. Esto permite I/O multiplexadas o integraciones con mainloopde Glib eficaces. En cambio, dnotify utiliza señales, que los programadores a menudo encuentran más complicadas o poco elegantes. La notificación Signal-drive I.O se agregó también a inotify en el kernel 2.6.25.

La API para inotify

Inotify suministra una API sencilla que utiliza descriptores de archivos mínimos y permite un monitoreo preciso. La comunicación con inotify se establece a través de una llamada al sistema. Las funciones disponibles son las siguientes:

inotify_init
es la llamada al sistema que crea una instancia inotify y devuelve un descriptor de archivos que consulta a la instancia.
inotify_init1
es similar a inotify_init con indicadores adicionales. Si los indicadores no se especifican, se comporta igual que inotify_init.
inotify_add_watch
agrega un reloj a un archivo o directorio y especifica qué eventos van a monitorearse. Los indicadores controlan si los eventos seran agregados a un reloj existente, si el reloj debería realizarse sólo si la ruta representa un directorio, si los enlaces simbólicos deberían seguirse o no, y si el reloj es un reloj one-shot que debería detenerse después del primer evento.
inotify_rm_watch
borra el item monitoreado de una lista de monitoreo.
read
lee un buffer que contiene información sobre uno o más eventos.
close
cierra el descriptor de archivos, y quita los relojes que quedan en ese descriptor. Cuando todos los descriptores de archivos de una instancia están cerrados, los recursos y objetos subyacentes son liberados de modo que los pueda reutilizar el kernel.

Por lo tanto, un programa de monitoreo típico hará lo siguiente:

  1. Utilizará inotify_init para abrir un descriptor de archivos
  2. Agregará uno o más relojes
  3. Esperará los eventos
  4. Provará los eventos, luego regresará para esperar más
  5. Cuando no haya relojes activos o ante alguna señal, cerrará el descriptor de archivos, limpiará y saldrá.

En la siguiente sección verá cuáles son los eventos que puede monitorear y cómo funcionan en nuestro programa de muestra. Finalmente verá cómo funciona el monitoreo de eventos.


Notificaciones

Cuando su aplicación lea una notificación, una secuencia de uno o más eventos se leerá en un buffer que usted suministre. Los eventos son devueltos en una estructura de longitud variable como se observa en el Listado 1. Si la cantidad de datos llenara su bufer, necesitaría administrar la caja de información de eventos parciales o el nombre parcial de la última entrada.

Listado 1. La estructura de eventos para inotify
 struct
                inotify_event { int wd; /* Watch descriptor. */ uint32_t mask;
                /* Watch mask. */ uint32_t cookie; /* Cookie to synchronize two
                events. */ uint32_t len; /* Length (including NULs) of name. */
                char name __flexarr; /* Name. */ };

Tenga en cuenta que el campo name está presente sólo si el elemento monitoreado es un directorio y el evento es para un elemento en el directorio, distinto del directory mismo. La cookie se utiliza para correlacionar un evento IN_MOVED_FROM con el evento IN_MOVED_TO correspondiente si ambos se relacionan con elementos monitoreados. El tipo de evento se devuelve en el campo mask, junto con indicadores que pueden ser determinados por el kernel. Por ejemplo, el indicador IN_ISDIR es establecido por el kernel si el evento es para un directorio


Eventos que puede monitorear

Hay varios eventos que se pueden monitorear. Algunos, como IN_DELETE_SELF, aplican sólo al elemento que se monitorea, mientras que otros, como IN_ATTRIB o IN_OPEN pueden aplicar al elemento monitoreado, o si el elemento es un directorio, a un directorio o archivo incluido en él.

IN_ACCESS
Se ha accedido al elemento monitoreado o a la entrada en un directorio monitoreado. Por ejemplo, se ha leido un archivo abierto.
IN_MODIFY
Se ha modificado el elemento monitoreado o una entrada en un directorio monitoreado. Por ejemplo, se ha actualizado un archivo abierto.
IN_ATTRIB
Los metadatos han sido modificados en el elemento monitoreado o en una entrada en un directorio monitoreado. Por ejemplo, se han modificado las marcas de tiempo o los permisos.
IN_CLOSE_WRITE
Se ha cerrado un archivo o directorio que se habia abierto para escribir en él.
IN_CLOSE_NOWRITE
Se ha cerrado un archivo o directorio que se había abierto de solo lectura.
IN_CLOSE
Una máscara de conveniencia que es la OR lógica de los dos eventos precedentes close events (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE).
IN_OPEN
Se ha abierto un archivo o directorio.
IN_MOVED_FROM
Se movió de la ubicación de monitoreo un elemento monitoreado o una entrada en un directorio monitoreado. El evento también incluye una cookie para permitirle correlacionar IN_MOVED_FROM con IN_MOVED_TO.
IN_MOVED_TO
Se movió a una ubicación monitoreada un archivo o directorio. El evento incluye una Si al archivo o directorio sólo se le cambia el nombre, vería ambos elementos. Si se ha movido hacia o desde una ubicación que no está monitoreando, sólo verá un evento. Si mueve o un elemento monitoreado o cambia el nombre del mismo, el reloj continua. Vea IN_MOVE-SELF más abajo.
IN_MOVE
Una máscara de conveniencia que es la OR lógica de los dos eventos move precedentes (IN_MOVED_FROM | IN_MOVED_TO).
IN_CREATE
Se crea un subdirectorio o archivo en un directorio monitoreado.
IN_DELETE
Se borró un subdirectorio o archivo en un directorio monitoreado.
IN_DELETE_SELF
El elemento monitoreado ha sido borrado. El reloj termina y recibe además un evento IN_IGNORED.
IN_MOVE_SELF
El elemento monitoreado ha sido movido

Además de los indicadores de eventos, hay varios otros indicadores que puede encontrar en el encabezado de inotify (/usr/include/sys/inotify.h). Por ejemplo, si sólo desea monitorear el primer evento, puede colocar el indicador IN_ONESHOT cuando agrega el reloj.


Una aplicación inotify simple

Nuestra aplicación de muestra (vea la sección Download ) sigue la lógica general presentada más arriba. Utilizamos un administrador de señal para capturar ctrl-c (SIGINT) y resetear un indicador (keep_running) de modo que la aplicación sepa cuando finalizar. Las llamadas actuales a inotify son realizadas en rutinas de utilidad. Tenga en cuenta que también creamos una cola de modo que los eventos puedan borrarse del objeto inotify subyacente y luego procesarse más tarde. En una aplicación real, quizá desee hacer esto en un hilo de ejecución diferente (y prioridad más alta) que el que utiliza para procesar los eventos. Para esta aplicación, simplemente se muestra el principio general. Nosotros utilizamos una lista enlazada muy simple de eventos donde cada una de nuestras entradas de cola consiste del espacio adicional del evento original para un indicador del próximo evento en la cola.

El programa principal

El administrador de señal y la rutina principalse ven en el Listado 2. Para este ejemplo sencillo, colocamos un reloj por cada archivo o directorio que ingresamos en la línea de comandos, y monitoreamos todos los eventos de cada una, usando la máscara de eventos IN_ALL_EVENTS. En una aplicación real, quizá desee rastrear sólo los eventos de creación o eliminación de archivos o directorios, de modo que podría desenmascarar los eventos abiertos y cerrados así como las modificaciones realizadas a los atributos. Si no está interesado en los cambios de nombre o el movimiento de archivos o directorios, podría además desenmascarar los diversos eventos de movimiento. Vea la página man de inotify si desea más detalles.

Listado 2. Rutina principal de muestra para inotify-test.c
 /*
                El administrador de señal que simplemente resetea un indicador
                para provocar la terminación */ void signal_handler (int signum)
                { keep_running = 0; } int main (int argc, char **argv) { /* Este
                es un descriptor de archivos para el reloj de inotify */ int
                inotify_fd; keep_running = 1; /* Establecer un administrador de
                señal ctrl-c */ si (signal (SIGINT, signal_handler) == SIG_IGN)
                { /* Resetear a SIG_IGN (ignorar) si ese era el estado previo */
                signal (SIGINT, SIG_IGN); } /* Primero abrimos la entrada
                inotify dev */ inotify_fd = open_inotify_fd (); si (inotify_fd
                > 0) { /* Necesitaremos un lugar para poner en cola los
                eventos de inotify, porque si no se leen los eventos lo
                suficientemente rápido, se pierden. Esta cola es probablemente
                demasiado pequeña si usted está monitoreando algo como un
                directorio con un montón de archivos y el directorio se borra.
                */ queue_t q; q = queue_create (128); /* este es el descriptor
                del reloj obtenido por cada elemento que estamos monitoreando.
                Una aplicación real podría mantener estos para darle algún uso
                en la aplicación. Esta muestra sólo se asegura de que ninguno de
                los descriptores de relojes sean menores a 0. */ int wd; /*
                Observe todos los eventos (IN_ALL_EVENTS) para los directorios y
                archivos ingresados como argumentos. Lea el artículo sobre las
                razones por las cuales podría desear modificar esto para lograr
                un uso más eficiente de inotify en su aplicación. */ int index;
                wd = 0; printf("\n"); for (index = 1; (index < argc)
                && (wd >= 0); index++) { wd = watch_dir
                (inotify_fd, argv[index], IN_ALL_EVENTS); } if (wd > 0) {
                /* Espere los eventos y procéselos hasta que se borre la
                condición de finalización */ process_inotify_events (q,
                inotify_fd); } printf ("\nTerminating\n"); /* Finalice cerrando
                fd, destruyendo la cola, y obtenidendo un código adecuado */
                close_inotify_fd (inotify_fd); queue_destroy (q); } return 0; }

Apertura del descriptor de archivos usando inotify_init

El Listado 3 muestra nuestra función utilitaria simple para la creación de una instancia de inotify y la obtención de un descriptor de archivos para la misma. El descriptor de archivos es devuelto al llamador. Si hay un error, el valor obtenido es negativo.

Listado 3. Uso de inotify_init
 /* Cree una instancia de inotify y
                abra un descriptor de archivos para acceder a la misma */ int
                open_inotify_fd () { int fd; watched_items = 0; fd =
                inotify_init (); if (fd < 0) { perror ("inotify_init () =
                "); } return fd; }

Incorporación de un reloj usando inotify_add_watch

Una vez que tenemos un descriptor de archivos para la instancia de inotify, debemos agregar uno o más relojes. Utilice la máscara para colocar los eventos puntuales que desee monitorear. En nuestro ejemplo, utilizamos la máscara IN_ALL_EVENTS, que monitorea todos los eventos disponibles.

Listado 4. Uso de inotify_add_watch
 int watch_dir (int fd, const
                char *dirname, unsigned long mask) { int wd; wd =
                inotify_add_watch (fd, dirname, mask); if (wd < 0) {
                printf ("Cannot add watch for \"%s\" with event mask %lX",
                dirname, mask); fflush (stdout); perror (" "); } else {
                watched_items++; printf ("Watching %s WD=%d\n", dirname, wd);
                printf ("Watching = %d items\n", watched_items); } return wd; }

El bucle de procesamiento de eventos

Ahora que hemos configurado algunos relojes, el próximo paso es esperar los eventos. Bucleamos mientras haya relojes y nuestro indicador keep_running no haya sido reseteado por el administrador de señales. El bucle espera que ocurra algún evento, coloca los eventos disponibles en cola, luego procesa la cola antes de regresar para esperear más eventos. En una aplicación real, probablemente colocaría eventos en la cola de un hilo de ejecución, mientras los procesa en otro hilo. El bucle se puede observar en el Listado 5.

Listado 5. El bucle de procesamiento de eventos
 int
                process_inotify_events (queue_t q, int fd) { while (keep_running
                && (watched_items > 0)) { if (event_check
                (fd) > 0) { int r; r = read_events (q, fd); if (r
                < 0) { break; } else { handle_events (q); } } } return 0;
                }

Esperando los eventos

En nuestra aplicación de muestra, esperamos indefinidamente, y nos ponemos en alerta sólo si un evento monitoreado ocurre o una señal interrumple el procesamiento. El código se puede observar en el Listado 6.

Listado 6. Esperando eventos o interrupciones
 int event_check
                (int fd) { fd_set rfds; FD_ZERO (&rfds); FD_SET (fd,
                &rfds); /* Esperar hasta que ocurra un evento o ser
                interrumpidos por la recepción de una señal */ return select
                (FD_SETSIZE, &rfds, NULL, NULL, NULL); }

Lectura de eventos

Cuando ocurre un evento, leemos tantos eventos como entren en un buffer grande y luego los colocamos en una cola para que el administrador de eventos los procese. El código de muestra no administra cajas en la que haya más eventos disponibles que los que caben en nuestro buffer de 16.384 bytes. Este debe ser capaz de administrar un evento parcial al final del buffer. Los límites actuales de longitud de nombre no debería representar un problema, pero un buen programa de defensa tendría que ser capaz de verificar que los nombres no excedan el buffer.

Listado 7. Lectura y puesta en cola de eventos
 int
                read_events (queue_t q, int fd) { char buffer[16384]; size_t
                buffer_i; struct inotify_event *pevent; queue_entry_t event;
                ssize_t r; size_t event_size, q_event_size; int count = 0; r =
                read (fd, buffer, 16384); if (r <= 0) return r; buffer_i
                = 0; while (buffer_i < r) { /* Analizar gramaticalmente y
                colocarlos en cola. */ pevent = (struct inotify_event *)
                &buffer[buffer_i]; event_size = offsetof (struct
                inotify_event, name) + pevent->len; q_event_size =
                offsetof (struct queue_entry, inot_ev.name) +
                pevent->len; event = malloc (q_event_size); memmove
                (&(event->inot_ev), pevent, event_size);
                queue_enqueue (event, q); buffer_i += event_size; count++; }
                printf ("\n%d events queued\n", count); return count; }

Procesamiento de eventos

¡Finalmente! Tenemos algunos eventos que procesar. Para esta aplicación, simplemente informamos cuáles son los eventos que ocurrieron. Si el nombre está presente en la estructura del evento, informamos si se trata de un archivo o de un directorio. En el caso de un movimiento, también damos la información de la cookie que permite correlacionar los eventos que se han movido o a los cuales se les ha cambiado el nombre. El Listado 8 muestra parte del código, incluyendo la administración de algunos eventos. Vea en la sección Download el código completo.

Listado 8. Procesamiento de eventos
 void handle_event
                (queue_entry_t event) { /* Si el evento se relaciona con el
                nombre del archivo, lo almacenamos aquí */ char
                *cur_event_filename = NULL; char *cur_event_file_or_dir = NULL;
                /* Este es el descriptor del reloj en el que ocurrió el evento
                */ int cur_event_wd = event->inot_ev.wd; int
                cur_event_cookie = event->inot_ev.cookie; indicadores
                grandes sin firma; si (event->inot_ev.len) {
                cur_event_filename = event->inot_ev.name; } si (
                event->inot_ev.mask & IN_ISDIR ) {
                cur_event_file_or_dir = "Dir"; } sino { cur_event_file_or_dir =
                "File"; } flags = event->inot_ev.mask &
                ~(IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED ); /*
                Realizar rutinas de administrador según evento */ /* La máscara
                es mágica y nos dice que operación de archivo ocurrió */ switch
                (event->inot_ev.mask & (IN_ALL_EVENTS |
                IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED)) { /* Se accedió al
                archivo */ case IN_ACCESS: printf ("ACCESS: %s \"%s\" on WD
                #%i\n", cur_event_file_or_dir, cur_event_filename,
                cur_event_wd); break; /* Se modificó el archivo */ case
                IN_MODIFY: printf ("MODIFY: %s \"%s\" on WD #%i\n",
                cur_event_file_or_dir, cur_event_filename, cur_event_wd); break;
                /* Se modificaron los atributos del archivo */ case IN_ATTRIB:
                printf ("ATTRIB: %s \"%s\" on WD #%i\n", cur_event_file_or_dir,
                cur_event_filename, cur_event_wd); break; /* El archivo abierto
                para escritura se cerró */ case IN_CLOSE_WRITE: printf
                ("CLOSE_WRITE: %s \"%s\" on WD #%i\n", cur_event_file_or_dir,
                cur_event_filename, cur_event_wd); break; /* El archivo de solo
                lectura se cerró */ case IN_CLOSE_NOWRITE: printf
                ("CLOSE_NOWRITE: %s \"%s\" on WD #%i\n", cur_event_file_or_dir,
                cur_event_filename, cur_event_wd); break; /* El archivo se abrió
                */ case IN_OPEN: printf ("OPEN: %s \"%s\" on WD #%i\n",
                cur_event_file_or_dir, cur_event_filename, cur_event_wd); break;
                /* El archivo se movió de X */ case IN_MOVED_FROM: printf
                ("MOVED_FROM: %s \"%s\" on WD #%i. Cookie=%d\n",
                cur_event_file_or_dir, cur_event_filename, cur_event_wd,
                cur_event_cookie); break; . . (otros casos) . /* El reloj se
                eliminó explícitamente con inotify_rm_watch o automáticamente
                porque se borró el archivo, o el sistema de archivos se
                desmontó. */ case IN_IGNORED: watched_items--; printf ("IGNORED:
                WD #%d\n", cur_event_wd); printf("Watching = %d
                items\n",watched_items); break; /* Se recibió mensaje
                desconocido */ por omisión: printf ("UNKNOWN EVENT \"%X\"
                OCCURRED for file \"%s\" on WD #%i\n",
                event->inot_ev.mask, cur_event_filename, cur_event_wd);
                break; } /* Si los indicadores colocados son distintos a
                IN_ISDIR, informar a los indicadores */ si (flags &
                (~IN_ISDIR)) { flags = event->inot_ev.mask; printf
                ("Flags=%lX\n", flags); } }

Este ejemplo sencillo ha sido diseñado para mostrar cómo funciona inotify y qué eventos se pueden monitorear. Sus propias necesidades le dirán qué eventos debe monitorear y cómo administrarlos.


Example usage

En esta sección creamos una estructura de directorio sencilla de dos niveles con un archivo en el directorio y luego ejecutamos la aplicación de muestra para ilustrar algunos de los eventos que puede monitorear inotify. Iniciaremos el programa de muestra de inotify desde una sesión de la terminal, pero la ejecutaremos en el entorno (usando &) de modo que los datos de salida del programa sean intercalados con nuestros comandos. Debería ejecutar además el programa en una ventana de terminal mientras ejecuta los comandos en una o más ventanas. El Listado 9 muestra la creación la estructura de nuestro directorio de muestra y el archivo vacio, junto con los datos de salida cuando instalamos por primera vez el programa de muestra.

Listado 9. Creación del entorno de muestra
                ian@attic4:~/inotify-sample$ mkdir -p dir1/dir2
                ian@attic4:~/inotify-sample$ touch dir1/dir2/file1
                ian@attic4:~/inotify-sample$ ./inotify_test dir1/ dir1/dir2/
                dir1/dir2/file1& [2] 8733 ian@attic4:~/inotify-sample$
                Watching dir1/ WD=1 Watching = 1 items Watching dir1/dir2/ WD=2
                Watching = 2 items Watching dir1/dir2/file1 WD=3 Watching = 3
                items ian@attic4:~/inotify-sample$

En el Listado 10, observamos los resultados del listado de los contenidos de dir2. El primer evento se informó para dir1, mostrando que algo, es decir dir2, en el directorio que se estaba monitoreando en el descriptor de reloj 1 se abrió. La segunda entrada es para el descriptor de reloj 2, y muestra que el elemento monitoreado (en este caso, dir2) se abrió. Si esta monitoreando muchos elementos en un árbol de directorio, probablemente verá este tipo de doble salida con frecuencia.

Listado 10. Listado de los contenidos de dir2
                ian@attic4:~/inotify-sample$ ls dir1/dir2 file1 4 events queued
                OPEN: Dir "dir2" on WD #1 OPEN: Dir "(null)" on WD #2
                CLOSE_NOWRITE: Dir "dir2" on WD #1 CLOSE_NOWRITE: Dir "(null)"
                on WD #2

En el Listado 11, agregamos algo de texto al file1. Preste atención nuevamente a los eventos de doble apertura, cierre, y modificación para el archivo y el directorio que contiene. Tenga en cuenta también que no todos los eventos son leidos a la vez. Nuestra rutina de puesta en cola se llamó tres veces con dos eventos cada vez. Si usted ejecuta la aplicación de nuevo y hace las mismas cosas otra vez, puede o no repetir este comportamiento en particular.

Listado 11. Incorporación de texto a file1
                ian@attic4:~/inotify-sample$ echo "Some text" >>
                dir1/dir2/file1 2 events queued OPEN: File "file1" on WD #2
                OPEN: File "(null)" on WD #3 2 events queued MODIFY: File
                "file1" on WD #2 MODIFY: File "(null)" on WD #3 2 events queued
                CLOSE_WRITE: File "file1" on WD #2 CLOSE_WRITE: File "(null)" on
                WD #3

En el Listado 12, cambiamos los atributos de file1. De nuevo, tenemos doble salida para el ítem monitoreado y el directorio que este contiene.

Listado 12. Modificación de los attributos de un archivo
                ian@attic4:~/inotify-sample$ chmod a+w dir1/dir2/file1 2 events
                queued ATTRIB: File "file1" on WD #2 ATTRIB: File "(null)" on WD
                #3

Ahora moveremos file1 al nivel de directorio de dir1. Los resultados obtenidos se observan en el Listado 13. Esta vez no tenemos entradas dobles. En realidad tenemos tres entradas, una por cada directorio y una por el mismo archivo. Tenga presente que la cookie (569) nos permite correlacionar el evento MOVED-FROM con el evento MOVED_TO.

Listado 13. Desplazamiento de file1 a dir1
                ian@attic4:~/inotify-sample$ mv dir1/dir2/file1 dir1 3 events
                queued MOVED_FROM: File "file1" on WD #2. Cookie=569 MOVED_TO:
                File "file1" on WD #1. Cookie=569 MOVE_SELF: File "(null)" on WD
                #3

Ahora crearemos un enlace duro desde file1 hasta file2. Dado que la cantidad de enlaces a inode se modifica, tenemos un evento ATTRIB en file1, y también tenemos un evento CREATE para file2.

Listado 14. Creación de un enlace duro
                ian@attic4:~/inotify-sample$ ln dir1/file1 dir1/file2 2 events
                queued ATTRIB: File "(null)" on WD #3 CREATE: File "file2" on WD
                #1

Ahora movamos file1 al directorio actual, colocándole el nombre file3. El directorio actual no se está monitoreando, así que no hay evento MOVED_TO event para correlacionar con el evento MOVED_FROM.

Listado 15. Desplazamiento de file1 a un directorio que no se está monitoreando
 ian@attic4:~/inotify-sample$ mv
                dir1/file1 ./file3 2 events queued MOVED_FROM: File "file1" on
                WD #1. Cookie=572 MOVE_SELF: File "(null)" on WD #3

En este punto, dir2 está vacío, por lo tanto lo eliminamos. Tenga en cuenta que obtendremos un evento IGNORED para el descritor de reloj 2, así que ahora sólo estaremos monitoreando dos elementos.

Listado 16. Eliminación de dir2
 ian@attic4:~/inotify-sample$
                rmdir dir1/dir2 3 events queued DELETE: Dir "dir2" on WD #1
                DELETE_SELF: File "(null)" on WD #2 IGNORED: WD #2 Watching = 2
                items

Eliminemos file3. Tenga en cuenta que no obtendremos un evento IGNORED esta vez. ¿Por qué no? ¿Y por qué obtuvimos un evento ATTRIB por el file 3 (el cual originalmente era dir1/dir2/file1)?

Listado 16. Eliminación de file3
 ian@attic4:~/inotify-sample$
                rm file3 1 events queued ATTRIB: File "(null)" on WD #3

Recuerde que hemos creado un enlace duro desde file1 hasta file2. El Listado 17 muestra que todavía estamos monitoreando file2 en el descriptor de reloj 3, ¡aunque file 2 no estuviera cuando empezamos!

Listado 17. ¡Seguimos monitoreando file2!
                ian@attic4:~/inotify-sample$ touch dir1/file2 6 events queued
                OPEN: File "file2" on WD #1 OPEN: File "(null)" on WD #3 ATTRIB:
                File "file2" on WD #1 ATTRIB: File "(null)" on WD #3
                CLOSE_WRITE: File "file2" on WD #1 CLOSE_WRITE: File "(null)" on
                WD #3

Por lo tanto eliminemos dir1 y monitoreemos la cascada de eventos, la cual dará como resultado la terminación de nuestro programa porque ya no se está monitoreando nada.

Listado 18. Eliminación de dir1
 ian@attic4:~/inotify-sample$
                rm -rf dir1 8 events queued OPEN: Dir "(null)" on WD #1 ATTRIB:
                File "(null)" on WD #3 DELETE_SELF: File "(null)" on WD #3
                IGNORED: WD #3 Watching = 1 items DELETE: File "file2" on WD #1
                CLOSE_NOWRITE: Dir "(null)" on WD #1 DELETE_SELF: File "(null)"
                on WD #1 IGNORED: WD #1 Watching = 0 items Terminating

Los usos posibles de inotify

Usted puede utilizar inotify para muchos propósitos. Estas son algunas de las posibilidades:

El monitoreo de la performance
Quizá desee determinar cuáles son los archivos que abre una aplicación con mayor frecuencia. Si descubre que un pequeño archivo se abre y se cierra reiteradamente, quizá considere la posibilidad de utilizar una versión incorporada a la memoria, o modificar la aplicación de modo que los datos se compartan de alguna otra forma.
La metainformación
Quizá desee registrar la información adicional sobre los archivos, como por ejemplo el momento original de creación, o la id del usuario que modificó por última vez el archivo.
Seguridad
Quizá desee monitorear todos los accesos a un archivo o directorio particular por razones de seguridad.

Nuestro código de muestra observa todos los eventos e informa sobre todos ellos. En la práctica, quizá desee ver sólo un subconjunto determinado de eventos, según sus necesidades. Quizá desee también monitorear diferentes eventos en diferentes elementos monitoreados. Por ejemplo, quizá desee monitorear los eventos de apertura y cierre de archivos, pero sólo en los casos en los que ocurrieran eventos de creación o eliminación en los directorios. Siempre que sea posible, debería limitar los monitoreos sólo a los conjuntos más pequeños de eventos que le interesan.


Conclusión

Cuando se utiliza en áreas como el monitoreo de la performance, la eliminación de errores, y la automatización, inotify resulta un mecanismo poderoso y de alta precisión para el monitoreo de sistemas de archivos Linux. Utilice el código de muestra suministrado en este artículo para comenzar a escribir sus propias aplicaciones que respondan a eventos en sistemas de archivos o registren los mismos en tiempo real con mínimos gastos de performance.


Descargar

DescripciónNombretamaño
Sample code used in this articleinotify-sample.tgz4 KB

Recursos

Aprender

  • Event Management Best Practices (IBM Redbook, June de 2004) abarca la administración de eventos de forma amplia y profunda, especialmente la filtración, la duplicación, la eliminación, la correlación, la notificación, el escalamiento, la sincronización, la integración de formularios de incidencia, los modos de mantenimiento, y la automatización de eventos.
  • "Use autonomic computing for problem determination" (developerWorks, junio de 2004) describe cómo un sistema automático se puede utilizar para monitorear eventos y diagnosticar condiciones de error en un sistema de IT y suministrar acciones correlativas.
  • En la developerWorks Linux zone, encuentre cientos de how-to articles and tutorials, así como descargas, foros de discusión, y otros recursos ricos para los desarrolladores y administradores de Linux.
  • Manténgase al día con developerWorks technical events and webcasts especializados en una variedad de productos IBM y temas relacionados con la industria IT.
  • Asista a un free developerWorks Live! briefing para ponerse al día rápidamente sobre los productos y herramientas de IBM y sobre las tendencias de la industria IT.
  • Vea las developerWorks on-demand demos que van desde la intalación de productos y demostraciones de configuración para principiantes hasta las funcionalidades avanzadas para los desarrolladores con experiencia.
  • Siga developerWorks on Twitter.

Obtener los productos y tecnologías

  • Evaluate IBM products como más le convenga: descargue productos de prueba, pruebe productos en línea, use un producto en un entorno nube, o pase algunas horas en SOA Sandbox aprendiendo cómo implementear de manera eficaz la Service Oriented Architecture (Arquitectura orientada al servicio).

Comentar

  • Participe en My developerWorks community. Conéctese con otros usuarios de developerWorks mientras explora los blogs administrados por los desarrolladores, los foros, los grupos, y los wikis.

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Linux
ArticleID=619096
ArticleTitle=Monitoreo de eventos en sistemas de archivos con inotify
publish-date=01212011