|
Packit |
8ea169 |
#:mode=python:
|
|
Packit |
8ea169 |
# -*- coding: utf-8 -*-
|
|
Packit |
8ea169 |
## Copyright (C) 2001-2005 Red Hat, Inc.
|
|
Packit |
8ea169 |
## Copyright (C) 2001-2005 Harald Hoyer <harald@redhat.com>
|
|
Packit |
8ea169 |
## Copyright (C) 2009 Jiri Moskovcak <jmoskovc@redhat.com>
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
## This program is free software; you can redistribute it and/or modify
|
|
Packit |
8ea169 |
## it under the terms of the GNU General Public License as published by
|
|
Packit |
8ea169 |
## the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
8ea169 |
## (at your option) any later version.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
## This program is distributed in the hope that it will be useful,
|
|
Packit |
8ea169 |
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8ea169 |
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8ea169 |
## GNU General Public License for more details.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
## You should have received a copy of the GNU General Public License
|
|
Packit |
8ea169 |
## along with this program; if not, write to the Free Software
|
|
Packit |
8ea169 |
## Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
Module for the ABRT exception handling hook
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
import sys
|
|
Packit |
8ea169 |
import os
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
class RPMinfoError(Exception):
|
|
Packit |
8ea169 |
"""Exception class for RPMdb-querying related errors"""
|
|
Packit |
8ea169 |
pass
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
def syslog(msg):
|
|
Packit |
8ea169 |
"""Log message to system logger (journal)"""
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
from systemd import journal
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# required as a workaround for rhbz#1023041
|
|
Packit |
8ea169 |
# where journal tries to log into non-existent log
|
|
Packit |
8ea169 |
# and fails (during %check in mock)
|
|
Packit |
8ea169 |
#
|
|
Packit |
8ea169 |
# try/except block should be removed when the bug is fixed
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
journal.send(msg)
|
|
Packit |
8ea169 |
except:
|
|
Packit |
8ea169 |
pass
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
def write_dump(tb_text, tb):
|
|
Packit |
8ea169 |
if sys.argv[0][0] == "/":
|
|
Packit |
8ea169 |
executable = os.path.abspath(sys.argv[0])
|
|
Packit |
8ea169 |
else:
|
|
Packit |
8ea169 |
# We don't know the path.
|
|
Packit |
8ea169 |
# (BTW, we *can't* assume the script is in current directory.)
|
|
Packit |
8ea169 |
executable = sys.argv[0]
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Open ABRT daemon's socket and write data to it
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
import socket
|
|
Packit |
8ea169 |
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
Packit |
8ea169 |
s.settimeout(5)
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
s.connect("/var/run" + "/abrt/abrt.socket")
|
|
Packit |
8ea169 |
s.sendall("POST / HTTP/1.1\r\n\r\n")
|
|
Packit |
8ea169 |
s.sendall("type=Python\0")
|
|
Packit |
8ea169 |
s.sendall("analyzer=abrt-python-handler\0")
|
|
Packit |
8ea169 |
s.sendall("pid=%s\0" % os.getpid())
|
|
Packit |
8ea169 |
s.sendall("executable=%s\0" % executable)
|
|
Packit |
8ea169 |
# This handler puts a short(er) crash descr in 1st line of the backtrace.
|
|
Packit |
8ea169 |
# Example:
|
|
Packit |
8ea169 |
# CCMainWindow.py:1:<module>:ZeroDivisionError: integer division or modulo by zero
|
|
Packit |
8ea169 |
s.sendall("reason=%s\0" % tb_text.splitlines()[0])
|
|
Packit |
8ea169 |
s.sendall("backtrace=%s\0" % tb_text)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
s.shutdown(socket.SHUT_WR)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Read the response and log if there's anything wrong
|
|
Packit |
8ea169 |
response = ""
|
|
Packit |
8ea169 |
while True:
|
|
Packit |
8ea169 |
buf = s.recv(256)
|
|
Packit |
8ea169 |
if not buf:
|
|
Packit |
8ea169 |
break
|
|
Packit |
8ea169 |
response += buf
|
|
Packit |
8ea169 |
except socket.timeout as ex:
|
|
Packit |
8ea169 |
syslog("communication with ABRT daemon failed: %s" % str(ex))
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
s.close()
|
|
Packit |
8ea169 |
parts = response.split()
|
|
Packit |
8ea169 |
if (len(parts) < 2
|
|
Packit |
8ea169 |
or (not parts[0].startswith("HTTP/"))
|
|
Packit |
8ea169 |
or (not parts[1].isdigit())
|
|
Packit |
8ea169 |
or (int(parts[1]) >= 400)):
|
|
Packit |
8ea169 |
syslog("error sending data to ABRT daemon: %s" % response)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
except Exception as ex:
|
|
Packit |
8ea169 |
syslog("can't communicate with ABRT daemon, is it running? %s" % str(ex))
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
def require_abs_path():
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
Return True if absolute path requirement is enabled
|
|
Packit |
8ea169 |
in configuration
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
import problem
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
conf = problem.load_plugin_conf_file("python.conf")
|
|
Packit |
8ea169 |
except OsError:
|
|
Packit |
8ea169 |
return False
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return conf.get("RequireAbsolutePath", "yes") == "yes"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
def handleMyException((etype, value, tb)):
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
The exception handling function.
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
progname - the name of the application
|
|
Packit |
8ea169 |
version - the version of the application
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
# Restore original exception handler
|
|
Packit |
8ea169 |
sys.excepthook = sys.__excepthook__ # pylint: disable-msg=E1101
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
import errno
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Ignore Ctrl-C
|
|
Packit |
8ea169 |
# SystemExit rhbz#636913 -> this exception is not an error
|
|
Packit |
8ea169 |
if etype in [KeyboardInterrupt, SystemExit]:
|
|
Packit |
8ea169 |
return sys.__excepthook__(etype, value, tb)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Ignore EPIPE: it happens all the time
|
|
Packit |
8ea169 |
# Testcase: script.py | true, where script.py is:
|
|
Packit |
8ea169 |
## #!/usr/bin/python
|
|
Packit |
8ea169 |
## import os
|
|
Packit |
8ea169 |
## import time
|
|
Packit |
8ea169 |
## time.sleep(1)
|
|
Packit |
8ea169 |
## os.write(1, "Hello\n") # print "Hello" wouldn't be the same
|
|
Packit |
8ea169 |
#
|
|
Packit |
8ea169 |
if etype == IOError or etype == OSError:
|
|
Packit |
8ea169 |
if value.errno == errno.EPIPE:
|
|
Packit |
8ea169 |
return sys.__excepthook__(etype, value, tb)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Ignore interactive Python and similar
|
|
Packit |
8ea169 |
# Check for first "-" is meant to catch "-c" which appears in this case:
|
|
Packit |
8ea169 |
## $ python -c 'import sys; print "argv0 is:%s" % sys.argv[0]'
|
|
Packit |
8ea169 |
## argv0 is:-c
|
|
Packit |
8ea169 |
# Are there other cases when sys.argv[0][0] is "-"?
|
|
Packit |
8ea169 |
if not sys.argv[0] or sys.argv[0][0] == "-":
|
|
Packit |
8ea169 |
einfo = "" if not sys.argv[0] else " (python %s ...)" % sys.argv[0]
|
|
Packit |
8ea169 |
syslog("detected unhandled Python exception in 'interactive mode%s'"
|
|
Packit |
8ea169 |
% einfo)
|
|
Packit |
8ea169 |
raise Exception
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Ignore scripts with relative path unless "RequireAbsolutePath = no".
|
|
Packit |
8ea169 |
# (In this case we can't reliably determine package)
|
|
Packit |
8ea169 |
syslog("detected unhandled Python exception in '%s'" % sys.argv[0])
|
|
Packit |
8ea169 |
if sys.argv[0][0] != "/":
|
|
Packit |
8ea169 |
if require_abs_path():
|
|
Packit |
8ea169 |
raise Exception
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
import traceback
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
elist = traceback.format_exception(etype, value, tb)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if tb != None and etype != IndentationError:
|
|
Packit |
8ea169 |
tblast = traceback.extract_tb(tb, limit=None)
|
|
Packit |
8ea169 |
if len(tblast):
|
|
Packit |
8ea169 |
tblast = tblast[len(tblast)-1]
|
|
Packit |
8ea169 |
extxt = traceback.format_exception_only(etype, value)
|
|
Packit |
8ea169 |
if tblast and len(tblast) > 3:
|
|
Packit |
8ea169 |
ll = []
|
|
Packit |
8ea169 |
ll.extend(tblast[:3])
|
|
Packit |
8ea169 |
ll[0] = os.path.basename(tblast[0])
|
|
Packit |
8ea169 |
tblast = ll
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
ntext = ""
|
|
Packit |
8ea169 |
for t in tblast:
|
|
Packit |
8ea169 |
ntext += str(t) + ":"
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
text = ntext
|
|
Packit |
8ea169 |
text += extxt[0]
|
|
Packit |
8ea169 |
text += "\n"
|
|
Packit |
8ea169 |
text += "".join(elist)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
trace = tb
|
|
Packit |
8ea169 |
while trace.tb_next:
|
|
Packit |
8ea169 |
trace = trace.tb_next
|
|
Packit |
8ea169 |
frame = trace.tb_frame
|
|
Packit |
8ea169 |
text += ("\nLocal variables in innermost frame:\n")
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
for (key, val) in frame.f_locals.items():
|
|
Packit |
8ea169 |
text += "%s: %s\n" % (key, repr(val))
|
|
Packit |
8ea169 |
except:
|
|
Packit |
8ea169 |
pass
|
|
Packit |
8ea169 |
else:
|
|
Packit |
8ea169 |
text = str(value) + "\n"
|
|
Packit |
8ea169 |
text += "\n"
|
|
Packit |
8ea169 |
text += "".join(elist)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# Send data to the daemon
|
|
Packit |
8ea169 |
write_dump(text, tb)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
except:
|
|
Packit |
8ea169 |
# Silently ignore any error in this hook,
|
|
Packit |
8ea169 |
# to not interfere with other scripts
|
|
Packit |
8ea169 |
pass
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
return sys.__excepthook__(etype, value, tb)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
def installExceptionHandler():
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
Install the exception handling function.
|
|
Packit |
8ea169 |
"""
|
|
Packit |
8ea169 |
sys.excepthook = lambda etype, value, tb: handleMyException((etype, value, tb))
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
# install the exception handler when the abrt_exception_handler
|
|
Packit |
8ea169 |
# module is imported
|
|
Packit |
8ea169 |
try:
|
|
Packit |
8ea169 |
installExceptionHandler()
|
|
Packit |
8ea169 |
except Exception, e:
|
|
Packit |
8ea169 |
# TODO: log errors?
|
|
Packit |
8ea169 |
# OTOH, if abrt is deinstalled uncleanly
|
|
Packit |
8ea169 |
# and this file (sitecustomize.py) exists but
|
|
Packit |
8ea169 |
# abrt_exception_handler module does not exist, we probably
|
|
Packit |
8ea169 |
# don't want to irritate admins...
|
|
Packit |
8ea169 |
pass
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
if __name__ == '__main__':
|
|
Packit |
8ea169 |
# test exception raised to show the effect
|
|
Packit |
8ea169 |
div0 = 1 / 0 # pylint: disable-msg=W0612
|
|
Packit |
8ea169 |
sys.exit(0)
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
|
|
Packit |
8ea169 |
__author__ = "Harald Hoyer <harald@redhat.com>"
|