1 What’s inotify
The inotify API provides a mechanism for monitoring file system events. Inotify can be used to monitor individual files, or to monitor directories. When a directory is monitored, inotify will return events for the directory itself, and for files inside the directory.
2 How to use inotify
2.1 system calls used with this API
The following system calls are used with this API: inotify_init(orinotify_init1), inotify_add_watch, inotify_rm_watch,read, and close.
2.1.1 inotify_initIt creates an inotify instance and returns a file descriptor referring to the inotify instance. The more recent inotify_init1is like inotify_init, but provides some extra functionality.
2.1.2 inotify_add_watch
It manipulates the "watch list" associated with an inotify instance. Each item ("watch") in the watch list specifies the pathname of a file or directory, along with some set of events that the kernel should monitor for the file referred to by that pathname.
inotify_add_watcheither creates a new watch item, or modifies an existing watch. Each watch has a unique "watch descriptor", an integer returned byinotify_add_watchwhen the watch is created.
2.1.3inotify_rm_watch
It removes an item from an inotify watch list.
When all file descriptors referring to an inotify instance have been closed, the underlying object and its resources are freed for reuse by the kernel; all associated watches are automatically freed.
2.1.4 read
To determine what events have occurred, an applicationreads from the inotify file descriptor. If no events have so far occurred, then, assuming a blocking file descriptor,readwill block until at least one event occurs (unless interrupted by a signal, in which case the call fails with the error EINTR; seesignal(7)).
Each successful readreturns a buffer containing one or more of the following structures:
struct inotify_event {
int wd; /* Watch descriptor */
uint32_t mask; /* Mask of events */
uint32_t cookie; /* Unique cookie associating related events (forrename) */
uint32_t len; /* Size of name field */
char name[]; /* Optional null-terminated name */
};
2.2 Inotify events
Theinotify_add_watchmask argument and the mask field of the inotify_event structure returned whenreading an inotify file descriptor are both bit masks identifying inotify events. The following bits can be specified in mask when callinginotify_add_watchand may be returned in the mask field returned byread:
IN_ACCESSFile was accessed (read) (*).
IN_ATTRIBMetadata changed, e.g., permissions, timestamps, extended attributes, link count (since Linux 2.6.25), UID, GID, etc. (*).
IN_CLOSE_WRITEFile opened for writing was closed (*).
IN_CLOSE_NOWRITEFile not opened for writing was closed (*).
IN_CREATEFile/directory created in watched directory (*).
IN_DELETEFile/directory deleted from watched directory (*).
IN_DELETE_SELFWatched file/directory was itself deleted.
IN_MODIFYFile was modified (*).
IN_MOVE_SELFWatched file/directory was itself moved.
IN_MOVED_FROMFile moved out of watched directory (*).
IN_MOVED_TOFile moved into watched directory (*).
IN_OPENFile was opened (*).
……
2.3 The flow for the systme calls used with inotify
3 Example used with Inotify
3.1 Description:
There are three subfunctions below : input_run, worker_thread,worker_cleanup.
The subfunction "input_run" is called by the main function .when it’s called,the input_run will creat a thread "worker_thread". when the thread is exit it will call the "worker_cleanup".
In the worker_thread we monitor the folder “/temp”.If a file(here it’s a picture) is move to the folder, we open it ,copy it’s context to a frame buffer for using ,then we delete the file if necessary.
3.2 source code:
#include
#include
#include
#include
#include
/* global variables for this plugin */
static char*folder = /temp;
staticintfd, rc, wd, size;
staticstructinotify_event *ev;
intinput_run(intid)
{
pglobal->in[id].buf = NULL;
rc = fd = inotify_init();
if(rc == -1) {
perror("could not initilialize inotify");
return1;
}
rc = wd = inotify_add_watch(fd, folder, IN_CLOSE_WRITE | IN_MOVED_TO | IN_ONLYDIR);
if(rc == -1) {
perror("could not add watch");
return1;
}
size =sizeof(structinotify_event) + (1 << 16);
ev =malloc(size);
if(ev == NULL) {
perror("not enough memory");
return1;
}
if(pthread_create(&worker, 0, worker_thread, NULL) != 0) {
free(pglobal->in[id].buf);
fprintf(stderr,"could not start worker thread\n");
exit(EXIT_FAILURE);
}
pthread_detach(worker);
return0;
}
/* the single writer thread */
void*worker_thread(void*arg)
{
charbuffer[1<<16];
intfile;
size_t filesize = 0;
structstat stats;
/* set cleanup handler to cleanup allocated ressources */
pthread_cleanup_push(worker_cleanup, NULL);
while(!pglobal->stop) {
/* wait for new frame, read will block until something happens */
rc =read(fd, ev, size);
if(rc == -1) {
perror("reading inotify events failed");
break;
}
/* sanity check */
if(wd != ev->wd) {
fprintf(stderr,"This event is not for the watched directory (%d != %d)\n", wd, ev->wd);
continue;
}
if(ev->mask & (IN_IGNORED | IN_Q_OVERFLOW | IN_UNMOUNT)) {
fprintf(stderr,"event mask suggests to stop\n");
break;
}
/***************** your reaction to the enent******************/
/* prepare filename */
/* check if the filename matches specified parameter (if given)*/
/* open file for reading */
/* approximate size of file */
/* copy frame from file to global buffer */
pthread_mutex_lock(&pglobal->in[plugin_number].db);
/* allocate memory for frame */
/* signal fresh_frame */
pthread_cond_broadcast(&pglobal->in[plugin_number].db_update);
pthread_mutex_unlock(&pglobal->in[plugin_number].db);
/* close file */
/* delete file if necessary */
/***************** your reaction to the event*******************/
}
DBG("leaving input thread, calling cleanup function now\n");
/* call cleanup handler, signal with the parameter */
pthread_cleanup_pop(1);
returnNULL;
}
voidworker_cleanup(void*arg)
{
staticunsignedcharfirst_run = 1;
if(!first_run) {
DBG("already cleaned up ressources\n");
return;
}
first_run = 0;
DBG("cleaning up ressources allocated by input thread\n");
if(pglobal->in[plugin_number].buf != NULL)free(pglobal->in[plugin_number].buf);
free(ev);
rc = inotify_rm_watch(fd, wd);
if(rc == -1) {
perror("could not close watch descriptor");
}
rc =close(fd);
if(rc == -1) {
perror("could not close filedescriptor");
}
}