--- 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