2 #include <sys/inotify.h> // for INOTIFY duh
3 #include <stdio.h> // for stdio, NULL
4 #include <stdlib.h> // for malloc, etc
5 #include <unistd.h> // for close
7 #define _XOPEN_SOURCE 500
8 #define __USE_XOPEN_EXTENDED
9 #include <ftw.h> /* for nftw, tree walker */
11 #include "pnd_notify.h"
12 #include "pnd_pathiter.h"
15 int fd; // notify API file descriptor
18 static int notify_handle;
20 static void pnd_notify_hookup ( int fd );
22 #define PND_INOTIFY_MASK IN_CREATE | IN_DELETE | IN_UNMOUNT \
23 | IN_DELETE_SELF | IN_MOVE_SELF \
24 | IN_MOVED_FROM | IN_MOVED_TO
26 pnd_notify_handle pnd_notify_init ( void ) {
36 p = malloc ( sizeof(pnd_notify_t) );
40 return ( NULL ); // uhh..
45 // setup some default watches
46 pnd_notify_hookup ( fd );
51 void pnd_notify_shutdown ( pnd_notify_handle h ) {
52 pnd_notify_t *p = (pnd_notify_t*) h;
61 static int pnd_notify_callback ( const char *fpath, const struct stat *sb,
62 int typeflag, struct FTW *ftwbuf )
65 // only include directories
66 if ( ! ( typeflag & FTW_D ) ) {
67 return ( 0 ); // continue the tree walk
70 //printf ( "Implicitly watching dir '%s'\n", fpath );
72 inotify_add_watch ( notify_handle, fpath, PND_INOTIFY_MASK );
74 return ( 0 ); // continue the tree walk
77 void pnd_notify_watch_path ( pnd_notify_handle h, char *fullpath, unsigned int flags ) {
78 pnd_notify_t *p = (pnd_notify_t*) h;
81 inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK );
83 inotify_add_watch ( p -> fd, fullpath, IN_ALL_EVENTS );
86 if ( flags & PND_NOTIFY_RECURSE ) {
88 notify_handle = p -> fd;
90 nftw ( fullpath, // path to descend
91 pnd_notify_callback, // callback to do processing
92 10, // no more than X open fd's at once
93 FTW_PHYS ); // do not follow symlinks
102 static void pnd_notify_hookup ( int fd ) {
104 inotify_add_watch ( fd, "./testdata", IN_CREATE | IN_DELETE | IN_UNMOUNT );
105 inotify_add_watch ( fd, "/media", IN_CREATE | IN_DELETE | IN_UNMOUNT );
110 unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) {
111 pnd_notify_t *p = (pnd_notify_t*) h;
117 // don't block for long..
119 //t.tv_usec = 0; //5000;
123 // only for our useful fd
125 FD_SET ( (p->fd), &rfds );
128 retcode = select ( (p->fd) + 1, &rfds, NULL, NULL, &t );
131 return ( 0 ); // hmm.. need a better error code handler
132 } else if ( retcode == 0 ) {
133 return ( 0 ); // timeout
136 if ( ! FD_ISSET ( (p->fd), &rfds ) ) {
140 // by this point, something must have happened on our watch
141 #define BINBUFLEN ( 100 * ( sizeof(struct inotify_event) + 30 ) ) /* approx 100 events in a shot? */
142 unsigned char binbuf [ BINBUFLEN ];
145 actuallen = read ( (p->fd), binbuf, BINBUFLEN );
147 if ( actuallen < 0 ) {
148 return ( 0 ); // error
149 } else if ( actuallen == 0 ) {
150 return ( 0 ); // nothing, or overflow, or .. whatever.
154 struct inotify_event *e;
156 while ( i < actuallen ) {
157 e = (struct inotify_event *) &binbuf [ i ];
163 //printf ( "Got event against '%s'\n", e -> name );
170 i += ( sizeof(struct inotify_event) + e -> len );
176 /* we've run into the issue where inotify returns that it is set up, but in
177 * fact is not doing anything; restarting the process repairs it.. so here
178 * we devise a wank that continually tests inotify until it responds, then
179 * returns knowing we're good
181 unsigned char pnd_notify_wait_until_ready ( unsigned int secs_timeout ) {
182 return ( 0 ); // fail
185 static unsigned char _inotify_test_run ( void ) {
193 return ( 0 ); // failed to init at all