Mostly changes to pndnotify, to facilitate HUP to reload conf, and to add watches...
[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   free ( p );
57
58   return;
59 }
60
61 static int pnd_notify_callback ( const char *fpath, const struct stat *sb,
62                                  int typeflag, struct FTW *ftwbuf )
63 {
64
65   // only include directories
66   if ( ! ( typeflag & FTW_D ) ) {
67     return ( 0 ); // continue the tree walk
68   }
69
70   //printf ( "Implicitly watching dir '%s'\n", fpath );
71
72   inotify_add_watch ( notify_handle, fpath, PND_INOTIFY_MASK );
73
74   return ( 0 ); // continue the tree walk
75 }
76
77 void pnd_notify_watch_path ( pnd_notify_handle h, char *fullpath, unsigned int flags ) {
78   pnd_notify_t *p = (pnd_notify_t*) h;
79
80 #if 1
81   inotify_add_watch ( p -> fd, fullpath, PND_INOTIFY_MASK );
82 #else
83   inotify_add_watch ( p -> fd, fullpath, IN_ALL_EVENTS );
84 #endif
85
86   if ( flags & PND_NOTIFY_RECURSE ) {
87
88     notify_handle = p -> fd;
89
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
94
95     notify_handle = -1;
96
97   } // recurse
98
99   return;
100 }
101
102 static void pnd_notify_hookup ( int fd ) {
103
104   inotify_add_watch ( fd, "./testdata", IN_CREATE | IN_DELETE | IN_UNMOUNT );
105
106   return;
107 }
108
109 unsigned char pnd_notify_rediscover_p ( pnd_notify_handle h ) {
110   pnd_notify_t *p = (pnd_notify_t*) h;
111
112   struct timeval t;
113   fd_set rfds;
114   int retcode;
115
116   // don't block for long..
117   //t.tv_sec = 1;
118   //t.tv_usec = 0; //5000;
119   t.tv_sec = 0;
120   t.tv_usec = 5000;
121
122   // only for our useful fd
123   FD_ZERO ( &rfds );
124   FD_SET ( (p->fd), &rfds );
125
126   // wait and test
127   retcode = select ( (p->fd) + 1, &rfds, NULL, NULL, &t );
128
129   if ( retcode < 0 ) {
130     return ( 0 ); // hmm.. need a better error code handler
131   } else if ( retcode == 0 ) {
132     return ( 0 ); // timeout
133   }
134
135   if ( ! FD_ISSET ( (p->fd), &rfds ) ) {
136     return ( 0 );
137   }
138
139   // by this point, something must have happened on our watch
140 #define BINBUFLEN ( 100 * ( sizeof(struct inotify_event) + 30 ) ) /* approx 100 events in a shot? */
141   unsigned char binbuf [ BINBUFLEN ];
142   int actuallen;
143
144   actuallen = read ( (p->fd), binbuf, BINBUFLEN );
145
146   if ( actuallen < 0 ) {
147     return ( 0 ); // error
148   } else if ( actuallen == 0 ) {
149     return ( 0 ); // nothing, or overflow, or .. whatever.
150   }
151
152   unsigned int i;
153   struct inotify_event *e;
154
155   while ( i < actuallen ) {
156     e = (struct inotify_event *) &binbuf [ i ];
157
158     /* do it!
159      */
160
161     if ( e -> len ) {
162       //printf ( "Got event against '%s'\n", e -> name );
163     }
164
165     /* do it!
166      */
167
168     // next
169     i += ( sizeof(struct inotify_event) + e -> len );
170   } // while
171
172   return ( 1 );
173 }