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
6 #include <time.h> // for time()
8 #define _XOPEN_SOURCE 500
9 #define __USE_XOPEN_EXTENDED
10 #include <ftw.h> /* for nftw, tree walker */
12 #include "pnd_notify.h"
13 #include "pnd_pathiter.h"
16 int fd; // notify API file descriptor
19 static int notify_handle;
21 //static void pnd_notify_hookup ( int fd );
23 #define PND_INOTIFY_MASK IN_CREATE | IN_DELETE | IN_UNMOUNT \
24 | IN_DELETE_SELF | IN_MOVE_SELF \
25 | IN_MOVED_FROM | IN_MOVED_TO
27 pnd_notify_handle pnd_notify_init ( void ) {
37 p = malloc ( sizeof(pnd_notify_t) );
41 return ( NULL ); // uhh..
46 // setup some default watches
47 //pnd_notify_hookup ( fd );
52 void pnd_notify_shutdown ( pnd_notify_handle h ) {
53 pnd_notify_t *p = (pnd_notify_t*) h;
62 static int pnd_notify_callback ( const char *fpath, const struct stat *sb,
63 int typeflag, struct FTW *ftwbuf )
66 // only include directories
67 if ( ! ( typeflag & FTW_D ) ) {
68 return ( 0 ); // continue the tree walk
71 //printf ( "Implicitly watching dir '%s'\n", fpath );
73 inotify_add_watch ( notify_handle, fpath, PND_INOTIFY_MASK );
75 return ( 0 ); // continue the tree walk
78 void pnd_notify_watch_path ( pnd_notify_handle h, char *fullpath, unsigned int flags ) {
79 pnd_notify_t *p = (pnd_notify_t*) h;
82 inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK );
84 inotify_add_watch ( p -> fd, fullpath, IN_ALL_EVENTS );
87 if ( flags & PND_NOTIFY_RECURSE ) {
89 notify_handle = p -> fd;
91 nftw ( fullpath, // path to descend
92 pnd_notify_callback, // callback to do processing
93 10, // no more than X open fd's at once
94 FTW_PHYS ); // do not follow symlinks
104 static void pnd_notify_hookup ( int fd ) {
106 inotify_add_watch ( fd, "./testdata", IN_CREATE | IN_DELETE | IN_UNMOUNT );
107 inotify_add_watch ( fd, "/media", IN_CREATE | IN_DELETE | IN_UNMOUNT );
113 unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) {
114 pnd_notify_t *p = (pnd_notify_t*) h;
120 // don't block for long..
122 //t.tv_usec = 0; //5000;
126 // only for our useful fd
128 FD_SET ( (p->fd), &rfds );
131 retcode = select ( (p->fd) + 1, &rfds, NULL, NULL, &t );
134 return ( 0 ); // hmm.. need a better error code handler
135 } else if ( retcode == 0 ) {
136 return ( 0 ); // timeout
139 if ( ! FD_ISSET ( (p->fd), &rfds ) ) {
143 // by this point, something must have happened on our watch
144 #define BINBUFLEN ( 100 * ( sizeof(struct inotify_event) + 30 ) ) /* approx 100 events in a shot? */
145 unsigned char binbuf [ BINBUFLEN ];
148 actuallen = read ( (p->fd), binbuf, BINBUFLEN );
150 if ( actuallen < 0 ) {
151 return ( 0 ); // error
152 } else if ( actuallen == 0 ) {
153 return ( 0 ); // nothing, or overflow, or .. whatever.
157 struct inotify_event *e;
159 while ( i < actuallen ) {
160 e = (struct inotify_event *) &binbuf [ i ];
166 //printf ( "Got event against '%s'\n", e -> name );
173 i += ( sizeof(struct inotify_event) + e -> len );
179 #define _INOTIFY_TEST_PATH "/tmp/.notifytest"
180 #define _INOTIFY_TEST_FILE "/tmp/.notifytest/foopanda"
181 static unsigned char _inotify_test_run ( void ) {
185 int wd; // watch-descriptor
188 fdt.fd = inotify_init();
191 return ( 0 ); // failed to init at all
195 mkdir ( _INOTIFY_TEST_PATH, 0777 ); // if it fails we assume it exists, which is fine
198 if ( ( wd = inotify_add_watch ( fdt.fd, _INOTIFY_TEST_PATH, IN_DELETE ) ) < 0 ) {
199 return ( 0 ); // couldn't watch dir
202 // sleep a sec, just to be safe; seems to dislike being called immediately sometimes
203 usleep ( 1000000 / 2 );
205 // create a temp file
207 if ( ! ( f = fopen ( _INOTIFY_TEST_FILE, "w" ) ) ) {
209 return ( 0 ); // couldn't create test file?!
214 // delete the temp file; this should trigger an event
215 if ( unlink ( _INOTIFY_TEST_FILE ) < 0 ) {
216 return ( 0 ); // couldn't rm a file? life is harsh.
219 // did we get anything?
221 s = pnd_notify_rediscover_p ( &fdt );
230 /* we've run into the issue where inotify returns that it is set up, but in
231 * fact is not doing anything; restarting the process repairs it.. so here
232 * we devise a wank that continually tests inotify until it responds, then
233 * returns knowing we're good
235 unsigned char pnd_notify_wait_until_ready ( unsigned int secs_timeout ) {
236 time_t start = time ( NULL );
238 while ( ( secs_timeout == 0 ) ||
239 ( time ( NULL ) - start < secs_timeout ) )
241 if ( _inotify_test_run() ) {
244 usleep ( 1000000 / 2 );
247 return ( 0 ); // fail