So this has been annoying me enough to track down the cause.

It's idled.  Specifically, the fork() after cyrus_init().
You can't do that.  It's broken.  If you want to fork then
you need to do it before cyrus_init() or you wind up cloning
the bdb environment and closing it twice.

Question for those who might know - why does idled fork so
late?  Well - first of all why does it fork at all rather
than being forked off by master - but following on from
that...

Anyway, the attached patch moves the fork before the
cyrus_init(), which solves the problem nicely for me.
I did consider just not calling cyrus_done in the parent
clean exit, but that seemed much more dangerous.

Bron.
diff --git a/imap/idled.c b/imap/idled.c
index e46d136..cd8f404 100644
--- a/imap/idled.c
+++ b/imap/idled.c
@@ -293,6 +293,22 @@ int main(int argc, char **argv)
        }
     }
 
+    /* fork unless we were given the -d option */
+    if (debugmode == 0) {
+       
+       pid = fork();
+       
+       if (pid == -1) {
+           perror("fork");
+           exit(1);
+       }
+       
+       if (pid != 0) { /* parent */
+           exit(0);
+       }
+    }
+    /* child */
+
     cyrus_init(alt_config, "idled", 0);
 
     /* get name of shutdown file */
@@ -354,24 +370,6 @@ int main(int argc, char **argv)
     umask(oldumask); /* for Linux */
     chmod(local.sun_path, 0777); /* for DUX */
 
-    /* fork unless we were given the -d option */
-    if (debugmode == 0) {
-       
-       pid = fork();
-       
-       if (pid == -1) {
-           perror("fork");
-           cyrus_done();
-           exit(1);
-       }
-       
-       if (pid != 0) { /* parent */
-           cyrus_done();
-           exit(0);
-       }
-    }
-    /* child */
-
     /* get ready for select() */
     FD_ZERO(&read_set);
     FD_SET(s, &read_set);

Reply via email to