00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020 #include "pnotify.h"
00021 #include "pnotify-internal.h"
00022
00029 #if HAVE_INOTIFY
00030
00031 #include <sys/epoll.h>
00032 #include <sys/inotify.h>
00033
00034 static int INOTIFY_FD = -1;
00035 static int EPOLL_FD = -1;
00036
00037 int _get_inotify_event(struct pnotify_event *evt, struct pnotify_ctx *ctx);
00038
00039 void linux_dump_inotify_event(struct inotify_event *iev);
00040
00041
00042 void *
00043 linux_inotify_loop(void * unused)
00044 {
00045 struct pn_watch *watch;
00046 struct pnotify_event *evt;
00047 struct inotify_event *iev, *endp;
00048 ssize_t bytes;
00049 char buf[4096];
00050
00051
00052 watch = unused;
00053
00054
00055 if ((INOTIFY_FD = inotify_init()) < 0)
00056 err(1, "inotify_init(2)");
00057
00058
00059 for (;;) {
00060
00061
00062
00063
00064
00065 bytes = read(INOTIFY_FD, &buf, sizeof(buf));
00066 if (bytes <= 0)
00067 err(1, "read(2)");
00068
00069
00070 iev = (struct inotify_event *) & buf;
00071 endp = iev + bytes;
00072
00073
00074 while (iev < endp) {
00075
00076 if (iev->wd == 0)
00077 break;
00078
00079
00080 if (iev->mask & IN_IGNORED)
00081 goto next_event;
00082
00083
00084
00085
00086
00087
00088 if ((watch = pn_get_watch_by_id(iev->wd)) == NULL) {
00089 warnx("watch # %d not found\n", iev->wd);
00090 linux_dump_inotify_event(iev);
00091 continue;
00092 }
00093
00094
00095 if ((evt = calloc(1, sizeof(*evt))) == NULL)
00096 err(1, "malloc failed");
00097
00098 evt->watch = watch;
00099 (void) strncpy(evt->name, iev->name, iev->len);
00100 if (iev->mask & IN_ATTRIB)
00101 evt->mask |= PN_ATTRIB;
00102 if (iev->mask & IN_MODIFY)
00103 evt->mask |= PN_MODIFY;
00104 if (iev->mask & IN_CREATE)
00105 evt->mask |= PN_CREATE;
00106 if (iev->mask & IN_DELETE)
00107 evt->mask |= PN_DELETE;
00108 if (iev->mask & IN_DELETE_SELF) {
00109 evt->mask |= PN_DELETE;
00110 (void) strncpy(evt->name, "", 0);
00111 }
00112
00113
00114 pn_event_add(watch->ctx, evt);
00115
00116 next_event:
00117
00118 iev += sizeof(*iev) + iev->len;
00119 }
00120 }
00121
00122 close(INOTIFY_FD);
00123 return NULL;
00124 }
00125
00126
00127 void *
00128 linux_epoll_loop(void * unused)
00129 {
00130 static const int maxevents = 100;
00131 struct pnotify_event *evt;
00132 struct pn_watch *watch;
00133 struct epoll_event events[maxevents];
00134 int i, numevents;
00135
00136
00137 watch = unused;
00138
00139
00140 if ((EPOLL_FD = epoll_create(1000)) < 0)
00141 err(1, "epoll_create(2)");
00142
00143
00144 for (;;) {
00145
00146
00147 numevents = epoll_wait(EPOLL_FD,
00148 (struct epoll_event *) &events, maxevents, -1);
00149 if (numevents < 0) {
00150 if (errno == EINTR)
00151 continue;
00152 err(1, "epoll_wait(2)");
00153 }
00154
00155
00156 for (i = 0; i < numevents; i++) {
00157
00158 watch = (struct pn_watch *) events[i].data.ptr;
00159
00160 #if DEAD
00161
00162 pthread_mutex_lock(&SIGNAL_CTX_MUTEX);
00163 ctx = SIGNAL_CTX[signum];
00164 pthread_mutex_unlock(&SIGNAL_CTX_MUTEX);
00165 if (!ctx) {
00166 default_signal_handler(signum);
00167 continue;
00168 }
00169 #endif
00170
00171
00172 if ((evt = calloc(1, sizeof(*evt))) == NULL)
00173 err(1, "calloc(3)");
00174 evt->watch = watch;
00175 evt->mask = 0;
00176 if (events[i].events & EPOLLIN)
00177 evt->mask |= PN_READ;
00178 if (events[i].events & EPOLLOUT)
00179 evt->mask |= PN_WRITE;
00180 if (events[i].events & EPOLLHUP)
00181 evt->mask |= PN_CLOSE;
00182 if (events[i].events & EPOLLERR)
00183 evt->mask |= PN_ERROR;
00184
00185
00186 pn_event_add(watch->ctx, evt);
00187 }
00188 }
00189
00190 close(EPOLL_FD);
00191 return NULL;
00192 }
00193
00194
00195 void
00196 linux_init_once(void)
00197 {
00198 pthread_t tid;
00199
00200
00201 if (pthread_create( &tid, NULL, linux_epoll_loop, NULL ) != 0)
00202 errx(1, "pthread_create(3) failed");
00203
00204
00205 if (pthread_create( &tid, NULL, linux_inotify_loop, NULL ) != 0)
00206 errx(1, "pthread_create(3) failed");
00207
00208
00209 }
00210
00211
00212 void
00213 linux_cleanup(void)
00214 {
00215 (void) close(INOTIFY_FD);
00216 }
00217
00218
00219 int
00220 linux_add_watch(struct pn_watch *watch)
00221 {
00222 struct epoll_event *ev = &watch->epoll_evt;
00223 int mask = watch->mask;
00224 uint32_t imask = 0;
00225
00226 switch (watch->type) {
00227
00228 case WATCH_FD:
00229
00230 ev->events = EPOLLET;
00231 if (mask & PN_READ)
00232 ev->events |= EPOLLIN;
00233 if (mask & PN_WRITE)
00234 ev->events |= EPOLLOUT;
00235 ev->data.ptr = watch;
00236
00237
00238 if (epoll_ctl(EPOLL_FD, EPOLL_CTL_ADD, watch->ident.fd, ev) < 0) {
00239 warn("epoll_ctl(2) failed");
00240 return -1;
00241 }
00242 break;
00243
00244 case WATCH_VNODE:
00245
00246 if (mask & PN_ATTRIB)
00247 imask |= IN_ATTRIB;
00248 if (mask & PN_CREATE)
00249 imask |= IN_CREATE;
00250 if (mask & PN_DELETE)
00251 imask |= IN_DELETE | IN_DELETE_SELF;
00252 if (mask & PN_MODIFY)
00253 imask |= IN_MODIFY;
00254 if (mask & PN_ONESHOT)
00255 imask |= IN_ONESHOT;
00256
00257
00258
00259 watch->wd = inotify_add_watch(INOTIFY_FD, watch->ident.path, imask);
00260 if (watch->wd < 0) {
00261 perror("inotify_add_watch(2) failed");
00262 return -1;
00263 }
00264 break;
00265
00266 default:
00267
00268 break;
00269 }
00270
00271 return 0;
00272 }
00273
00274 int
00275 linux_rm_watch(struct pn_watch *watch)
00276 {
00277 if (inotify_rm_watch(INOTIFY_FD, watch->wd) < 0) {
00278 perror("inotify_rm_watch(2)");
00279 return -1;
00280 }
00281
00282 return 0;
00283 }
00284
00285 int
00286 _get_inotify_event(struct pnotify_event *evt, struct pnotify_ctx *ctx)
00287 {
00288
00289
00290 return 0;
00291 }
00292
00293 int
00294 linux_trap_signal(struct pnotify_ctx *ctx, int signum)
00295 {
00296
00297
00298
00299
00300 assert(ctx && signum);
00301 return 0;
00302 }
00303
00304 void
00305 linux_dump_inotify_event(struct inotify_event *iev)
00306 {
00307 static const char *nam[] = {
00308 "IN_ACCESS", "IN_MODIFY", "IN_ATTRIB", "IN_CLOSE_WRITE",
00309 "IN_CLOSE_NOWRITE", "IN_OPEN", "IN_MOVED_FROM",
00310 "IN_MOVED_TO", "IN_CREATE", "IN_DELETE", "IN_DELETE_SELF",
00311 "IN_MOVE_SELF", "IN_UNMOUNT", "IN_Q_OVERFLOW", "IN_IGNORED",
00312 "IN_ONLYDIR", "IN_DONT_FOLLOW", "IN_MASK_ADD", "IN_ISDIR",
00313 "IN_ONESHOT", NULL };
00314 static const int val[] = {
00315 IN_ACCESS, IN_MODIFY, IN_ATTRIB, IN_CLOSE_WRITE,
00316 IN_CLOSE_NOWRITE, IN_OPEN, IN_MOVED_FROM,
00317 IN_MOVED_TO, IN_CREATE, IN_DELETE, IN_DELETE_SELF,
00318 IN_MOVE_SELF, IN_UNMOUNT, IN_Q_OVERFLOW, IN_IGNORED,
00319 IN_ONLYDIR, IN_DONT_FOLLOW, IN_MASK_ADD, IN_ISDIR,
00320 IN_ONESHOT, 0 };
00321 int i;
00322
00323 fprintf(stderr, "inotify event: wd=%d mask=", iev->wd);
00324 for (i = 0; val[i] != 0; i++) {
00325 if (iev->mask & val[i])
00326 fprintf(stderr, "%s ", nam[i]);
00327 }
00328 fprintf(stderr, "\n");
00329 }
00330
00331 const struct pnotify_vtable LINUX_VTABLE = {
00332 .init_once = linux_init_once,
00333 .add_watch = linux_add_watch,
00334 .rm_watch = linux_rm_watch,
00335 .cleanup = linux_cleanup,
00336 };
00337
00338 #endif
00339