Added a 'flags' arg to pnd_apps_exec
[pandora-libraries.git] / lib / pnd_notify.c
1
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
7 #define _XOPEN_SOURCE 500
8 #define __USE_XOPEN_EXTENDED
9 #include <ftw.h> /* for nftw, tree walker */
10
11 #include "pnd_notify.h"
12 #include "pnd_pathiter.h"
13
14 typedef struct {
15   int fd;              // notify API file descriptor
16 } pnd_notify_t;
17
18 static int notify_handle;
19
20 static void pnd_notify_hookup ( int fd );
21
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
25
26 pnd_notify_handle pnd_notify_init ( void ) {
27   int fd;
28   pnd_notify_t *p;
29
30   fd = inotify_init();
31
32   if ( fd < 0 ) {
33     return ( NULL );
34   }
35
36   p = malloc ( sizeof(pnd_notify_t) );
37
38   if ( ! p ) {
39     close ( fd );
40     return ( NULL ); // uhh..
41   }
42
43   p -> fd = fd;
44
45   // setup some default watches
46   pnd_notify_hookup ( fd );
47
48   return ( p );
49 }
50
51 void pnd_notify_shutdown ( pnd_notify_handle h ) {
52   pnd_notify_t *p = (pnd_notify_t*) h;
53
54   close ( p -> fd );
55
56   return;
57 }
58
59 static int pnd_notify_callback ( const char *fpath, const struct stat *sb,
60                                  int typeflag, struct FTW *ftwbuf )
61 {
62
63   // only include directories
64   if ( ! ( typeflag & FTW_D ) ) {
65     return ( 0 ); // continue the tree walk
66   }
67
68   //printf ( "Implicitly watching dir '%s'\n", fpath );
69
70   inotify_add_watch ( notify_handle, fpath, PND_INOTIFY_MASK );
71
72   return ( 0 ); // continue the tree walk
73 }
74
75 void pnd_notify_watch_path ( pnd_notify_handle h, char *fullpath, unsigned int flags ) {
76   pnd_notify_t *p = (pnd_notify_t*) h;
77
78 #if 1
79   inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK );
80 #else
81   inotify_add_watch ( p -> fd, fullpath, IN_ALL_EVENTS );
82 #endif
83
84   if ( flags & PND_NOTIFY_RECURSE ) {
85
86     notify_handle = p -> fd;
87
88     nftw ( fullpath,             // path to descend
89            pnd_notify_callback,  // callback to do processing
90            10,                   // no more than X open fd's at once
91            FTW_PHYS );           // do not follow symlinks
92
93     notify_handle = -1;
94
95   } // recurse
96
97   return;
98 }
99
100 static void pnd_notify_hookup ( int fd ) {
101
102   inotify_add_watch ( fd, "./testdata", IN_CREATE | IN_DELETE | IN_UNMOUNT );
103
104   return;
105 }
106
107 unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) {
108   pnd_notify_t *p = (pnd_notify_t*) h;
109
110   struct timeval t;
111   fd_set rfds;
112   int retcode;
113
114   // don't block for long..
115   //t.tv_sec = 1;
116   //t.tv_usec = 0; //5000;
117   t.tv_sec = 0;
118   t.tv_usec = 5000;
119
120   // only for our useful fd
121   FD_ZERO ( &rfds );
122   FD_SET ( (p->fd), &rfds );
123
124   // wait and test
125   retcode = select ( (p->fd) + 1, &rfds, NULL, NULL, &t );
126
127   if ( retcode < 0 ) {
128     return ( 0 ); // hmm.. need a better error code handler
129   } else if ( retcode == 0 ) {
130     return ( 0 ); // timeout
131   }
132
133   if ( ! FD_ISSET ( (p->fd), &rfds ) ) {
134     return ( 0 );
135   }
136
137   // by this point, something must have happened on our watch
138 #define BINBUFLEN ( 100 * ( sizeof(struct inotify_event) + 30 ) ) /* approx 100 events in a shot? */
139   unsigned char binbuf [ BINBUFLEN ];
140   int actuallen;
141
142   actuallen = read ( (p->fd), binbuf, BINBUFLEN );
143
144   if ( actuallen < 0 ) {
145     return ( 0 ); // error
146   } else if ( actuallen == 0 ) {
147     return ( 0 ); // nothing, or overflow, or .. whatever.
148   }
149
150   unsigned int i;
151   struct inotify_event *e;
152
153   while ( i < actuallen ) {
154     e = (struct inotify_event *) &binbuf [ i ];
155
156     /* do it!
157      */
158
159     if ( e -> len ) {
160       //printf ( "Got event against '%s'\n", e -> name );
161     }
162
163     /* do it!
164      */
165
166     // next
167     i += ( sizeof(struct inotify_event) + e -> len );
168   } // while
169
170   return ( 1 );
171 }