Hello,

For the Debian packaging, I added the ability to fork to background, and
proper pidfile locking to cyrus master...  it is not very polished yet -- no
configure.in support to set the lockfile location, for example. But it
should be very useful for other Linux distributions compliant to the FHS,
and anyone else that does not run cyrus from a sysvinit-like process
controller.

The patch applies against the CVS version (HEAD branch) of Cyrus IMAPd.

Sideeffects of this patch are a few less gcc 2.95.4 warnings, and that cyrus
will shut up about not being able to set the file handlers limit to infinity
all the time (this is useful for Linux 2.2.x; feel free to rip it out... it
was in my mods to master.c, so I left it in there).

Suggestions, fixes and improvements are welcome.  If the CMU crew would like
modifications so as to add this to upstream cyrus, I'd be happy to try to
modify the patch to acommodate them.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh
--- cyrus21-imapd-2.1.0.0preCVS20011125.orig/master/Makefile.in
+++ cyrus21-imapd-2.1.0.0preCVS20011125/master/Makefile.in
@@ -53,8 +53,8 @@
 CYRUS_GROUP=@cyrus_group@
 
 DEFS = @DEFS@ @LOCALDEFS@
-CPPFLAGS = -I. -I.. -I$(srcdir) @CPPFLAGS@ @COM_ERR_CPPFLAGS@
-DEPLIBS = @DEPLIBS@
+CPPFLAGS = -I. -I.. -I$(srcdir) -I$(srcdir)/../lib @CPPFLAGS@ @COM_ERR_CPPFLAGS@
+DEPLIBS = ../lib/libcyrus.a @DEPLIBS@
 
 CFLAGS = @CFLAGS@
 LDFLAGS = @LDFLAGS@ @CFLAGS@ @COM_ERR_LDFLAGS@
--- cyrus21-imapd-2.1.0.0preCVS20011125.orig/master/master.c
+++ cyrus21-imapd-2.1.0.0preCVS20011125/master/master.c
@@ -47,6 +47,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
+#include <time.h>
 #include <grp.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -92,8 +93,10 @@
 
 #include "master.h"
 #include "service.h"
+#include "lock.h"
 
 #define SERVICE_PATH (CYRUS_PATH "/bin")
+#define PIDFILE "/var/run/cyrmaster.pid"
 
 enum {
     become_cyrus_early = 1,
@@ -184,6 +187,68 @@
     return result;
 }
 
+void acquire_daemon_lock(int closeflag)
+/* Copyright 1988,1990,1993,1994 by Paul Vixie
+ * All rights reserved
+ *
+ * Distribute freely, except: don't remove my name from the source or
+ * documentation (don't take credit for my work), mark your changes (don't
+ * get me blamed for your possible bugs), don't alter or remove this
+ * notice.  May be sold if buildable source is provided to buyer.  No
+ * warrantee of any kind, express or implied, is included with this
+ * software; use at your own risk, responsibility for damages (if any) to
+ * anyone resulting from the use of this software rests entirely with the
+ * user.
+ *
+ * Changelog: 
+ *   2001-11-18 ([EMAIL PROTECTED]): 
+ *       Got acquire_daemonlock (and above copyright notice) from Paul Vixie's
+ *       cron, as packaged by the Debian project.  Modified acquire_daemon_lock 
+ *       to adequate it for Cyrus IMAPd needs. Applied it to cyrus master the
+ *       same proven way it is used in Vixie cron.  Basically, call it with
+ *       a zero to update the pidfile, and with a 1 at every fork() of a 
+ *       worker process.
+ */
+{
+       static  FILE    *fp = NULL;
+       int fdflags;
+
+       if (closeflag && fp) {
+               fclose(fp);
+               fp = NULL;
+               return;
+       }
+
+       if (!fp) {
+               int     fd;
+
+               if ((-1 == (fd = open(PIDFILE, O_RDWR|O_CREAT, 0644)))
+                   || (NULL == (fp = fdopen(fd, "r+")))
+                   ) {
+                       fatal("couldn't open or create pidfile " PIDFILE ": %m",1);
+               }
+
+               if (lock_nonblocking(fd)) {
+                       fatal("failed to acquire pidfile lock", 1);
+               }
+               fdflags =  fcntl(fd, F_GETFD, 0);
+               if (fdflags != -1) fdflags = fcntl(fd, F_SETFD, 
+                                               fdflags | FD_CLOEXEC);
+               if (fdflags == -1) {
+                       fatal("unable to set close-on-exec for pidfile: %m", 1);
+               }
+       }
+
+       rewind(fp);
+       fprintf(fp, "%d\n", getpid());
+       fflush(fp);
+       (void) ftruncate(fileno(fp), ftell(fp));
+
+       /* abandon fd and fp even though the file is open. we need to
+        * keep it open and locked, but we don't need the handles elsewhere.
+        */
+}
+
 void get_prog(char *path, char *const *cmd)
 {
     if (cmd[0][0] == '/') strcpy(path, cmd[0]);
@@ -430,6 +495,8 @@
        break;
        
     case 0:
+       acquire_daemon_lock(1);
+    
        if (become_cyrus() != 0) {
            syslog(LOG_ERR, "can't change to the cyrus user");
            exit(1);
@@ -477,6 +544,7 @@
 
     case 0:
        /* child */
+       acquire_daemon_lock(1);
        if (become_cyrus() != 0) {
            syslog(LOG_ERR, "can't change to the cyrus user");
            exit(1);
@@ -583,10 +651,11 @@
     while (a && a != schedule) {
        switch (p = fork()) {
        case -1:
-           syslog(LOG_CRIT, "can't fork process to run event %s");
+           syslog(LOG_CRIT, "can't fork process to run event %s", a->name);
            break;
 
        case 0:
+           acquire_daemon_lock(1);
            if (become_cyrus() != 0) {
                syslog(LOG_ERR, "can't change to the cyrus user");
                exit(1);
@@ -958,12 +1027,11 @@
 
     rl.rlim_cur = x;
     rl.rlim_max = x;
-    if (setrlimit(RLIMIT_NUMFDS, &rl) < 0) {
+    if (setrlimit(RLIMIT_NUMFDS, &rl) < 0 && x != RLIM_INFINITY) {
        syslog(LOG_ERR, "setrlimit: Unable to set file descriptors limit to %d: %m", 
x);
     }
 
-    if (verbose > 1) {
-       r = getrlimit(RLIMIT_NUMFDS, &rl);
+    if (verbose > 1 && getrlimit(RLIMIT_NUMFDS, &rl) >= 0) {
        syslog(LOG_DEBUG, "set maximum file descriptors to %d/%d", rl.rlim_cur,
               rl.rlim_max);
     }
@@ -1081,7 +1149,19 @@
 
     limit_fds(RLIM_INFINITY);
 
+    /* lock pidfile (and create it while we're root) */
+    acquire_daemon_lock(0);
+
     masterconf_init("master");
+
+#ifdef HAVE_UNISTD_H
+    /* go daemon, if not in debug mode */
+    if (close_std) {
+        if (daemon(0, 0)) fatal("could not enter daemon mode: %m", 2);
+        acquire_daemon_lock(0);
+    }
+#endif /* HAVE_UNISTD_H */
+
     syslog(LOG_NOTICE, "process started");
 
 #ifdef HAVE_UCDSNMP

Reply via email to