X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fpnd_notify.c;h=9c377c7638c12d727d09fa5350a861f906252fd2;hb=36af8dacb33edc9307d08a2918166c7cf77d72af;hp=0c99458d96c9fc78bbda2a768c0d4600253c384e;hpb=e6523064950059e3e4fb7c2c6a15e0a42c1106e3;p=pandora-libraries.git diff --git a/lib/pnd_notify.c b/lib/pnd_notify.c index 0c99458..9c377c7 100644 --- a/lib/pnd_notify.c +++ b/lib/pnd_notify.c @@ -3,14 +3,31 @@ #include // for stdio, NULL #include // for malloc, etc #include // for close +#include // for time() + +#define _XOPEN_SOURCE 500 +#define __USE_XOPEN_EXTENDED +#include /* for nftw, tree walker */ #include "pnd_notify.h" +#include "pnd_pathiter.h" +#include "pnd_logger.h" typedef struct { int fd; // notify API file descriptor } pnd_notify_t; -static void pnd_notify_hookup ( int fd ); +static int notify_handle; + +//static void pnd_notify_hookup ( int fd ); + +#if 1 +#define PND_INOTIFY_MASK IN_CREATE | IN_DELETE | IN_UNMOUNT \ + | IN_DELETE_SELF | IN_MOVE_SELF \ + | IN_MOVED_FROM | IN_MOVED_TO | IN_MODIFY +#else +#define PND_INOTIFY_MASK IN_ALL_EVENTS +#endif pnd_notify_handle pnd_notify_init ( void ) { int fd; @@ -32,7 +49,7 @@ pnd_notify_handle pnd_notify_init ( void ) { p -> fd = fd; // setup some default watches - pnd_notify_hookup ( fd ); + //pnd_notify_hookup ( fd ); return ( p ); } @@ -42,15 +59,61 @@ void pnd_notify_shutdown ( pnd_notify_handle h ) { close ( p -> fd ); + free ( p ); + + return; +} + +static int pnd_notify_callback ( const char *fpath, const struct stat *sb, + int typeflag, struct FTW *ftwbuf ) +{ + + // only include directories + if ( ! ( typeflag & FTW_D ) ) { + return ( 0 ); // continue the tree walk + } + + //printf ( "Implicitly watching dir '%s'\n", fpath ); + + inotify_add_watch ( notify_handle, fpath, PND_INOTIFY_MASK ); + + if ( pnd_log_do_buried_logging() ) { + pnd_log ( PND_LOG_DEFAULT, "notify callback: added watch on %s\n", fpath ); + } + + return ( 0 ); // continue the tree walk +} + +void pnd_notify_watch_path ( pnd_notify_handle h, char *fullpath, unsigned int flags ) { + pnd_notify_t *p = (pnd_notify_t*) h; + + inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK ); + + if ( flags & PND_NOTIFY_RECURSE ) { + + notify_handle = p -> fd; + + nftw ( fullpath, // path to descend + pnd_notify_callback, // callback to do processing + 10, // no more than X open fd's at once + FTW_PHYS ); // do not follow symlinks + + notify_handle = -1; + + } // recurse + return; } +#if 0 static void pnd_notify_hookup ( int fd ) { inotify_add_watch ( fd, "./testdata", IN_CREATE | IN_DELETE | IN_UNMOUNT ); + inotify_add_watch ( fd, "/media", IN_CREATE | IN_DELETE | IN_UNMOUNT ); return; } +#endif unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) { pnd_notify_t *p = (pnd_notify_t*) h; @@ -60,8 +123,10 @@ unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) { int retcode; // don't block for long.. - t.tv_sec = 1; - t.tv_usec = 0; //5000; + //t.tv_sec = 1; + //t.tv_usec = 0; //5000; + t.tv_sec = 0; + t.tv_usec = 5000; // only for our useful fd FD_ZERO ( &rfds ); @@ -93,7 +158,7 @@ unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) { return ( 0 ); // nothing, or overflow, or .. whatever. } - unsigned int i; + unsigned int i = 0; struct inotify_event *e; while ( i < actuallen ) { @@ -102,8 +167,8 @@ unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) { /* do it! */ - if ( e -> len ) { - printf ( "Got event against '%s'\n", e -> name ); + if ( pnd_log_do_buried_logging() ) { + pnd_log ( PND_LOG_DEFAULT, "notify: Got event against '%s' [%u %x]\n", e -> name, e -> mask, e -> mask ); } /* do it! @@ -115,3 +180,74 @@ unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) { return ( 1 ); } + +#define _INOTIFY_TEST_PATH "/tmp/.notifytest" +#define _INOTIFY_TEST_FILE "/tmp/.notifytest/foopanda" +static unsigned char _inotify_test_run ( void ) { + + // set up inotify + pnd_notify_t fdt; + int wd; // watch-descriptor + + // set up inotify + fdt.fd = inotify_init(); + + if ( fdt.fd < 0 ) { + return ( 0 ); // failed to init at all + } + + // make a temp dir + mkdir ( _INOTIFY_TEST_PATH, 0777 ); // if it fails we assume it exists, which is fine + + // watch the dir + if ( ( wd = inotify_add_watch ( fdt.fd, _INOTIFY_TEST_PATH, IN_DELETE ) ) < 0 ) { + return ( 0 ); // couldn't watch dir + } + + // sleep a sec, just to be safe; seems to dislike being called immediately sometimes + usleep ( 1000000 / 2 ); + + // create a temp file + FILE *f; + if ( ! ( f = fopen ( _INOTIFY_TEST_FILE, "w" ) ) ) { + close ( fdt.fd ); + return ( 0 ); // couldn't create test file?! + } + + fclose ( f ); + + // delete the temp file; this should trigger an event + if ( unlink ( _INOTIFY_TEST_FILE ) < 0 ) { + return ( 0 ); // couldn't rm a file? life is harsh. + } + + // did we get anything? + unsigned char s; + s = pnd_notify_rediscover_p ( &fdt ); + + // ditch inotify + close ( fdt.fd ); + + // success + return ( s ); +} + +/* we've run into the issue where inotify returns that it is set up, but in + * fact is not doing anything; restarting the process repairs it.. so here + * we devise a wank that continually tests inotify until it responds, then + * returns knowing we're good + */ +unsigned char pnd_notify_wait_until_ready ( unsigned int secs_timeout ) { + time_t start = time ( NULL ); + + while ( ( secs_timeout == 0 ) || + ( time ( NULL ) - start < secs_timeout ) ) + { + if ( _inotify_test_run() ) { + return ( 1 ); + } + usleep ( 1000000 / 2 ); + } + + return ( 0 ); // fail +}