diff -rupd dovecot-1.0.beta2.original/src/lib/ioloop-kqueue.c dovecot-1.0.beta2/src/lib/ioloop-kqueue.c
--- dovecot-1.0.beta2.original/src/lib/ioloop-kqueue.c	Fri Dec 30 21:46:28 2005
+++ dovecot-1.0.beta2/src/lib/ioloop-kqueue.c	Mon Jan 23 18:31:29 2006
@@ -12,11 +12,13 @@
 /* @UNSAFE: whole file */
 
 #include "lib.h"
-#include "ioloop-internal.h"
 
 #ifdef IOLOOP_KQUEUE
 
+#include "fd-close-on-exec.h"
+#include "ioloop-internal.h"
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/event.h>
 #include <sys/time.h>
@@ -28,166 +30,181 @@
 #define MASK (IO_READ | IO_WRITE | IO_ERROR)
 
 struct ioloop_handler_context {
-        int kq;
-        size_t evbuf_size;
-        struct kevent *evbuf;
+	int kq;
+	size_t evbuf_size;
+	struct kevent *evbuf;
 
-        size_t fds_size;
-        struct fdrecord *fds;
+	size_t fds_size;
+	struct fdrecord *fds;
 };
 
 struct fdrecord {
-        struct io *errio;
-        enum io_condition mode;
+	struct io *errio;
+	enum io_condition mode;
 };
 
 void io_loop_handler_init(struct ioloop *ioloop)
 {
-        struct ioloop_handler_context *ctx;
+	struct ioloop_handler_context *ctx;
 
-        ioloop->handler_context = ctx =
-                p_new(ioloop->pool, struct ioloop_handler_context, 1);
+	ioloop->handler_context = ctx =
+		p_new(ioloop->pool, struct ioloop_handler_context, 1);
 
 	ctx->evbuf_size = INITIAL_BUF_SIZE;
-        ctx->evbuf = p_new(ioloop->pool, struct kevent, ctx->evbuf_size);
-        ctx->kq = kqueue();
-        if (ctx->kq < 0)
-                i_fatal("kqueue(): %m");
+	ctx->evbuf = p_new(ioloop->pool, struct kevent, ctx->evbuf_size);
+	ctx->kq = kqueue();
+	if (ctx->kq < 0)
+		i_fatal("kqueue() for io_loop_handler_init() failed : %m");
+	fd_close_on_exec(ctx->kq, TRUE);
 
-        ctx->fds_size = INITIAL_BUF_SIZE;
-        ctx->fds = p_new(ioloop->pool, struct fdrecord, ctx->fds_size);
+	ctx->fds_size = INITIAL_BUF_SIZE;
+	ctx->fds = p_new(ioloop->pool, struct fdrecord, ctx->fds_size);
 }
 
 void io_loop_handler_deinit(struct ioloop *ioloop)
 {
 	if (close(ioloop->handler_context->kq) < 0)
-		i_error("close(kqueue) failed: %m");
-        p_free(ioloop->pool, ioloop->handler_context->evbuf);
-        p_free(ioloop->pool, ioloop->handler_context->fds);
-        p_free(ioloop->pool, ioloop->handler_context);
+		i_error("close(kqueue) for io_loop_handler_deinit() failed: %m");
+	p_free(ioloop->pool, ioloop->handler_context->evbuf);
+	p_free(ioloop->pool, ioloop->handler_context->fds);
+	p_free(ioloop->pool, ioloop->handler_context);
 }
 
 void io_loop_handle_add(struct ioloop *ioloop, struct io *io)
 {
-        struct ioloop_handler_context *ctx = ioloop->handler_context;
-        const int fd = io->fd;
-        struct kevent ev = { fd, 0, EV_ADD | EV_EOF, 0, 0, NULL };
-        enum io_condition condition = io->condition & MASK;
-
-        /* grow ctx->fds array if necessary */
-        if ((size_t)fd >= ctx->fds_size) {
-                size_t old_size = ctx->fds_size;
+	struct ioloop_handler_context *ctx = ioloop->handler_context;
+	const int fd = io->fd;
+	struct kevent ev = { fd, 0, EV_ADD | EV_EOF, 0, 0, NULL };
+	enum io_condition condition = io->condition & MASK;
+	
+	i_assert(io->callback);
+	/* grow ctx->fds array if necessary */
+	if ((size_t)fd >= ctx->fds_size) {
+		size_t old_size = ctx->fds_size;
 
-                ctx->fds_size = nearest_power((unsigned int)fd+1);
-                i_assert(ctx->fds_size < (size_t)-1 / sizeof(int));
+		ctx->fds_size = nearest_power((unsigned int)fd+1);
+		i_assert(ctx->fds_size < (size_t)-1 / sizeof(int));
 
-                ctx->fds = p_realloc(ioloop->pool, ctx->fds,
-                                     sizeof(struct fdrecord) * old_size,
-                                     sizeof(struct fdrecord) * ctx->fds_size);
-                memset(ctx->fds + old_size, 0,
-                       sizeof(struct fdrecord) * (ctx->fds_size - old_size));
-        }
+		ctx->fds = p_realloc(ioloop->pool, ctx->fds,
+				     sizeof(struct fdrecord) * old_size,
+				     sizeof(struct fdrecord) * ctx->fds_size);
+		memset(ctx->fds + old_size, 0,
+		       sizeof(struct fdrecord) * (ctx->fds_size - old_size));
+	}
 
-        if (condition & (IO_READ | IO_WRITE))
-                ev.udata = io;
-        if (condition & IO_ERROR)
-                ctx->fds[fd].errio = io;
+	if (condition & (IO_READ | IO_WRITE))
+		ev.udata = io;
+	if (condition & IO_ERROR)
+		ctx->fds[fd].errio = io;
 
-        if (condition & (IO_READ | IO_ERROR)) {
-                ctx->fds[fd].mode |= condition;
-                ev.filter = EVFILT_READ;
-                kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
-        }
-        if (condition & (IO_WRITE | IO_ERROR)) {
-                ctx->fds[fd].mode |= condition;
-                ev.filter = EVFILT_WRITE;
-                kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
-        }
+	if (condition & (IO_READ | IO_ERROR)) {
+		ctx->fds[fd].mode |= condition;
+		ev.filter = EVFILT_READ;
+		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) == -1) {
+			i_error("kevent() for io_loop_handle_add() has failed,"
+				" fd:%d, %m", fd);
+		}
+	}
+	if (condition & (IO_WRITE | IO_ERROR)) {
+		ctx->fds[fd].mode |= condition;
+		ev.filter = EVFILT_WRITE;
+		if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) == -1) {
+			i_error("kevent() for io_loop_handle_add() has failed,"
+				" fd:%d, %m", fd);
+		}
+	}
 }
 
 void io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
 {
-        struct ioloop_handler_context *ctx = ioloop->handler_context;
-        const int fd = io->fd;
-        struct kevent ev = { fd, 0, EV_DELETE, 0, 0, NULL };
-        struct fdrecord *const fds = ctx->fds;
-        const enum io_condition condition = io->condition & MASK;
+	struct ioloop_handler_context *ctx = ioloop->handler_context;
+	const int fd = io->fd;
+	struct kevent ev = { fd, 0, EV_DELETE, 0, 0, NULL };
+	struct fdrecord *const fds = ctx->fds;
+	const enum io_condition condition = io->condition & MASK;
 
-        i_assert((size_t)fd < ctx->fds_size);
-        i_assert(fds[fd].mode != 0);
+	i_assert((size_t)fd < ctx->fds_size);
 
-        if (condition & IO_ERROR)
-                fds[fd].errio = NULL;
-        if (condition & (IO_READ | IO_ERROR)) {
-                ev.filter = EVFILT_READ;
-                fds[fd].mode &= ~condition;
-                if ((fds[fd].mode & (IO_READ | IO_ERROR)) == 0)
-                        kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
-        }
-        if (condition & (IO_WRITE | IO_ERROR)) {
-                ev.filter = EVFILT_WRITE;
-                fds[fd].mode &= ~condition;
-                if ((fds[fd].mode & (IO_WRITE | IO_ERROR)) == 0)
-                        kevent(ctx->kq, &ev, 1, NULL, 0, NULL);
-        }
+	if (condition & IO_ERROR)
+		fds[fd].errio = NULL;
+	if (condition & (IO_READ | IO_ERROR)) {
+		ev.filter = EVFILT_READ;
+		fds[fd].mode &= ~condition;
+		if ((fds[fd].mode & (IO_READ | IO_ERROR)) == 0 &&
+		    (fcntl(io->fd, F_GETFD, 0) != -1 || errno != EBADF))
+			if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) == -1) {
+				i_error("kevent() for io_loop_handle_remove"
+					" has failed: fd:%d, %m", fd);
+			}
+	}
+	if (condition & (IO_WRITE | IO_ERROR)) {
+		ev.filter = EVFILT_WRITE;
+		fds[fd].mode &= ~condition;
+		if ((fds[fd].mode & (IO_WRITE | IO_ERROR)) == 0 &&
+		    (fcntl(io->fd, F_GETFD, 0) != -1 || errno != EBADF))
+			if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) == -1) {
+				i_error("kevent() for io_loop_handle_remove"
+					" has failed: fd:%d, %m", fd);
+			}
+	}
 }
 
 void io_loop_handler_run(struct ioloop *ioloop)
 {
-        struct ioloop_handler_context *ctx = ioloop->handler_context;
-        struct timeval tv;
-        struct timespec ts;
-        unsigned int t_id;
-        int msecs, ret, i;
+	struct ioloop_handler_context *ctx = ioloop->handler_context;
+	struct timeval tv;
+	struct timespec ts;
+	unsigned int t_id;
+	int msecs, ret, i;
 
-        /* get the time left for next timeout task */
-        msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
-        ts.tv_sec = tv.tv_sec;
-        ts.tv_nsec = tv.tv_usec * 1000;
+	/* get the time left for next timeout task */
+	msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
+	ts.tv_sec = tv.tv_sec;
+	ts.tv_nsec = tv.tv_usec * 1000;
 
-        /* wait for events */
-        ret = kevent (ctx->kq, NULL, 0, ctx->evbuf, ctx->evbuf_size, &ts);
-        if (ret < 0 && errno != EINTR)
-                i_fatal("kevent(): %m");
+	/* wait for events */
+	ret = kevent (ctx->kq, NULL, 0, ctx->evbuf, ctx->evbuf_size, &ts);
+	if (ret < 0 && errno != EINTR)
+		i_fatal("kevent(): %m");
 
-        /* execute timeout handlers */
-        io_loop_handle_timeouts(ioloop);
+	/* execute timeout handlers */
+	io_loop_handle_timeouts(ioloop);
 
-        if (ret <= 0 || !ioloop->running) {
-                /* no I/O events */
-                return;
-        }
+	if (ret <= 0 || !ioloop->running) {
+		/* no I/O events */
+		return;
+	}
 
-        i_assert((size_t)ret <= ctx->evbuf_size);
+	i_assert((size_t)ret <= ctx->evbuf_size);
 
-        /* loop through all received events */
-        for (i = 0; i < ret; ++i) {
-                struct io *io = ctx->evbuf[i].udata;
+	/* loop through all received events */
+	for (i = 0; i < ret; ++i) {
+		struct io *io = ctx->evbuf[i].udata;
 
-                i_assert(ctx->evbuf[i].ident < ctx->fds_size);
+		i_assert(ctx->evbuf[i].ident < ctx->fds_size);
 		if ((ctx->fds[ctx->evbuf[i].ident].mode & IO_ERROR) &&
 		    (ctx->evbuf[i].flags & EV_EOF)) {
-                        struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
+			struct io *errio = ctx->fds[ctx->evbuf[i].ident].errio;
 
-                        t_id = t_push();
-                        errio->callback(errio->context);
+			t_id = t_push();
+			errio->callback(errio->context);
 			if (t_pop() != t_id) {
-                                i_panic("Leaked a t_pop() call"
-                                        " in I/O handler %p",
+				i_panic("Leaked a t_pop() call"
+					" in I/O handler %p",
 					(void *)errio->callback);
 			}
-                } else if (ctx->fds[ctx->evbuf[i].ident].mode
-                         & (IO_WRITE | IO_READ)) {
-                        t_id = t_push();
-                        io->callback(io->context);
+		} else if (ctx->fds[ctx->evbuf[i].ident].mode
+			 & (IO_WRITE | IO_READ)) {
+			t_id = t_push();
+			io->callback(io->context);
 			if (t_pop() != t_id) {
-                                i_panic("Leaked a t_pop() call"
-                                        " in I/O handler %p",
+				i_panic("Leaked a t_pop() call"
+					" in I/O handler %p",
 					(void *)io->callback);
 			}
-                } else
-                        i_panic("Unrecognized event");
-        }
+		} else
+			i_panic("Unrecognized event");
+	}
 }
 
 #endif
diff -rupd dovecot-1.0.beta2.original/src/lib/ioloop-notify-kqueue.c dovecot-1.0.beta2/src/lib/ioloop-notify-kqueue.c
--- dovecot-1.0.beta2.original/src/lib/ioloop-notify-kqueue.c	Sun Jan 15 00:27:11 2006
+++ dovecot-1.0.beta2/src/lib/ioloop-notify-kqueue.c	Mon Jan 23 18:31:16 2006
@@ -15,11 +15,13 @@
 #ifdef IOLOOP_NOTIFY_KQUEUE
 
 #include "ioloop-internal.h"
+#include "fd-close-on-exec.h"
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/event.h>
 #include <sys/time.h>
+#include <sys/stat.h>
 
 struct ioloop_notify_handler_context {
 	int kq;
@@ -53,7 +55,8 @@ void io_loop_notify_handler_init(struct 
 	ctx->event_io = NULL;
 	ctx->kq = kqueue();
 	if (ctx->kq < 0)
-		i_fatal("kqueue() failed: %m");
+		i_fatal("kqueue() for io_loop_notify_handler_init() failed: %m");
+	fd_close_on_exec(ctx->kq, TRUE);
 }
 
 void io_loop_notify_handler_deinit(struct ioloop *ioloop)
@@ -61,8 +64,8 @@ void io_loop_notify_handler_deinit(struc
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
 
-        if (ctx->event_io)
-                io_remove(ctx->event_io);
+	if (ctx->event_io)
+		io_remove(&ctx->event_io);
 	if (close(ctx->kq) < 0)
 		i_error("close(kqueue notify) failed: %m");
 	p_free(ioloop->pool, ctx);
@@ -75,6 +78,11 @@ static void unchain_io (struct ioloop *i
 	for (io_p = &ioloop->notifys; *io_p != NULL; io_p = &(*io_p)->next) {
 		if (*io_p == io) {
 			*io_p = io->next;
+			if (io->next) {
+				io->next->prev = io->prev;
+			}
+			io->prev = NULL;
+			io->next = NULL;
 			break;
 		}
 	}
@@ -90,17 +98,23 @@ struct io *io_loop_notify_add(struct iol
 			     | NOTE_REVOKE, 0, NULL };
 	struct io *io;
 	int fd;
+	struct stat sb;
 
+	i_assert(callback);
 	fd = open(path, O_RDONLY);
 	if (fd == -1) {
 		i_error("open(%s) for notify failed: %m", path);
 		return NULL;
 	}
+	fd_close_on_exec(fd, TRUE);
 
-	ev.ident = fd;
-	ev.udata = io;
-	if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
-		i_error("kevent(%s) for notify failed: %m", path);
+	if (fstat(fd, &sb) == -1) {
+		i_error("fstat(%d \"%s\") for notify failed: %m", fd, path);
+		close(fd);
+		return NULL;
+	}
+	if (! (sb.st_mode & S_IFDIR)) {
+		close(fd);
 		return NULL;
 	}
 
@@ -108,7 +122,17 @@ struct io *io_loop_notify_add(struct iol
 	io->fd = fd;
 	io->callback = callback;
 	io->context = context;
+	ev.ident = fd;
+	ev.udata = io;
+	if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0) {
+		i_error("kevent(%s) for notify failed: fd:%d, %m", path, fd);
+		p_free(ioloop->pool, io);
+		return NULL;
+	}
 	io->next = ioloop->notifys;
+	io->prev = NULL;
+	if (ioloop->notifys)
+		ioloop->notifys->prev = io;
 	ioloop->notifys = io;
 
 	if (ctx->event_io == NULL) {
@@ -116,7 +140,6 @@ struct io *io_loop_notify_add(struct iol
 			io_add(ctx->kq, IO_READ, event_callback,
 			       ioloop->notify_handler_context);
 	}
-
 	return io;
 }
 
@@ -124,15 +147,29 @@ void io_loop_notify_remove(struct ioloop
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
-	struct kevent ev = { io->fd, 0, EV_DELETE, 0, 0, NULL };
+	struct kevent ev = { io->fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL };
+	struct stat sb;
 	int ret;
 
+	if (fcntl(io->fd, F_GETFD, 0) != -1 || errno != EBADF) {
+		if (fstat(io->fd, &sb) == -1) {
+			i_error("fstat(%d) for notify_remove failed:"
+				" %m", io->fd);
+			return;
+		}
+		if (! (sb.st_mode & S_IFDIR)) {
+			i_error("calling io_loop_notify_remove on non-dir"
+				" handle");
+			return;
+		}
+		ret = kevent(ctx->kq, &ev, 1, NULL, 0, 0);
+		if (ret == -1)
+			i_error("kevent() for notify remove failed, "
+				"but fd:%d is valid: (%d) %m", io->fd, errno);
+	}
+	close(io->fd);
 	unchain_io(ioloop, io);
 	p_free(ioloop->pool, io);
-
-	ret = kevent(ctx->kq, &ev, 1, NULL, 0, 0);
-	if (ret == -1)
-		i_error("kevent() for notify failed: %m");
 }
 
 #endif
diff -rupd dovecot-1.0.beta2.original/src/lib/ioloop.c dovecot-1.0.beta2/src/lib/ioloop.c
--- dovecot-1.0.beta2.original/src/lib/ioloop.c	Sat Jan 14 18:42:22 2006
+++ dovecot-1.0.beta2/src/lib/ioloop.c	Mon Jan 23 18:21:40 2006
@@ -279,6 +279,8 @@ void io_loop_destroy(struct ioloop **_io
 
 	*_ioloop = NULL;
 
+	io_loop_notify_handler_deinit(ioloop);
+
 	while (ioloop->ios != NULL) {
 		struct io *io = ioloop->ios;
 
@@ -295,8 +297,7 @@ void io_loop_destroy(struct ioloop **_io
 		}
                 timeout_destroy(ioloop, &ioloop->timeouts);
 	}
-
-	io_loop_notify_handler_deinit(ioloop);
+	
         io_loop_handler_deinit(ioloop);
 
         /* ->prev won't work unless loops are destroyed in create order */
