#include <stdio.h> // for stdio, NULL
#include <stdlib.h> // for malloc, etc
#include <unistd.h> // for close
+#include <errno.h> // for errno
+#include <time.h> // for time()
#define _XOPEN_SOURCE 500
#define __USE_XOPEN_EXTENDED
#include "pnd_notify.h"
#include "pnd_pathiter.h"
+#include "pnd_logger.h"
typedef struct {
int fd; // notify API file descriptor
static int notify_handle;
-static void pnd_notify_hookup ( int fd );
+//static void pnd_notify_hookup ( int fd );
-#define PND_INOTIFY_MASK IN_CREATE | IN_DELETE | IN_UNMOUNT \
+#if 1
+#define PND_INOTIFY_MASK IN_DELETE | IN_UNMOUNT \
| IN_DELETE_SELF | IN_MOVE_SELF \
- | IN_MOVED_FROM | IN_MOVED_TO
+ | IN_MOVED_FROM | IN_MOVED_TO | IN_CLOSE_WRITE
+#else
+#define PND_INOTIFY_MASK IN_ALL_EVENTS
+#endif
pnd_notify_handle pnd_notify_init ( void ) {
int fd;
p -> fd = fd;
// setup some default watches
- pnd_notify_hookup ( fd );
+ //pnd_notify_hookup ( fd );
return ( p );
}
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;
-#if 1
inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK );
-#else
- inotify_add_watch ( p -> fd, fullpath, IN_ALL_EVENTS );
-#endif
if ( flags & PND_NOTIFY_RECURSE ) {
return;
}
+#if 0
static void pnd_notify_hookup ( int fd ) {
inotify_add_watch ( fd, "./testdata", 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;
retcode = select ( (p->fd) + 1, &rfds, NULL, NULL, &t );
if ( retcode < 0 ) {
+ pnd_log ( 3, "ERROR: notify: select failed: %d\n", errno );
return ( 0 ); // hmm.. need a better error code handler
} else if ( retcode == 0 ) {
return ( 0 ); // timeout
actuallen = read ( (p->fd), binbuf, BINBUFLEN );
if ( actuallen < 0 ) {
+ pnd_log ( 3, "ERROR: notify: read failed: %d\n", errno );
return ( 0 ); // error
} else if ( actuallen == 0 ) {
return ( 0 ); // nothing, or overflow, or .. whatever.
}
- unsigned int i;
+ unsigned int i = 0;
struct inotify_event *e;
while ( i < actuallen ) {
/* 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!
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
+}
+
+int pnd_notify_fd ( pnd_notify_handle h ) {
+ pnd_notify_t *p = (pnd_notify_t*) h;
+ int r = -1;
+
+ if ( p )
+ r = p->fd;
+
+ return r;
+}