diff options
| -rw-r--r-- | Mailman/Cgi/create.py | 12 | ||||
| -rw-r--r-- | Mailman/Cgi/edithtml.py | 11 | ||||
| -rw-r--r-- | Mailman/Handlers/Scrubber.py | 32 | ||||
| -rw-r--r-- | Mailman/Handlers/ToDigest.py | 8 | ||||
| -rw-r--r-- | Mailman/ListAdmin.py | 38 | ||||
| -rw-r--r-- | Mailman/LockFile.py | 10 | ||||
| -rw-r--r-- | Mailman/MTA/Postfix.py | 20 | ||||
| -rw-r--r-- | Mailman/Pending.py | 18 | ||||
| -rw-r--r-- | Mailman/Queue/BounceRunner.py | 8 | ||||
| -rw-r--r-- | Mailman/Queue/HTTPRunner.py | 1 | ||||
| -rw-r--r-- | Mailman/Queue/Switchboard.py | 28 | ||||
| -rw-r--r-- | Mailman/Utils.py | 7 | ||||
| -rw-r--r-- | Mailman/bin/genaliases.py | 7 | ||||
| -rw-r--r-- | Mailman/bin/import.py | 6 | ||||
| -rw-r--r-- | Mailman/bin/mailmanctl.py | 15 | ||||
| -rw-r--r-- | Mailman/bin/newlist.py | 36 | ||||
| -rw-r--r-- | Mailman/bin/nightly_gzip.py | 16 | ||||
| -rw-r--r-- | Mailman/bin/update.py | 10 | ||||
| -rw-r--r-- | Mailman/database/__init__.py | 17 | ||||
| -rw-r--r-- | Mailman/database/dbcontext.py | 30 | ||||
| -rw-r--r-- | Mailman/initialize.py | 11 |
21 files changed, 138 insertions, 203 deletions
diff --git a/Mailman/Cgi/create.py b/Mailman/Cgi/create.py index 8c11f22e5..53001b356 100644 --- a/Mailman/Cgi/create.py +++ b/Mailman/Cgi/create.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,7 +17,6 @@ """Create mailing lists through the web.""" -import os import cgi import sha import sys @@ -162,15 +161,8 @@ def process_request(doc, cgidata): mlist = MailList.MailList() try: pw = sha.new(password).hexdigest() - # Guarantee that all newly created files have the proper permission. - # proper group ownership should be assured by the autoconf script - # enforcing that all directories have the group sticky bit set - oldmask = os.umask(002) try: - try: - mlist.Create(fqdn_listname, owner, pw, langs) - finally: - os.umask(oldmask) + mlist.Create(fqdn_listname, owner, pw, langs) except Errors.EmailAddressError, s: request_creation(doc, cgidata, _('Bad owner email address: $s')) return diff --git a/Mailman/Cgi/edithtml.py b/Mailman/Cgi/edithtml.py index 6083bfdb9..bac719b6d 100644 --- a/Mailman/Cgi/edithtml.py +++ b/Mailman/Cgi/edithtml.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -165,14 +165,7 @@ def ChangeHTML(mlist, cgi_info, template_name, doc): code = re.sub(r'<([/]?script.*?)>', r'<\1>', code) langdir = os.path.join(mlist.fullpath(), mlist.preferred_language) # Make sure the directory exists - omask = os.umask(0) - try: - try: - os.mkdir(langdir, 02775) - except OSError, e: - if e.errno <> errno.EEXIST: raise - finally: - os.umask(omask) + Utils.makedirs(langdir) fp = open(os.path.join(langdir, template_name), 'w') try: fp.write(code) diff --git a/Mailman/Handlers/Scrubber.py b/Mailman/Handlers/Scrubber.py index 0dc21d8c4..e14f9a549 100644 --- a/Mailman/Handlers/Scrubber.py +++ b/Mailman/Handlers/Scrubber.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -176,11 +176,7 @@ def process(mlist, msg, msgdata=None): # TK: if part is attached then check charset and scrub if none if part.get('content-disposition') and \ not part.get_content_charset(): - omask = os.umask(002) - try: - url = save_attachment(mlist, part, dir) - finally: - os.umask(omask) + url = save_attachment(mlist, part, dir) filename = part.get_filename(_('not available')) filename = Utils.oneline(filename, lcset) replace_payload_by_text(part, _("""\ @@ -204,11 +200,7 @@ Url: %(url)s # Pull it out as an attachment but leave it unescaped. This # is dangerous, but perhaps useful for heavily moderated # lists. - omask = os.umask(002) - try: - url = save_attachment(mlist, part, dir, filter_html=False) - finally: - os.umask(omask) + url = save_attachment(mlist, part, dir, filter_html=False) replace_payload_by_text(part, _("""\ An HTML attachment was scrubbed... URL: %(url)s @@ -229,11 +221,7 @@ URL: %(url)s # We're replacing the payload with the decoded payload so this # will just get in the way. del part['content-transfer-encoding'] - omask = os.umask(002) - try: - url = save_attachment(mlist, part, dir, filter_html=False) - finally: - os.umask(omask) + url = save_attachment(mlist, part, dir, filter_html=False) replace_payload_by_text(part, _("""\ An HTML attachment was scrubbed... URL: %(url)s @@ -241,11 +229,7 @@ URL: %(url)s elif ctype == 'message/rfc822': # This part contains a submessage, so it too needs scrubbing submsg = part.get_payload(0) - omask = os.umask(002) - try: - url = save_attachment(mlist, part, dir) - finally: - os.umask(omask) + url = save_attachment(mlist, part, dir) subject = submsg.get('subject', _('no subject')) date = submsg.get('date', _('no date')) who = submsg.get('from', _('unknown sender')) @@ -273,11 +257,7 @@ Url: %(url)s if payload is None: continue size = len(payload) - omask = os.umask(002) - try: - url = save_attachment(mlist, part, dir) - finally: - os.umask(omask) + url = save_attachment(mlist, part, dir) desc = part.get('content-description', _('not available')) filename = part.get_filename(_('not available')) filename = Utils.oneline(filename, lcset) diff --git a/Mailman/Handlers/ToDigest.py b/Mailman/Handlers/ToDigest.py index f759e82c8..471886afc 100644 --- a/Mailman/Handlers/ToDigest.py +++ b/Mailman/Handlers/ToDigest.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -67,11 +67,7 @@ def process(mlist, msg, msgdata): if not mlist.digestable or msgdata.get('isdigest'): return mboxfile = os.path.join(mlist.fullpath(), 'digest.mbox') - omask = os.umask(007) - try: - mboxfp = open(mboxfile, 'a+') - finally: - os.umask(omask) + mboxfp = open(mboxfile, 'a+') mbox = Mailbox(mboxfp) mbox.AppendMessage(msg) # Calculate the current size of the accumulation file. This will not tell diff --git a/Mailman/ListAdmin.py b/Mailman/ListAdmin.py index 84b97e2fd..bcef7d2c9 100644 --- a/Mailman/ListAdmin.py +++ b/Mailman/ListAdmin.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -98,17 +98,13 @@ class ListAdmin: # should we be as paranoid as for the config.pck file? Should we # use pickle? tmpfile = self.__filename + '.tmp' - omask = os.umask(002) + fp = open(tmpfile, 'w') try: - fp = open(tmpfile, 'w') - try: - cPickle.dump(self.__db, fp, 1) - fp.flush() - os.fsync(fp.fileno()) - finally: - fp.close() + cPickle.dump(self.__db, fp, 1) + fp.flush() + os.fsync(fp.fileno()) finally: - os.umask(omask) + fp.close() self.__db = None # Do the dance os.rename(tmpfile, self.__filename) @@ -191,21 +187,17 @@ class ListAdmin: else: ext = 'txt' filename = 'heldmsg-%s-%d.%s' % (self.internal_name(), id, ext) - omask = os.umask(002) + fp = open(os.path.join(config.DATA_DIR, filename), 'w') try: - fp = open(os.path.join(config.DATA_DIR, filename), 'w') - try: - if config.HOLD_MESSAGES_AS_PICKLES: - cPickle.dump(msg, fp, 1) - else: - g = Generator(fp) - g(msg, 1) - fp.flush() - os.fsync(fp.fileno()) - finally: - fp.close() + if config.HOLD_MESSAGES_AS_PICKLES: + cPickle.dump(msg, fp, 1) + else: + g = Generator(fp) + g(msg, 1) + fp.flush() + os.fsync(fp.fileno()) finally: - os.umask(omask) + fp.close() # save the information to the request database. for held message # entries, each record in the database will be of the following # format: diff --git a/Mailman/LockFile.py b/Mailman/LockFile.py index 06d5c5f8e..d13699ec4 100644 --- a/Mailman/LockFile.py +++ b/Mailman/LockFile.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -369,15 +369,11 @@ class LockFile: def _write(self): # Make sure it's group writable - oldmask = os.umask(002) - fp = None + fp = open(self._tmpfname, 'w') try: - fp = open(self._tmpfname, 'w') fp.write(self._tmpfname) finally: - if fp: - fp.close() - os.umask(oldmask) + fp.close() def _read(self): try: diff --git a/Mailman/MTA/Postfix.py b/Mailman/MTA/Postfix.py index 2c6f8c60e..6b43011ff 100644 --- a/Mailman/MTA/Postfix.py +++ b/Mailman/MTA/Postfix.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -174,11 +174,7 @@ def _check_for_virtual_loopaddr(mlist, filename, func): if func is _addtransport: loopdest = 'local:' + loopdest infp = open(filename) - omask = os.umask(007) - try: - outfp = open(filename + '.tmp', 'w') - finally: - os.umask(omask) + outfp = open(filename + '.tmp', 'w') try: # Find the start of the loop address block while True: @@ -264,11 +260,7 @@ def _do_create(mlist, textfile, func): fp = open(textfile, 'r+') except IOError, e: if e.errno <> errno.ENOENT: raise - omask = os.umask(007) - try: - fp = open(textfile, 'w+') - finally: - os.umask(omask) + fp = open(textfile, 'w+') try: func(mlist, fp) finally: @@ -313,11 +305,7 @@ def _do_remove(mlist, textfile): # Otherwise, there's no text file to filter so we're done. return try: - omask = os.umask(007) - try: - outfp = open(textfile + '.tmp', 'w') - finally: - os.umask(omask) + outfp = open(textfile + '.tmp', 'w') filteroutp = False start = '# STANZA START: %s@%s' % (listname, hostname) end = '# STANZA END: %s@%s' % (listname, hostname) diff --git a/Mailman/Pending.py b/Mailman/Pending.py index eb3b7950e..f5794453d 100644 --- a/Mailman/Pending.py +++ b/Mailman/Pending.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -113,18 +113,14 @@ class Pending: del evictions[cookie] db['version'] = config.PENDING_FILE_SCHEMA_VERSION tmpfile = '%s.tmp.%d.%d' % (self.__pendfile, os.getpid(), now) - omask = os.umask(007) + fp = open(tmpfile, 'w') try: - fp = open(tmpfile, 'w') - try: - cPickle.dump(db, fp) - fp.flush() - os.fsync(fp.fileno()) - finally: - fp.close() - os.rename(tmpfile, self.__pendfile) + cPickle.dump(db, fp) + fp.flush() + os.fsync(fp.fileno()) finally: - os.umask(omask) + fp.close() + os.rename(tmpfile, self.__pendfile) def pend_confirm(self, cookie, expunge=True): """Return data for cookie, or None if not found. diff --git a/Mailman/Queue/BounceRunner.py b/Mailman/Queue/BounceRunner.py index 2d132708a..d398e1b4a 100644 --- a/Mailman/Queue/BounceRunner.py +++ b/Mailman/Queue/BounceRunner.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -86,11 +86,7 @@ class BounceMixin: def _queue_bounces(self, listname, addrs, msg): today = time.localtime()[:3] if self._bounce_events_fp is None: - omask = os.umask(006) - try: - self._bounce_events_fp = open(self._bounce_events_file, 'a+b') - finally: - os.umask(omask) + self._bounce_events_fp = open(self._bounce_events_file, 'a+b') for addr in addrs: cPickle.dump((listname, addr, today, msg), self._bounce_events_fp, 1) diff --git a/Mailman/Queue/HTTPRunner.py b/Mailman/Queue/HTTPRunner.py index 32620f458..1858cff58 100644 --- a/Mailman/Queue/HTTPRunner.py +++ b/Mailman/Queue/HTTPRunner.py @@ -61,6 +61,7 @@ server = make_server(config.HTTP_HOST, config.HTTP_PORT, qlog.info('HTTPRunner qrunner started.') +hlog.info('HTTPRunner listening on %s:%s', config.HTTP_HOST, config.HTTP_PORT) try: server.serve_forever() # Do it this way because of exception hierarchy changes in Python 2.5. XXX diff --git a/Mailman/Queue/Switchboard.py b/Mailman/Queue/Switchboard.py index bc16bbd2d..faf0988e1 100644 --- a/Mailman/Queue/Switchboard.py +++ b/Mailman/Queue/Switchboard.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -65,15 +65,7 @@ class Switchboard: def __init__(self, whichq, slice=None, numslices=1, recover=False): self.__whichq = whichq # Create the directory if it doesn't yet exist. - # FIXME - omask = os.umask(0) # rwxrws--- - try: - try: - os.mkdir(self.__whichq, 0770) - except OSError, e: - if e.errno <> errno.EEXIST: raise - finally: - os.umask(omask) + Utils.makedirs(self.__whichq, 0770) # Fast track for no slices self.__lower = None self.__upper = None @@ -122,18 +114,14 @@ class Switchboard: # object or not. data['_parsemsg'] = (protocol == 0) # Write to the pickle file the message object and metadata. - omask = os.umask(007) # -rw-rw---- + fp = open(tmpfile, 'w') try: - fp = open(tmpfile, 'w') - try: - fp.write(msgsave) - cPickle.dump(data, fp, protocol) - fp.flush() - os.fsync(fp.fileno()) - finally: - fp.close() + fp.write(msgsave) + cPickle.dump(data, fp, protocol) + fp.flush() + os.fsync(fp.fileno()) finally: - os.umask(omask) + fp.close() os.rename(tmpfile, filename) return filebase diff --git a/Mailman/Utils.py b/Mailman/Utils.py index d89d45f59..0d46e7d32 100644 --- a/Mailman/Utils.py +++ b/Mailman/Utils.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -347,6 +347,7 @@ def set_global_password(pw, siteadmin=True): else: filename = config.LISTCREATOR_PW_FILE # rw-r----- + # XXX Is the default umask of 007 good enough? omask = os.umask(026) try: fp = open(filename, 'w') @@ -641,11 +642,11 @@ def reap(kids, func=None, once=False): -def makedirs(path): +def makedirs(path, mode=02775): try: omask = os.umask(0) try: - os.makedirs(path, 02775) + os.makedirs(path, mode) finally: os.umask(omask) except OSError, e: diff --git a/Mailman/bin/genaliases.py b/Mailman/bin/genaliases.py index 2796804df..4ce8160fd 100644 --- a/Mailman/bin/genaliases.py +++ b/Mailman/bin/genaliases.py @@ -1,6 +1,6 @@ #! @PYTHON@ # -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -17,7 +17,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. -import os import sys import optparse @@ -72,9 +71,6 @@ def main(): for listname in Utils.list_names(): mlist = MailList.MailList(listname, lock=False) mlists.setdefault(mlist.host_name, []).append(mlist) - # Make sure the files are created rw-rw-xxx; it should be okay to be world - # readable. - omask = os.umask(002) try: MTA.clear() if not mlists: @@ -86,7 +82,6 @@ def main(): # Be verbose for only the first printed list quiet = True finally: - os.umask(omask) lock.unlock(unconditionally=True) diff --git a/Mailman/bin/import.py b/Mailman/bin/import.py index 68876def1..b643de389 100644 --- a/Mailman/bin/import.py +++ b/Mailman/bin/import.py @@ -48,12 +48,12 @@ def nodetext(node): return u'' -def nodegen(node, *entities): +def nodegen(node, *elements): for child in node.childNodes: if child.nodeType <> minidom.Node.ELEMENT_NODE: continue - if entities and child.tagName not in entities: - print _('Ignoring unexpected entity: $node.tagName') + if elements and child.tagName not in elements: + print _('Ignoring unexpected element: $node.tagName') else: yield child diff --git a/Mailman/bin/mailmanctl.py b/Mailman/bin/mailmanctl.py index 5c85799bc..db74214c0 100644 --- a/Mailman/bin/mailmanctl.py +++ b/Mailman/bin/mailmanctl.py @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 by the Free Software Foundation, Inc. +# Copyright (C) 2001-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -261,7 +261,7 @@ def start_runner(qrname, slice, count): args.extend(['-C', opts.config]) os.execl(*args) # Should never get here - raise RuntimeError, 'os.execl() failed' + raise RuntimeError('os.execl() failed') def start_all_runners(): @@ -371,23 +371,18 @@ def main(): 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) + # Save our pid in a file for "mailmanctl stop" rendezvous. + fp = open(config.PIDFILE, 'w') try: - fp = open(config.PIDFILE, 'w') print >> fp, os.getpid() - fp.close() finally: - os.umask(omask) + fp.close() # 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(config.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 diff --git a/Mailman/bin/newlist.py b/Mailman/bin/newlist.py index edd7ad7bd..a127b25e1 100644 --- a/Mailman/bin/newlist.py +++ b/Mailman/bin/newlist.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -15,7 +15,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. -import os import sha import sys import getpass @@ -148,27 +147,20 @@ def main(): mlist.preferred_language = opts.language try: pw = sha.new(listpasswd).hexdigest() - # Guarantee that all newly created files have the proper permission. - # proper group ownership should be assured by the autoconf script - # enforcing that all directories have the group sticky bit set. - oldmask = os.umask(002) try: - try: - mlist.Create(fqdn_listname, owner_mail, pw) - except Errors.BadListNameError, s: - parser.print_help() - print >> sys.stderr, _('Illegal list name: $s') - sys.exit(1) - except Errors.EmailAddressError, s: - parser.print_help() - print >> sys.stderr, _('Bad owner email address: $s') - sys.exit(1) - except Errors.MMListAlreadyExistsError: - parser.print_help() - print >> sys.stderr, _('List already exists: $listname') - sys.exit(1) - finally: - os.umask(oldmask) + mlist.Create(fqdn_listname, owner_mail, pw) + except Errors.BadListNameError, s: + parser.print_help() + print >> sys.stderr, _('Illegal list name: $s') + sys.exit(1) + except Errors.EmailAddressError, s: + parser.print_help() + print >> sys.stderr, _('Bad owner email address: $s') + sys.exit(1) + except Errors.MMListAlreadyExistsError: + parser.print_help() + print >> sys.stderr, _('List already exists: $listname') + sys.exit(1) mlist.Save() finally: mlist.Unlock() diff --git a/Mailman/bin/nightly_gzip.py b/Mailman/bin/nightly_gzip.py index f55b21493..4bd9271bc 100644 --- a/Mailman/bin/nightly_gzip.py +++ b/Mailman/bin/nightly_gzip.py @@ -1,6 +1,4 @@ -#! @PYTHON@ -# -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -31,6 +29,7 @@ from Mailman import Utils from Mailman import Version from Mailman.configuration import config from Mailman.i18n import _ +from Mailman.initialize import initialize __i18n_templates__ = True @@ -77,7 +76,7 @@ def compress(txtfile, opts): def main(): opts, args, parser = parseargs() - config.load(opts.config) + initialize(opts.config) if config.ARCHIVE_TO_MBOX not in (1, 2) or config.GZIP_ARCHIVE_TXT_FILES: # We're only going to run the nightly archiver if messages are @@ -119,12 +118,3 @@ def main(): files.append(txtfile) for f in files: compress(f, opts) - - - -if __name__ == '__main__': - omask = os.umask(002) - try: - main() - finally: - os.umask(omask) diff --git a/Mailman/bin/update.py b/Mailman/bin/update.py index b6953e007..281f40420 100644 --- a/Mailman/bin/update.py +++ b/Mailman/bin/update.py @@ -1,4 +1,4 @@ -# Copyright (C) 1998-2006 by the Free Software Foundation, Inc. +# Copyright (C) 1998-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -255,9 +255,7 @@ def dolist(listname): o_html_dir = makeabs('public_html/archives/%s' % (listname)) # Make the mbox directory if it's not there. if not os.path.exists(mbox_dir): - ou = os.umask(0) - os.mkdir(mbox_dir, 02775) - os.umask(ou) + Utils.makedirs(mbox_dir) else: # This shouldn't happen, but hey, just in case if not os.path.isdir(mbox_dir): @@ -265,9 +263,7 @@ def dolist(listname): For some reason, $mbox_dir exists as a file. This won't work with b6, so I'm renaming it to ${mbox_dir}.tmp and proceeding.""") os.rename(mbox_dir, "%s.tmp" % (mbox_dir)) - ou = os.umask(0) - os.mkdir(mbox_dir, 02775) - os.umask(ou) + Utils.makedirs(mbox_dir) # Move any existing mboxes around, but watch out for both a public and a # private one existing if os.path.isfile(o_pri_mbox_file) and os.path.isfile(o_pub_mbox_file): diff --git a/Mailman/database/__init__.py b/Mailman/database/__init__.py index a2b6c97ce..808ad9fd0 100644 --- a/Mailman/database/__init__.py +++ b/Mailman/database/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006 by the Free Software Foundation, Inc. +# Copyright (C) 2006-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -22,12 +22,23 @@ # from Mailman import database # database.add_list(foo) +import os + def initialize(): from Mailman import database + from Mailman.LockFile import LockFile + from Mailman.configuration import config from Mailman.database.dbcontext import dbcontext - - dbcontext.connect() + # Serialize this so we don't get multiple processes trying to create the + # database at the same time. + lockfile = os.path.join(config.LOCK_DIR, '<dbcreatelock>') + lock = LockFile(lockfile) + lock.lock() + try: + dbcontext.connect() + finally: + lock.unlock() for attr in dir(dbcontext): if attr.startswith('api_'): exposed_name = attr[4:] diff --git a/Mailman/database/dbcontext.py b/Mailman/database/dbcontext.py index a13f20498..b2b1fb826 100644 --- a/Mailman/database/dbcontext.py +++ b/Mailman/database/dbcontext.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006 by the Free Software Foundation, Inc. +# Copyright (C) 2006-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -15,10 +15,12 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, # USA. +import os import weakref from sqlalchemy import * from string import Template +from urlparse import urlparse from Mailman import Version from Mailman.configuration import config @@ -49,6 +51,21 @@ class DBContext(object): # Calculate the engine url url = Template(config.SQLALCHEMY_ENGINE_URL).safe_substitute( config.paths) + # XXX By design of SQLite, database file creation does not honor + # umask. See their ticket #1193: + # http://www.sqlite.org/cvstrac/tktview?tn=1193,31 + # + # This sucks for us because the mailman.db file /must/ be group + # writable, however even though we guarantee our umask is 002 here, it + # still gets created without the necessary g+w permission, due to + # SQLite's policy. This should only affect SQLite engines because its + # the only one that creates a little file on the local file system. + # This kludges around their bug by "touch"ing the database file before + # SQLite has any chance to create it, thus honoring the umask and + # ensuring the right permissions. We only try to do this for SQLite + # engines, and yes, we could have chmod'd the file after the fact, but + # half dozen and all... + self._touch(url) self.metadata = BoundMetaData(url) self.metadata.engine.echo = config.SQLALCHEMY_ECHO # Create all the table objects, and then let SA conditionally create @@ -74,6 +91,17 @@ class DBContext(object): raise SchemaVersionMismatchError(row.version) self.session = create_session() + def _touch(self, url): + parts = urlparse(url) + # XXX Python 2.5; use parts.scheme and parts.path + if parts[0] <> 'sqlite': + return + path = os.path.normpath(parts[2]) + fd = os.open(path, os.O_WRONLY | os.O_NONBLOCK | os.O_CREAT, 0666) + # Ignore errors + if fd > 0: + os.close(fd) + # Cooperative method for use with @txn decorator def _withtxn(self, meth, *args, **kws): try: diff --git a/Mailman/initialize.py b/Mailman/initialize.py index db26d15df..ddd4b1c3e 100644 --- a/Mailman/initialize.py +++ b/Mailman/initialize.py @@ -1,4 +1,4 @@ -# Copyright (C) 2006 by the Free Software Foundation, Inc. +# Copyright (C) 2006-2007 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,6 +24,8 @@ line argument parsing, since some of the initialization behavior is controlled by the command line arguments. """ +import os + import Mailman.configuration import Mailman.database import Mailman.loginit @@ -31,6 +33,13 @@ import Mailman.loginit def initialize(config=None, propagate_logs=False): + # By default, set the umask so that only owner and group can read and + # write our files. Specifically we must have g+rw and we probably want + # o-rwx although I think in most cases it doesn't hurt if other can read + # or write the files. Note that the Pipermail archive has more + # restrictive permissions in order to handle private archives, but it + # handles that correctly. + os.umask(007) Mailman.configuration.config.load(config) Mailman.loginit.initialize(propagate_logs) Mailman.database.initialize() |
