ioloop-notify-dn.c revision 01c43cb586726efc06342114c0545db4b1733d2c
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (C) 2003 Timo Sirainen */
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen/* Logic is pretty much based on dnotify by Oskar Liljeblad. */
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define _GNU_SOURCE
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "lib.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#ifdef IOLOOP_NOTIFY_DNOTIFY
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "ioloop-internal.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "network.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "fd-close-on-exec.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include <signal.h>
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include <unistd.h>
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include <fcntl.h>
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct ioloop_notify_handler_context {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct io *event_io;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int disabled;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen};
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int event_pipe[2] = { -1, -1 };
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic void sigrt_handler(int signo __attr_unused__, siginfo_t *si,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen void *data __attr_unused__)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = write(event_pipe[1], &si->si_fd, sizeof(int));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret < 0 && errno != EINTR && errno != EAGAIN)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_fatal("write(event_pipe) failed: %m");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_assert(ret <= 0 || ret == sizeof(int));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic void event_callback(void *context)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop *ioloop = context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct io *io;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int fd, ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen ret = read(event_pipe[0], &fd, sizeof(fd));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_fatal("read(event_pipe) failed: %m");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret != sizeof(fd))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_fatal("read(event_pipe) returned %d != %d", ret, sizeof(fd));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_fatal("gettimeofday(): %m");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ioloop_time = ioloop_timeval.tv_sec;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen for (io = ioloop->notifys; io != NULL; io = io->next) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (io->fd == fd) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io->callback(io->context);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstruct io *io_loop_notify_add(struct ioloop *ioloop, int fd,
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen enum io_condition condition,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io_callback_t *callback, void *context)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct ioloop_notify_handler_context *ctx =
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen ioloop->notify_handler_context;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct io *io;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if ((condition & IO_FILE_NOTIFY) != 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (fcntl(fd, F_SETSIG, SIGRTMIN) < 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (errno == EINVAL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* dnotify not in kernel. disable it. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->disabled = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_error("fcntl(F_SETSIG) failed: %m");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen DN_MULTISHOT) < 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("fcntl(F_NOTIFY) failed: %m");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen (void)fcntl(fd, F_SETSIG, 0);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return FALSE;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (ctx->event_io == NULL) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen ctx->event_io =
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io_add(event_pipe[0], IO_READ, event_callback, ioloop);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io = p_new(ioloop->pool, struct io, 1);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io->fd = fd;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io->condition = condition;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io->callback = callback;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io->context = context;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen io->next = ioloop->notifys;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen ioloop->notifys = io;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return io;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainenvoid io_loop_notify_remove(struct ioloop *ioloop, struct io *io)
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen{
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen struct ioloop_notify_handler_context *ctx =
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen ioloop->notify_handler_context;
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen struct io **io_p;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (ctx->disabled)
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen return;
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen for (io_p = &ioloop->notifys; *io_p != NULL; io_p = &(*io_p)->next) {
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen if (*io_p == io) {
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen *io_p = io->next;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen break;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen if (fcntl(io->fd, F_NOTIFY, 0) < 0)
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen i_error("fcntl(F_NOTIFY, 0) failed: %m");
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen if (fcntl(io->fd, F_SETSIG, 0) < 0)
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen i_error("fcntl(F_SETSIG, 0) failed: %m");
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen p_free(ioloop->pool, io);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (ioloop->notifys == NULL) {
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen io_remove(ctx->event_io);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen ctx->event_io = NULL;
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen }
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen}
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenvoid io_loop_notify_handler_init(struct ioloop *ioloop)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop_notify_handler_context *ctx;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct sigaction act;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_assert(event_pipe[0] == -1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx = ioloop->notify_handler_context =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_new(struct ioloop_notify_handler_context, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
9fd6f70ed6d4733ae5eabd49822bda280393e403Timo Sirainen if (pipe(event_pipe) < 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_fatal("pipe() failed: %m");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return;
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen }
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen net_set_nonblock(event_pipe[0], TRUE);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen net_set_nonblock(event_pipe[1], TRUE);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen fd_close_on_exec(event_pipe[0], TRUE);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen fd_close_on_exec(event_pipe[1], TRUE);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen /* SIGIO is sent if queue gets full. we'll just ignore it. */
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen signal(SIGIO, SIG_IGN);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen act.sa_sigaction = sigrt_handler;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen sigemptyset(&act.sa_mask);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen act.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (sigaction(SIGRTMIN, &act, NULL) < 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen i_fatal("sigaction(SIGRTMIN) failed: %m");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
90e39174d397567c101dbf694761371af3682928Timo Sirainenvoid io_loop_notify_handler_deinit(struct ioloop *ioloop __attr_unused__)
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen{
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen struct ioloop_notify_handler_context *ctx =
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen ioloop->notify_handler_context;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen signal(SIGRTMIN, SIG_IGN);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (close(event_pipe[0]) < 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen i_error("close(event_pipe[0]) failed: %m");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (close(event_pipe[1]) < 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen i_error("close(event_pipe[1]) failed: %m");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen i_free(ctx);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
#endif