apple-mods.diff   [plain text]


--- a/Mailman/Archiver/Archiver.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Archiver/Archiver.py	2010-01-14 11:59:33.000000000 -0700
@@ -93,7 +93,7 @@
         omask = os.umask(0)
         try:
             try:
-                os.mkdir(self.archive_dir()+'.mbox', 02775)
+                os.mkdir(self.archive_dir()+'.mbox', 0775)
             except OSError, e:
                 if e.errno <> errno.EEXIST: raise
                 # We also create an empty pipermail archive directory into
@@ -101,7 +101,7 @@
                 # that lists that have not yet received a posting have
                 # /something/ as their index.html, and don't just get a 404.
             try:
-                os.mkdir(self.archive_dir(), 02775)
+                os.mkdir(self.archive_dir(), 0775)
             except OSError, e:
                 if e.errno <> errno.EEXIST: raise
             # See if there's an index.html file there already and if not,
--- a/Mailman/Archiver/HyperArch.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Archiver/HyperArch.py	2010-01-14 11:59:33.000000000 -0700
@@ -623,7 +623,7 @@
     __super_add_article = pipermail.T.add_article
 
     # some defaults
-    DIRMODE = 02775
+    DIRMODE = 0775
     FILEMODE = 0660
 
     VERBOSE = 0
--- a/Mailman/Archiver/HyperDatabase.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Archiver/HyperDatabase.py	2010-01-14 11:59:33.000000000 -0700
@@ -242,7 +242,7 @@
         omask = os.umask(0)
         try:
             try:
-                os.mkdir(arcdir, 02770)
+                os.mkdir(arcdir, 0770)
             except OSError, e:
                 if e.errno <> errno.EEXIST: raise
         finally:
--- a/Mailman/Archiver/pipermail.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Archiver/pipermail.py	2010-01-14 11:59:33.000000000 -0700
@@ -775,7 +775,7 @@
         omask = os.umask(0)
         try:
             try:
-                os.mkdir(arcdir, 02775)
+                os.mkdir(arcdir, 0775)
             except OSError:
                 # BAW: Hmm...
                 pass
--- a/Mailman/Cgi/edithtml.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Cgi/edithtml.py	2010-01-14 11:59:33.000000000 -0700
@@ -178,7 +178,7 @@
     omask = os.umask(0)
     try:
         try:
-            os.mkdir(langdir, 02775)
+            os.mkdir(langdir, 0775)
         except OSError, e:
             if e.errno <> errno.EEXIST: raise
     finally:
--- a/Mailman/Handlers/Scrubber.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Handlers/Scrubber.py	2010-01-14 11:59:33.000000000 -0700
@@ -417,11 +417,11 @@
 def makedirs(dir):
     # Create all the directories to store this attachment in
     try:
-        os.makedirs(dir, 02775)
+        os.makedirs(dir, 0775)
         # Unfortunately, FreeBSD seems to be broken in that it doesn't honor
         # the mode arg of mkdir().
         def twiddle(arg, dirname, names):
-            os.chmod(dirname, 02775)
+            os.chmod(dirname, 0775)
         os.path.walk(dir, twiddle, None)
     except OSError, e:
         if e.errno <> errno.EEXIST: raise
--- a/Mailman/Site.py	2009-01-11 10:49:38.000000000 -0700
+++ b/Mailman/Site.py	2010-01-14 11:59:33.000000000 -0700
@@ -37,7 +37,7 @@
     try:
         omask = os.umask(0)
         try:
-            os.makedirs(path, 02775)
+            os.makedirs(path, 0775)
         finally:
             os.umask(omask)
     except OSError, e:
--- a/Makefile.in	2009-01-11 10:49:38.000000000 -0700
+++ b/Makefile.in	2010-01-14 11:59:33.000000000 -0700
@@ -39,7 +39,7 @@
 # Customizable but not set by configure
 
 OPT=		@OPT@
-CFLAGS=		@CFLAGS@ $(OPT) $(DEFS)
+CFLAGS=		@CFLAGS@ $(OPT) $(BI_RC_CFLAGS) $(DEFS)
 
 VAR_DIRS= \
 	logs archives lists locks data spam qfiles \
--- a/bin/check_perms	2009-01-11 10:49:38.000000000 -0700
+++ b/bin/check_perms	2010-01-14 11:59:32.000000000 -0700
@@ -70,8 +70,8 @@
 
 STATE = State()
 
-DIRPERMS = S_ISGID | S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
-QFILEPERMS = S_ISGID | S_IRWXU | S_IRWXG
+DIRPERMS = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
+QFILEPERMS = S_IRWXU | S_IRWXG
 PYFILEPERMS = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
 ARTICLEFILEPERMS = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
 PRIVATEPERMS = QFILEPERMS
@@ -194,7 +194,7 @@
             continue
         if (mode & DIRPERMS) <> DIRPERMS:
             STATE.ERRORS += 1
-            print _('directory must be at least 02775: %(d)s'),
+            print _('directory must be at least 0775: %(d)s'),
             if STATE.FIX:
                 print _('(fixing)')
                 os.chmod(d, mode | DIRPERMS)
--- a/bin/mailmanctl	2009-01-11 10:49:38.000000000 -0700
+++ b/bin/mailmanctl	2010-01-14 11:59:32.000000000 -0700
@@ -319,6 +319,14 @@
     checkprivs = 1
     force = 0
     quiet = 0
+    if not os.path.isdir('/var/run/mailman'):
+        os.mkdir('/var/run/mailman', 0775)
+    if os.path.isdir('/var/run/mailman'):
+        os.chown('/var/run/mailman', 78, 78)
+    if not os.path.isdir('/var/log/mailman'):
+        os.mkdir('/var/log/mailman', 0775)
+    if os.path.isdir('/var/log/mailman'):
+        os.chown('/var/log/mailman', 78, 78)
     for opt, arg in opts:
         if opt in ('-h', '--help'):
             usage(0)
@@ -351,6 +359,185 @@
         if not quiet:
             print _("Shutting down Mailman's master qrunner")
         kill_watcher(signal.SIGTERM)
+    elif command == 'startf':
+        # First, complain loudly if there's no site list.
+        check_for_site_list()
+        # Here's the scoop on the processes we're about to create.  We'll need
+        # one for each qrunner, and one for a master child process watcher /
+        # lock refresher process.
+        #
+        # The child watcher process simply waits on the pids of the children
+        # qrunners.  Unless explicitly disabled by a mailmanctl switch (or the
+        # children are killed with SIGTERM instead of SIGINT), the watcher
+        # will automatically restart any child process that exits.  This
+        # allows us to be more robust, and also to implement restart by simply
+        # SIGINT'ing the qrunner children, and letting the watcher restart
+        # them.
+        #
+        # Under normal operation, we have a child per queue.  This lets us get
+        # the most out of the available resources, since a qrunner with no
+        # files in its queue directory is pretty cheap, but having a separate
+        # runner process per queue allows for a very responsive system.  Some
+        # people want a more traditional (i.e. MM2.0.x) cron-invoked qrunner.
+        # No problem, but using mailmanctl isn't the answer.  So while
+        # mailmanctl hard codes some things, others, such as the number of
+        # qrunners per queue, is configurable in mm_cfg.py.
+        #
+        # First, acquire the master mailmanctl lock
+        lock = acquire_lock(force)
+        if not lock:
+            return
+        # Daemon process startup according to Stevens, Advanced Programming in
+        # the UNIX Environment, Chapter 13.
+        #pid = os.fork()
+        #if pid:
+        #    # parent
+        #    if not quiet:
+        #        print _("Starting Mailman's master qrunner.")
+        #    # Give up the lock "ownership".  This just means the foreground
+        #    # process won't close/unlock the lock when it finalizes this lock
+        #    # instance.  We'll let the mater watcher subproc own the lock.
+        #    lock._transfer_to(pid)
+        #    return
+        # child
+        #lock._take_possession()
+        # First, save our pid in a file for "mailmanctl stop" rendezvous.  We
+        # want the perms on the .pid file to be rw-rw----
+        omask = os.umask(6)
+        try:
+            fp = open(mm_cfg.PIDFILE, 'w')
+            print >> fp, os.getpid()
+            fp.close()
+        finally:
+            os.umask(omask)
+        # Create a new session and become the session leader, but since we
+        # won't be opening any terminal devices, don't do the ultra-paranoid
+        # suggestion of doing a second fork after the setsid() call.
+        #os.setsid()
+        # Instead of cd'ing to root, cd to the Mailman installation home
+        #os.chdir(mm_cfg.PREFIX)
+        # Set our file mode creation umask
+        #os.umask(007)
+        # I don't think we have any unneeded file descriptors.
+        #
+        # Now start all the qrunners.  This returns a dictionary where the
+        # keys are qrunner pids and the values are tuples of the following
+        # form: (qrname, slice, count).  This does its own fork and exec, and
+        # sets up its own signal handlers.
+        kids = start_all_runners()
+        # Set up a SIGALRM handler to refresh the lock once per day.  The lock
+        # lifetime is 1day+6hours so this should be plenty.
+        def sigalrm_handler(signum, frame, lock=lock):
+            lock.refresh()
+            signal.alarm(mm_cfg.days(1))
+        signal.signal(signal.SIGALRM, sigalrm_handler)
+        signal.alarm(mm_cfg.days(1))
+        # Set up a SIGHUP handler so that if we get one, we'll pass it along
+        # to all the qrunner children.  This will tell them to close and
+        # reopen their log files
+        def sighup_handler(signum, frame, kids=kids):
+            # Closing our syslog will cause it to be re-opened at the next log
+            # print output.
+            syslog.close()
+            for pid in kids.keys():
+                os.kill(pid, signal.SIGHUP)
+            # And just to tweak things...
+            syslog('qrunner',
+                   'Master watcher caught SIGHUP.  Re-opening log files.')
+        signal.signal(signal.SIGHUP, sighup_handler)
+        # We also need to install a SIGTERM handler because that's what init
+        # will kill this process with when changing run levels.
+        def sigterm_handler(signum, frame, kids=kids):
+            for pid in kids.keys():
+                try:
+                    os.kill(pid, signal.SIGTERM)
+                except OSError, e:
+                    if e.errno <> errno.ESRCH: raise
+            syslog('qrunner', 'Master watcher caught SIGTERM.  Exiting.')
+        signal.signal(signal.SIGTERM, sigterm_handler)
+        # Finally, we need a SIGINT handler which will cause the sub-qrunners
+        # to exit, but the master will restart SIGINT'd sub-processes unless
+        # the -n flag was given.
+        def sigint_handler(signum, frame, kids=kids):
+            for pid in kids.keys():
+                os.kill(pid, signal.SIGINT)
+            syslog('qrunner', 'Master watcher caught SIGINT.  Restarting.')
+        signal.signal(signal.SIGINT, sigint_handler)
+        # Now we're ready to simply do our wait/restart loop.  This is the
+        # master qrunner watcher.
+        try:
+            while 1:
+                try:
+                    pid, status = os.wait()
+                except OSError, e:
+                    # No children?  We're done
+                    if e.errno == errno.ECHILD:
+                        break
+                    # If the system call got interrupted, just restart it.
+                    elif e.errno <> errno.EINTR:
+                        raise
+                    continue
+                killsig = exitstatus = None
+                if os.WIFSIGNALED(status):
+                    killsig = os.WTERMSIG(status)
+                if os.WIFEXITED(status):
+                    exitstatus = os.WEXITSTATUS(status)
+                # We'll restart the process unless we were given the
+                # "no-restart" switch, or if the process was SIGTERM'd or
+                # exitted with a SIGTERM exit status.  This lets us better
+                # handle runaway restarts (say, if the subproc had a syntax
+                # error!)
+                restarting = ''
+                if restart:
+                    if (exitstatus == None and killsig <> signal.SIGTERM) or \
+                       (killsig == None and exitstatus <> signal.SIGTERM):
+                        # Then
+                        restarting = '[restarting]'
+                qrname, slice, count, restarts = kids[pid]
+                del kids[pid]
+                syslog('qrunner', """\
+Master qrunner detected subprocess exit
+(pid: %d, sig: %s, sts: %s, class: %s, slice: %d/%d) %s""",
+                       pid, killsig, exitstatus, qrname,
+                       slice+1, count, restarting)
+                # See if we've reached the maximum number of allowable restarts
+                if exitstatus <> signal.SIGINT:
+                    restarts += 1
+                if restarts > MAX_RESTARTS:
+                    syslog('qrunner', """\
+Qrunner %s reached maximum restart limit of %d, not restarting.""",
+                           qrname, MAX_RESTARTS)
+                    restarting = ''
+                # Now perhaps restart the process unless it exited with a
+                # SIGTERM or we aren't restarting.
+                if restarting:
+                    newpid = start_runner(qrname, slice, count)
+                    kids[newpid] = (qrname, slice, count, restarts)
+        finally:
+            # Should we leave the main loop for any reason, we want to be sure
+            # all of our children are exited cleanly.  Send SIGTERMs to all
+            # the child processes and wait for them all to exit.
+            for pid in kids.keys():
+                try:
+                    os.kill(pid, signal.SIGTERM)
+                except OSError, e:
+                    if e.errno == errno.ESRCH:
+                        # The child has already exited
+                        syslog('qrunner', 'ESRCH on pid: %d', pid)
+                        del kids[pid]
+            # Wait for all the children to go away
+            while 1:
+                try:
+                    pid, status = os.wait()
+                except OSError, e:
+                    if e.errno == errno.ECHILD:
+                        break
+                    elif e.errno <> errno.EINTR:
+                        raise
+                    continue
+        # Finally, give up the lock
+        lock.unlock(unconditionally=1)
+        os._exit(0)
     elif command == 'restart':
         # Sent the master qrunner process a SIGHUP.  This will cause the
         # master qrunner to kill and restart all the worker qrunners, and to
--- a/bin/update	2009-01-11 10:49:38.000000000 -0700
+++ b/bin/update	2010-01-14 11:59:32.000000000 -0700
@@ -234,7 +234,7 @@
     #
     if not os.path.exists(mbox_dir):
         ou = os.umask(0)
-        os.mkdir(mbox_dir, 02775)
+        os.mkdir(mbox_dir, 0775)
         os.umask(ou)
     else:
         # this shouldn't happen, but hey, just in case
@@ -244,7 +244,7 @@
 b6, so I'm renaming it to %(mbox_dir)s.tmp and proceeding.""")
             os.rename(mbox_dir, "%s.tmp" % (mbox_dir))
             ou = os.umask(0)
-            os.mkdir(mbox_dir, 02775)
+            os.mkdir(mbox_dir, 0775)
             os.umask(ou)
 
     # Move any existing mboxes around, but watch out for both a public and a
@@ -333,7 +333,7 @@
         #
         # chmod the html archives
         #
-        os.chmod(html_dir, 02775)
+        os.chmod(html_dir, 0775)
     # BAW: Is this still necessary?!
     mlist.Save()
     #
@@ -385,9 +385,9 @@
         abs = os.path.join(dir, f)
         if os.path.isdir(abs):
             if f == "database":
-                os.chmod(abs, 02770)
+                os.chmod(abs, 0770)
             else:
-                os.chmod(abs, 02775)
+                os.chmod(abs, 0775)
         elif os.path.isfile(abs):
             os.chmod(abs, 0664)
 
--- a/configure	2009-01-11 10:49:38.000000000 -0700
+++ b/configure	2010-01-14 11:59:33.000000000 -0700
@@ -3329,11 +3329,9 @@
     if mailmangid <> gid:
         problems.append("Directory must be owned by group " +
                         groupname + ": " + prefix)
-    if (mode & S_ISGID) <> S_ISGID:
-        problems.append("Set-gid bit must be set for directory: " + prefix)
     perms = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
     if (mode & perms) <> perms:
-        problems.append("Permissions should be at least 02775: " + prefix)
+        problems.append("Permissions should be at least 0775: " + prefix)
 if not problems:
     msg = "okay\n"
 else:
--- a/configure.in	2009-01-11 10:49:38.000000000 -0700
+++ b/configure.in	2010-01-14 11:59:33.000000000 -0700
@@ -394,11 +394,9 @@
     if mailmangid <> gid:
         problems.append("Directory must be owned by group " +
                         groupname + ": " + prefix)
-    if (mode & S_ISGID) <> S_ISGID:
-        problems.append("Set-gid bit must be set for directory: " + prefix)
     perms = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH
     if (mode & perms) <> perms:
-        problems.append("Permissions should be at least 02775: " + prefix)
+        problems.append("Permissions should be at least 0775: " + prefix)
 if not problems:
     msg = "okay\n"
 else:
--- a/contrib/check_perms_grsecurity.py	2009-01-11 10:49:38.000000000 -0700
+++ b/contrib/check_perms_grsecurity.py	2010-01-14 11:59:27.000000000 -0700
@@ -82,7 +82,7 @@
     for dir in dirstochownroot:
         dirpath = paths.prefix + '/' + dir
         os.chown(dirpath, 0, gid)
-        os.chmod(dirpath, 02755)
+        os.chmod(dirpath, 0755)
         print dirpath
 
     print
--- a/misc/Makefile.in	2009-01-11 10:49:38.000000000 -0700
+++ b/misc/Makefile.in	2010-01-14 11:59:25.000000000 -0700
@@ -98,7 +98,7 @@
 	for p in $(PACKAGES); \
 	do \
 	    gunzip -c $(srcdir)/$$p.tar.gz | (cd $(PKGDIR) ; tar xf -); \
-	    (cd $(PKGDIR)/$$p ; umask 02 ; PYTHONPATH=$(PYTHONLIBDIR) $(PYTHON) $(SETUPCMD)); \
+	    (cd $(PKGDIR)/$$p ; umask 02 ; PYTHONPATH=$(PYTHONLIBDIR) CFLAGS="$(BI_RC_CFLAGS)" $(PYTHON) $(SETUPCMD)); \
 	done
 
 finish:
--- a/src/Makefile.in	2009-01-11 10:49:38.000000000 -0700
+++ b/src/Makefile.in	2010-01-14 11:59:24.000000000 -0700
@@ -42,7 +42,7 @@
 
 # Customizable but not set by configure
 OPT=		@OPT@
-CFLAGS=		@CFLAGS@ $(OPT) $(DEFS) $(LIBS)
+CFLAGS=		@CFLAGS@ $(BI_RC_CFLAGS) $(OPT) $(DEFS) $(LIBS)
 CGIDIR= 	$(exec_prefix)/cgi-bin
 CGIEXT=		@CGIEXT@
 MAILDIR=	$(exec_prefix)/mail