#! /usr/bin/env python # # Copyright (C) 1998 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 # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # This better succeed. If this fails, Python is royally screwed so we might # as well let the Web server give us a fatal and obtrusive error. import sys # From here on we are as bulletproof as possible! # This function is useful for debugging. When an error occurs, this attaches # the file name to the exception string and re-raises. This will be # unnecessary in Python 1.5.2, which also does sensible things to most os # module functions. ##realopen = open ##def open(filename, mode='r', bufsize=-1, realopen=realopen): ## from Mailman.Utils import reraise ## try: ## return realopen(filename, mode, bufsize) ## except IOError, e: ## strerror = e.strerror + ': ' + filename ## e.strerror = strerror ## e.filename = filename ## e.args = (e.args[0], strerror) ## reraise(e) ##import __builtin__ ##__builtin__.__dict__['open'] = open # This standard driver script is used to run CGI programs, wrapped in code # that catches errors, and displays them as HTML. This guarantees that # (almost) any problems in the Mailman software doesn't result in a Web server # error. It is much more helpful to generate and show a traceback, which the # user could send to the administrator, than to display a server error and # have to trudge through server logs. # Note: this isn't 100% perfect! Here are some things that can go wrong that # are not caught and reported as traceback-containing HTML: # # - This file could contain a syntax error. In that case, you would indeed # get a Web server error since this file wouldn't even compile, and there's # no way to catch that. # # - The sys module could be royally screwed, probably we couldn't import it. # Both those would indicate serious problems in the Python installation. # These won't generate Web server errors, but neither will they give # meaningful tracebacks. # # I consider these pretty unlikely. def run_main(): try: # These will ensure that even if something between now and the # creation of the real logger below fails, we can still get # *something* meaningful logger = None # insert the relative path to the parent of the Mailman package # directory, so we can pick up the Utils module import os # sys gets imported at module level below sys.path.insert(0, os.pardir) # map stderr to a logger, if possible from Mailman.Logging.StampedLogger import StampedLogger logger = StampedLogger('error', label='admin', manual_reprime=1, nofail=0, immediate=1) # pre-load the `cgi' module. we do this because we're distributing a # slightly different version than the standard Python module. it's # essentially Python 1.5.2's module, with an experimental patch to # handle clients that give bogus or non-existant content-type headers. # # we assign sys.modules['cgi'] to this special cgi module because we # don't want to have to rewrite all the Mailman.Cgi modules to get the # special one. import Mailman.pythonlib.cgi sys.modules['cgi'] = Mailman.pythonlib.cgi # The name of the module to run is passed in argv[1]. What we # actually do is import the module named by argv[1] that lives in the # Mailman.Cgi package. That module must have a main() function, which # we dig out and call. # scriptname = sys.argv[1] # See the reference manual for why we have to do things this way. # Note that importing should have no side-effects! pkg = __import__('Mailman.Cgi', globals(), locals(), [scriptname]) module = getattr(pkg, scriptname) main = getattr(module, 'main') try: main() except SystemExit: # this is a valid way for the function to exit pass except: print_traceback(logger) print_environment(logger) # We are printing error reporting to two places. One will always be stdout # and the other will always be the log file. It is assumed that stdout is an # HTML sink and the log file is a plain text sink. def print_traceback(logfp=None): if logfp is None: logfp = sys.__stderr__ try: import traceback except ImportError: traceback = None try: from Mailman.mm_cfg import VERSION except ImportError: VERSION = '<undetermined>' # write to the log file first logfp.write('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n') logfp.write('[----- Mailman Version: %s -----]\n' % VERSION) logfp.write('[----- Traceback ------]\n') if traceback: traceback.print_exc(file=logfp) else: logfp.write('[failed to import module traceback]\n') logfp.write('[exc: %s, var: %s]\n' % sys.exc_info()[0:2]) # print to the HTML sink print """\ Content-type: text/html Bug in Mailman version %(VERSION)s

Bug in Mailman version %(VERSION)s

We're sorry, we hit a bug!

If you would like to help us identify the problem, please email a copy of this page to the webmaster for this site with a description of what happened. Thanks!

Traceback:

""" % locals()
    if traceback:
        traceback.print_exc(file=sys.stdout)
    else:
        print '[failed to import module traceback]'
        print '[exc: %s, var: %s]' % sys.exc_info()[0:2]
    print '\n\n
' def print_environment(logfp=None): if logfp is None: logfp = sys.__stderr__ try: import os except ImportError: os = None # write to the log file first logfp.write('[----- Environment Variables -----]\n') if os: for k, v in os.environ.items(): logfp.write('\t%s: %s\n' % (k, v)) else: logfp.write('[failed to import module os]\n') # write to the HTML sink if os: print '''\


Environment variables:

''' for k, v in os.environ.items(): print '' print '
Variable Value
', k, '', v, '
' else: print '


[failed to import module os]' try: # Python 1.5 doesn't have these by default. Let's make our lives easy if not hasattr(sys, '__stderr__'): sys.__stderr__ = sys.stderr if not hasattr(sys, '__stdout__'): sys.__stdout__ = sys.stdout run_main() except: # Some exception percolated all the way back up to the top. This # generally shouldn't happen because the run_main() call is similarly # wrapped, but just in case, we'll give it one last ditch effort to report # problems to *somebody*. Most likely this will end up in the Web server # log file. try: print_traceback() print_environment() except: # Nope, we're quite screwed print """\ Content-type: text/html

We're sorry, we hit a bug!

Mailman experienced a very low level failure and could not even generate a useful traceback for you. Please report this to the Mailman administrator at this site. """ sys.__stderr__.write('[Mailman: low level unrecoverable exception]\n')