# # exception.py - general exception formatting and saving # # Matt Wilson # Erik Troan # # Copyright 2000-2002 Red Hat, Inc. # # This software may be freely redistributed under the terms of the GNU # library public license. # # You should have received a copy of the GNU Library Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # import isys import sys import os import signal import traceback import iutil import types import rpm from string import joinfields from cPickle import Pickler from rhpl.translate import _ from flags import flags dumpHash = {} # XXX do length limits on obj dumps. def dumpClass(instance, fd, level=0): # protect from loops if not dumpHash.has_key(instance): dumpHash[instance] = None else: fd.write("Already dumped\n") return if (instance.__class__.__dict__.has_key("__str__") or instance.__class__.__dict__.has_key("__repr__")): fd.write("%s\n" % (instance,)) return fd.write("%s instance, containing members:\n" % (instance.__class__.__name__)) pad = ' ' * ((level) * 2) for key, value in instance.__dict__.items(): if type(value) == types.ListType: fd.write("%s%s: [" % (pad, key)) first = 1 for item in value: if not first: fd.write(", ") else: first = 0 if type(item) == types.InstanceType: dumpClass(item, fd, level + 1) else: fd.write("%s" % (item,)) fd.write("]\n") elif type(value) == types.DictType: fd.write("%s%s: {" % (pad, key)) first = 1 for k, v in value.items(): if not first: fd.write(", ") else: first = 0 if type(k) == types.StringType: fd.write("'%s': " % (k,)) else: fd.write("%s: " % (k,)) if type(v) == types.InstanceType: dumpClass(v, fd, level + 1) else: fd.write("%s" % (v,)) fd.write("}\n") elif type(value) == types.InstanceType: fd.write("%s%s: " % (pad, key)) dumpClass(value, fd, level + 1) else: fd.write("%s%s: %s\n" % (pad, key, value)) def dumpException(out, text, tb, dispatch): p = Pickler(out) out.write(text) trace = tb while trace.tb_next: trace = trace.tb_next frame = trace.tb_frame out.write ("\nLocal variables in innermost frame:\n") try: for (key, value) in frame.f_locals.items(): out.write ("%s: %s\n" % (key, value)) except: pass if dispatch.id.comps: out.write("\n\nPackage Group selection status:\n") for comp in dispatch.id.comps: out.write("%s: %s\n" % (comp.name, comp.isSelected(justManual = 1))) if dispatch.id.hdList: out.write("\n\nIndividual package selection status:\n") pkgList = dispatch.id.hdList.keys() pkgList.sort() for pkg in pkgList: p = dispatch.id.hdList[pkg] out.write("%s: %s, " % (p[rpm.RPMTAG_NAME], p.isSelected())) out.write("\n") # these have C objects in them which can't dump dispatch.id.hdList = None dispatch.id.comps = None # we don't need to know passwords dispatch.id.rootPassword = None dispatch.id.accounts = None # dispatch.intf = None # dispatch.dispatch = None try: if dispatch.id.xsetup and dispatch.id.xsetup.xhwstate and dispatch.id.xsetup.xhwstate.monitor: dispatch.id.xsetup.xhwstate.monitor.monlist = None dispatch.id.xsetup.xhwstate.monitor.monids = None dispatch.id.langSupport.langNicks = None dispatch.id.langSupport.langList = None dispatch.id.langSupport.allSupportedLangs = None dispatch.intf.icw.buff = None except: pass try: out.write("\n\n") dumpClass(dispatch, out) except: out.write("\nException occurred during state dump:\n") traceback.print_exc(None, out) for file in ("/tmp/syslog", "/tmp/anaconda.log", "/tmp/netinfo", dispatch.instPath + "/root/install.log", dispatch.instPath + "/root/upgrade.log"): try: f = open(file, 'r') line = "\n\n%s:\n" % (file,) while line: out.write(line) line = f.readline() f.close() except IOError: pass except: out.write("\nException occurred during %s file copy:\n" % (file,)) traceback.print_exc(None, out) def handleException(dispatch, intf, (type, value, tb)): # restore original exception handler sys.excepthook = sys.__excepthook__ list = traceback.format_exception (type, value, tb) text = joinfields (list, "") rc = intf.exceptionWindow (_("Exception Occurred"), text) if rc == 1: intf.__del__ () print text import pdb pdb.post_mortem (tb) os.kill(os.getpid(), signal.SIGKILL) elif not rc: intf.__del__ () os.kill(os.getpid(), signal.SIGKILL) if not flags.setupFilesystems: out = open("/tmp/anacdump.txt", "w") dumpException (out, text, tb, dispatch) out.close() intf.__del__ () os.kill(os.getpid(), signal.SIGKILL) while 1: rc = intf.dumpWindow() if rc: intf.__del__ () os.kill(os.getpid(), signal.SIGKILL) device = dispatch.id.floppyDevice file = "/tmp/floppy" try: isys.makeDevInode(device, file) except SystemError: pass try: fd = os.open(file, os.O_RDONLY) except: continue os.close(fd) if iutil.getArch() != "ia64": args = [ 'mkdosfs', '/tmp/floppy' ] cmd = "/usr/sbin/mkdosfs" if os.access("/sbin/mkdosfs", os.X_OK): cmd = "/sbin/mkdosfs" iutil.execWithRedirect (cmd, args, stdout = '/dev/tty5', stderr = '/dev/tty5') try: isys.mount(device, "/tmp/crash", fstype = "vfat") except SystemError: continue out = open("/tmp/crash/anacdump.txt", "w") dumpException (out, text, tb, dispatch) out.close() # write out any syslog information as well try: iutil.copyFile("/tmp/syslog", "/tmp/crash") except: pass isys.umount("/tmp/crash") intf.messageWindow(_("Dump Written"), _("Your system's state has been successfully written to the " "floppy. Your system will now be reset.")) intf.__del__ () os.kill(os.getpid(), signal.SIGKILL)