Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib/ioloop-notify-dn.c @ 9191:b340ecb24469 HEAD
Fix VPATH build of RQUOTA support.
Some rpcgen derive #include "..." paths from the infile argument.
This will be off for VPATH builds, as the generated rquota_xdr.c
code will look in $(srcdir), but we'll generate the rquota.h file in
$(builddir). Play safe and copy rquota.x to $(builddir) first.
This fixes the build on openSUSE 11.1.
author | Matthias Andree <matthias.andree@gmx.de> |
---|---|
date | Tue, 07 Jul 2009 21:01:36 +0200 |
parents | b9faf4db2a9f |
children | 00cd9aacd03c |
line wrap: on
line source
/* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */ /* Logic is pretty much based on dnotify by Oskar Liljeblad. */ #define _GNU_SOURCE #include "lib.h" #ifdef IOLOOP_NOTIFY_DNOTIFY #include "ioloop-internal.h" #include "ioloop-notify-fd.h" #include "fd-set-nonblock.h" #include "fd-close-on-exec.h" #include <signal.h> #include <unistd.h> #include <fcntl.h> struct ioloop_notify_handler_context { struct ioloop_notify_fd_context fd_ctx; struct io *event_io; int event_pipe[2]; bool disabled; }; static int sigrt_refcount = 0; static struct ioloop_notify_handler_context *io_loop_notify_handler_init(void); static void ioloop_dnotify_disable(struct ioloop_notify_handler_context *ctx) { if (ctx->disabled) return; if (--sigrt_refcount == 0) signal(SIGRTMIN, SIG_IGN); if (close(ctx->event_pipe[0]) < 0) i_error("close(dnotify pipe[0]) failed: %m"); if (close(ctx->event_pipe[1]) < 0) i_error("close(dnotify pipe[1]) failed: %m"); ctx->disabled = TRUE; } static void sigrt_handler(int signo ATTR_UNUSED, siginfo_t *si, void *data ATTR_UNUSED) { struct ioloop_notify_handler_context *ctx = current_ioloop->notify_handler_context; int saved_errno = errno; int ret; if (ctx->disabled) return; ret = write(ctx->event_pipe[1], &si->si_fd, sizeof(int)); if (ret < 0 && errno != EINTR && errno != EAGAIN) { i_error("write(dnotify pipe) failed: %m"); ioloop_dnotify_disable(ctx); } i_assert(ret <= 0 || ret == sizeof(int)); errno = saved_errno; } static void dnotify_input(struct ioloop *ioloop) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; struct io_notify *io; int fd_buf[256], i, ret; ret = read(ctx->event_pipe[0], fd_buf, sizeof(fd_buf)); if (ret < 0) i_fatal("read(dnotify pipe) failed: %m"); if ((ret % sizeof(fd_buf[0])) != 0) i_fatal("read(dnotify pipe) returned %d", ret); ret /= sizeof(fd_buf[0]); if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0) i_fatal("gettimeofday(): %m"); ioloop_time = ioloop_timeval.tv_sec; for (i = 0; i < ret; i++) { io = io_notify_fd_find(&ctx->fd_ctx, fd_buf[i]); if (io != NULL) io->io.callback(io->io.context); } } #undef io_add_notify enum io_notify_result io_add_notify(const char *path, io_callback_t *callback, void *context, struct io **io_r) { struct ioloop_notify_handler_context *ctx = current_ioloop->notify_handler_context; int fd; *io_r = NULL; if (ctx == NULL) ctx = io_loop_notify_handler_init(); if (ctx->disabled) return IO_NOTIFY_NOSUPPORT; fd = open(path, O_RDONLY); if (fd == -1) { /* ESTALE could happen with NFS. Don't bother giving an error message then. */ if (errno != ENOENT && errno != ESTALE) i_error("open(%s) for dnotify failed: %m", path); return IO_NOTIFY_NOTFOUND; } if (fcntl(fd, F_SETSIG, SIGRTMIN) < 0) { /* EINVAL means there's no realtime signals and no dnotify */ if (errno != EINVAL) i_error("fcntl(F_SETSIG) failed: %m"); ioloop_dnotify_disable(ctx); (void)close(fd); return IO_NOTIFY_NOSUPPORT; } if (fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME | DN_MULTISHOT) < 0) { if (errno == ENOTDIR) { /* we're trying to add dnotify to a non-directory fd. fail silently. */ } else { /* dnotify not in kernel. disable it. */ if (errno != EINVAL) i_error("fcntl(F_NOTIFY) failed: %m"); ioloop_dnotify_disable(ctx); } (void)fcntl(fd, F_SETSIG, 0); (void)close(fd); return IO_NOTIFY_NOSUPPORT; } if (ctx->event_io == NULL) { ctx->event_io = io_add(ctx->event_pipe[0], IO_READ, dnotify_input, current_ioloop); } *io_r = io_notify_fd_add(&ctx->fd_ctx, fd, callback, context); return IO_NOTIFY_ADDED; } void io_loop_notify_remove(struct io *_io) { struct ioloop_notify_handler_context *ctx = _io->ioloop->notify_handler_context; struct io_notify *io = (struct io_notify *)_io; if (fcntl(io->fd, F_NOTIFY, 0) < 0) i_error("fcntl(F_NOTIFY, 0) failed: %m"); if (fcntl(io->fd, F_SETSIG, 0) < 0) i_error("fcntl(F_SETSIG, 0) failed: %m"); if (close(io->fd)) i_error("close(dnotify) 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_notify_handler_context *ctx; struct sigaction act; ctx = current_ioloop->notify_handler_context = i_new(struct ioloop_notify_handler_context, 1); if (pipe(ctx->event_pipe) < 0) { ctx->disabled = TRUE; i_error("dnotify: pipe() failed: %m"); return ctx; } fd_set_nonblock(ctx->event_pipe[0], TRUE); fd_set_nonblock(ctx->event_pipe[1], TRUE); fd_close_on_exec(ctx->event_pipe[0], TRUE); fd_close_on_exec(ctx->event_pipe[1], TRUE); if (sigrt_refcount++ == 0) { /* SIGIO is sent if queue gets full. we'll just ignore it. */ signal(SIGIO, SIG_IGN); act.sa_sigaction = sigrt_handler; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER; if (sigaction(SIGRTMIN, &act, NULL) < 0) { if (errno == EINVAL) { /* kernel is too old to understand even RT signals, so there's no way dnotify works */ ioloop_dnotify_disable(ctx); } else { i_fatal("sigaction(SIGRTMIN) failed: %m"); } } } return ctx; } void io_loop_notify_handler_deinit(struct ioloop *ioloop) { struct ioloop_notify_handler_context *ctx = ioloop->notify_handler_context; ioloop_dnotify_disable(ctx); i_free(ctx); } #endif