Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib/ioloop-notify-inotify.c @ 5248:12ac5f685814 HEAD
Various cleanups to ioloop code.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 09 Mar 2007 00:04:21 +0200 |
parents | b4adc5bc7f2b |
children | 498ef9bc33f1 |
line wrap: on
line source
/* Copyright (C) 2005-2007 Johannes Berg, Timo Sirainen */ #define _GNU_SOURCE #include "lib.h" #ifdef IOLOOP_NOTIFY_INOTIFY #include "fd-close-on-exec.h" #include "ioloop-internal.h" #include "ioloop-notify-fd.h" #include "buffer.h" #include "network.h" #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/inotify.h> #define INOTIFY_BUFLEN (32*1024) struct ioloop_notify_handler_context { struct ioloop_notify_fd_context fd_ctx; int inotify_fd; struct io *event_io; bool disabled; }; static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void); static bool inotify_input_more(struct ioloop *ioloop) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; const struct inotify_event *event; unsigned char event_buf[INOTIFY_BUFLEN]; struct io_notify *io; ssize_t ret, pos; /* read as many events as there is available and fit into our buffer. only full events are returned by the kernel. */ ret = read(ctx->inotify_fd, event_buf, sizeof(event_buf)); if (ret <= 0) { if (ret == 0) { /* nothing more to read */ return FALSE; } i_fatal("read(inotify) failed: %m"); } if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0) i_fatal("gettimeofday(): %m"); ioloop_time = ioloop_timeval.tv_sec; for (pos = 0; pos < ret; ) { if ((size_t)(ret - pos) < sizeof(*event)) break; event = (struct inotify_event *)(event_buf + pos); pos += sizeof(*event) + event->len; io = io_notify_fd_find(&ctx->fd_ctx, event->wd); if (io != NULL) io->io.callback(io->io.context); } if (pos != ret) i_error("read(inotify) returned partial event"); return TRUE; } static void inotify_input(struct ioloop *ioloop) { while (inotify_input_more(ioloop)) ; } #undef io_add_notify struct io *io_add_notify(const char *path, io_callback_t *callback, void *context) { struct ioloop_notify_handler_context *ctx = current_ioloop->notify_handler_context; int fd; if (ctx == NULL) ctx = io_loop_notify_handler_init(); if (ctx->disabled) return NULL; fd = inotify_add_watch(ctx->inotify_fd, path, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE | IN_MODIFY); if (fd < 0) { /* ESTALE could happen with NFS. Don't bother giving an error message then. */ if (errno != ESTALE) i_error("inotify_add_watch(%s) failed: %m", path); ctx->disabled = TRUE; return NULL; } if (ctx->event_io == NULL) { ctx->event_io = io_add(ctx->inotify_fd, IO_READ, inotify_input, current_ioloop); } return io_notify_fd_add(&ctx->fd_ctx, fd, callback, context); } void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; struct io_notify *io = (struct io_notify *)_io; if (inotify_rm_watch(ctx->inotify_fd, io->fd) < 0) i_error("inotify_rm_watch() failed: %m"); io_notify_fd_free(&ctx->fd_ctx, io); if (ctx->fd_ctx.notifies == NULL) io_remove(&ctx->event_io); } static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void) { struct ioloop *ioloop = current_ioloop; struct ioloop_notify_handler_context *ctx; ctx = ioloop->notify_handler_context = i_new(struct ioloop_notify_handler_context, 1); ctx->inotify_fd = inotify_init(); if (ctx->inotify_fd == -1) { i_error("inotify_init() failed: %m"); ctx->disabled = TRUE; } else { fd_close_on_exec(ctx->inotify_fd, TRUE); } return ctx; } void io_loop_notify_handler_deinit(struct ioloop *ioloop) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; if (ctx->inotify_fd != -1) { if (close(ctx->inotify_fd) < 0) i_error("close(inotify) failed: %m"); } i_free(ctx); } #endif