ioloop-notify-inotify.c revision a6280be05b9c90579bb59ff57a3035661706c3d3
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2005-2017 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define _GNU_SOURCE
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#ifdef IOLOOP_NOTIFY_INOTIFY
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen#include "fd-close-on-exec.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "fd-set-nonblock.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "ioloop-private.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "ioloop-notify-fd.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "buffer.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "net.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ipwd.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdio.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <unistd.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <fcntl.h>
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen#include <sys/ioctl.h>
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen#include <sys/inotify.h>
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define INOTIFY_BUFLEN (32*1024)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct ioloop_notify_handler_context {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen struct ioloop_notify_fd_context fd_ctx;
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen int inotify_fd;
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen struct io *event_io;
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen bool disabled;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct ioloop_notify_handler_context *io_loop_notify_handler_init(void);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool inotify_input_more(struct ioloop *ioloop)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct ioloop_notify_handler_context *ctx =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ioloop->notify_handler_context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct inotify_event *event;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned char event_buf[INOTIFY_BUFLEN];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct io_notify *io;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ssize_t ret, pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* read as many events as there is available and fit into our buffer.
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen only full events are returned by the kernel. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = read(ctx->inotify_fd, event_buf, sizeof(event_buf));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret <= 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret == 0 || errno == EAGAIN) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen /* nothing more to read */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_fatal("read(inotify) failed: %m");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_fatal("gettimeofday(): %m");
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen ioloop_time = ioloop_timeval.tv_sec;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen for (pos = 0; pos < ret; ) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if ((size_t)(ret - pos) < sizeof(*event))
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen break;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen event = (struct inotify_event *)(event_buf + pos);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen i_assert(event->len < (size_t)ret);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen pos += sizeof(*event) + event->len;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io = io_notify_fd_find(&ctx->fd_ctx, event->wd);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (io != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((event->mask & IN_IGNORED) != 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* calling inotify_rm_watch() would now give
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen EINVAL */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io->fd = -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io_loop_call_io(&io->io);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (pos != ret)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("read(inotify) returned partial event");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return (size_t)ret >= sizeof(event_buf)-512;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic void inotify_input(struct ioloop *ioloop)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen while (inotify_input_more(ioloop)) ;
4ca83616715c3bd417e34ced2c1d61852513e427Timo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#undef io_add_notify
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenenum io_notify_result
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenio_add_notify(const char *path, const char *source_filename,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen unsigned int source_linenum,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io_callback_t *callback, void *context, struct io **io_r)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop_notify_handler_context *ctx =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen current_ioloop->notify_handler_context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int wd;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen *io_r = NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ctx == NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx = io_loop_notify_handler_init();
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ctx->disabled)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return IO_NOTIFY_NOSUPPORT;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen wd = inotify_add_watch(ctx->inotify_fd, path,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen IN_CREATE | IN_DELETE | IN_DELETE_SELF |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen IN_MOVE | IN_MODIFY);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (wd < 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* ESTALE could happen with NFS. Don't bother giving an error
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen message then. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (errno == ENOENT || errno == ESTALE)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return IO_NOTIFY_NOTFOUND;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (errno != ENOSPC)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("inotify_add_watch(%s) failed: %m", path);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("Inotify watch limit for user exceeded, "
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "disabling. Increase "
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "/proc/sys/fs/inotify/max_user_watches");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->disabled = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return IO_NOTIFY_NOSUPPORT;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ctx->event_io == NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->event_io = io_add(ctx->inotify_fd, IO_READ,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen inotify_input, current_ioloop);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen *io_r = io_notify_fd_add(&ctx->fd_ctx, wd, callback, context);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (*io_r)->source_filename = source_filename;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (*io_r)->source_linenum = source_linenum;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return IO_NOTIFY_ADDED;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid io_loop_notify_remove(struct io *_io)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop_notify_handler_context *ctx =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen _io->ioloop->notify_handler_context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct io_notify *io = (struct io_notify *)_io;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (io->fd != -1) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* ernro=EINVAL happens if the file itself is deleted and
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen kernel has sent IN_IGNORED event which we haven't read. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (inotify_rm_watch(ctx->inotify_fd, io->fd) < 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen errno != EINVAL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_error("inotify_rm_watch() failed: %m");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen io_notify_fd_free(&ctx->fd_ctx, io);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ctx->fd_ctx.notifies == NULL && ctx->event_io != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen io_remove(&ctx->event_io);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void ioloop_inotify_user_limit_exceeded(void)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct passwd pw;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *name;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uid_t uid = geteuid();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (i_getpwuid(uid, &pw) <= 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen name = t_strdup_printf("UID %s", dec2str(uid));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen name = t_strdup_printf("%s (UID %s)",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dec2str(uid), pw.pw_name);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("Inotify instance limit for user %s exceeded, disabling. "
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "Increase /proc/sys/fs/inotify/max_user_instances", name);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct ioloop_notify_handler_context *io_loop_notify_handler_init(void)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop *ioloop = current_ioloop;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop_notify_handler_context *ctx;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx = ioloop->notify_handler_context =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_new(struct ioloop_notify_handler_context, 1);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->inotify_fd = inotify_init();
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ctx->inotify_fd == -1) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (errno != EMFILE)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("inotify_init() failed: %m");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen else
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ioloop_inotify_user_limit_exceeded();
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->disabled = TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen fd_close_on_exec(ctx->inotify_fd, TRUE);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen fd_set_nonblock(ctx->inotify_fd, TRUE);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ctx;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid io_loop_notify_handler_deinit(struct ioloop *ioloop)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop_notify_handler_context *ctx =
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ioloop->notify_handler_context;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen while (ctx->fd_ctx.notifies != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct io_notify *io = ctx->fd_ctx.notifies;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct io *_io = &io->io;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("I/O notify leak: %p (%s:%u, fd %d)",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (void *)_io->callback,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen _io->source_filename,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen _io->source_linenum, io->fd);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen io_remove(&_io);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ctx->inotify_fd != -1) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (close(ctx->inotify_fd) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_error("close(inotify) failed: %m");
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ctx->inotify_fd = -1;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_free(ctx);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint io_loop_extract_notify_fd(struct ioloop *ioloop)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct ioloop_notify_handler_context *ctx =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ioloop->notify_handler_context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct io_notify *io;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int fd, new_inotify_fd;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (ctx == NULL || ctx->inotify_fd == -1)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_inotify_fd = inotify_init();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (new_inotify_fd == -1) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (errno != EMFILE)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_error("inotify_init() failed: %m");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ioloop_inotify_user_limit_exceeded();
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen for (io = ctx->fd_ctx.notifies; io != NULL; io = io->next)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen io->fd = -1;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (ctx->event_io != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen io_remove(&ctx->event_io);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = ctx->inotify_fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ctx->inotify_fd = new_inotify_fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#endif
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen