Bugfixes and improvements to crash handler script
* Fixed a bug on get_results_dir list (wrong indent level of a return
statement)
* Use GDB also to determine information about the core dump
* Keep a copy of the core file on a temp directory for safety
* After all reporting is done, compress core files generated
to save space (they are usually pretty large)
Signed-off-by: Lucas Meneghel Rodrigues <lmr@redhat.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@4582 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/client/tools/crash_handler.py b/client/tools/crash_handler.py
index 9a94510..7ee9a78 100755
--- a/client/tools/crash_handler.py
+++ b/client/tools/crash_handler.py
@@ -5,7 +5,7 @@
@copyright Red Hat Inc 2009
@author Lucas Meneghel Rodrigues <lmr@redhat.com>
"""
-import sys, os, commands, glob, tempfile, shutil, syslog
+import sys, os, commands, glob, tempfile, shutil, syslog, re, time
def get_parent_pid(pid):
@@ -24,17 +24,30 @@
return ppid
-def write_to_file(file_path, contents):
+def write_to_file(filename, data, compress=False):
"""
Write contents to a given file path specified. If not specified, the file
- will be created.
+ will be created. Optionally, compress the destination file.
@param file_path: Path to a given file.
- @param contents: File contents.
+ @param data: File contents.
+ @param compress: Whether the file is going to be compressed at the end of
+ the data write process.
"""
- file_object = open(file_path, 'w')
- file_object.write(contents)
- file_object.close()
+ f = open(filename, 'w')
+ try:
+ f.write(data)
+ finally:
+ f.close()
+
+ if compress:
+ s, o = commands.getstatusoutput('bzip2 %s' % filename)
+ if s:
+ syslog.syslog("File %s compression failed: %s" % (filename, o))
+ else:
+ filename += '.bz2'
+
+ return filename
def get_results_dir_list(pid, core_dir_basename):
@@ -68,9 +81,9 @@
else:
results_dir_list = pid_dir_dict.values()
- return (results_dir_list or
- pid_dir_dict.values() or
- [os.path.join("/tmp", core_dir_basename)])
+ return (results_dir_list or
+ pid_dir_dict.values() or
+ [os.path.join("/tmp", core_dir_basename)])
def get_info_from_core(path):
@@ -80,17 +93,22 @@
@param path: Path to core file.
"""
- # Here we are getting the executable full path in a very inelegant way :(
- # Since the 'right' solution for it is to make a library to get information
- # from core dump files, properly written, I'll leave this as it is for now.
- full_exe_path = commands.getoutput('strings %s | grep "_="' %
- path).strip("_=")
- if full_exe_path.startswith("./"):
- pwd = commands.getoutput('strings %s | grep "^PWD="' %
- path).strip("PWD=")
- full_exe_path = os.path.join(pwd, full_exe_path.strip("./"))
+ full_exe_path = None
+ output = commands.getoutput('gdb -c %s batch' % path)
+ path_pattern = re.compile("Core was generated by `([^\0]+)'", re.IGNORECASE)
+ match = re.findall(path_pattern, output)
+ for m in match:
+ # Sometimes the command line args come with the core, so get rid of them
+ m = m.split(" ")[0]
+ if os.path.isfile(m):
+ full_exe_path = m
+ break
- return {'core_file': path, 'full_exe_path': full_exe_path}
+ if full_exe_path is None:
+ syslog.syslog("Could not determine from which application core file %s "
+ "is from" % path)
+
+ return {'full_exe_path': full_exe_path}
if __name__ == "__main__":
@@ -99,7 +117,7 @@
try:
full_functionality = False
try:
- (crashed_pid, time, uid, signal, hostname, exe) = sys.argv[1:]
+ (crashed_pid, crash_time, uid, signal, hostname, exe) = sys.argv[1:]
full_functionality = True
except ValueError, e:
# Probably due a kernel bug, we can't exactly map the parameters
@@ -128,74 +146,75 @@
# Write the core file to the appropriate directory
# (we are piping it to this script)
core_file = sys.stdin.read()
- # Write the core file to its temporary location
- write_to_file(core_tmp_path, core_file)
+ # Write the core file to its temporary location, let's keep it
+ # there in case something goes wrong
+ core_tmp_path = write_to_file(core_tmp_path, core_file)
+ processing_succeed = False
if not full_functionality:
- syslog.syslog(syslog.LOG_INFO, "Writing core files to %s" %
+ syslog.syslog("Writing core files to %s" %
current_results_dir_list)
for result_dir in current_results_dir_list:
if not os.path.isdir(result_dir):
os.makedirs(result_dir)
core_path = os.path.join(result_dir, 'core')
- write_to_file(core_path, core_file)
+ core_path = write_to_file(core_path, core_file,
+ compress=True)
+ processing_succeed = True
raise ValueError("Incorrect params passed to handler "
"script: %s." % sys.argv[1:])
- # Write a command file for GDB
- gdb_command = 'bt full\n'
- write_to_file(gdb_command_path, gdb_command)
-
# Get full command path
exe_path = get_info_from_core(core_tmp_path)['full_exe_path']
- # Take a backtrace from the running program
- gdb_cmd = ('gdb -e %s -c %s -x %s -n -batch -quiet' %
- (exe_path, core_tmp_path, gdb_command_path))
- backtrace = commands.getoutput(gdb_cmd)
- # Sanitize output before passing it to the report
- backtrace = backtrace.decode('utf-8', 'ignore')
+ if exe_path is not None:
+ # Write a command file for GDB
+ gdb_command = 'bt full\n'
+ write_to_file(gdb_command_path, gdb_command)
+
+ # Take a backtrace from the running program
+ gdb_cmd = ('gdb -e %s -c %s -x %s -n -batch -quiet' %
+ (exe_path, core_tmp_path, gdb_command_path))
+ backtrace = commands.getoutput(gdb_cmd)
+ # Sanitize output before passing it to the report
+ backtrace = backtrace.decode('utf-8', 'ignore')
+ else:
+ exe_path = "Unknown"
+ backtrace = ("Could not determine backtrace for core file %s" %
+ core_tmp_path)
# Composing the format_dict
- format_dict = {}
- format_dict['program'] = exe_path
- format_dict['pid'] = crashed_pid
- format_dict['signal'] = signal
- format_dict['hostname'] = hostname
- format_dict['time'] = time
- format_dict['backtrace'] = backtrace
+ report = "Program: %s\n" % exe_path
+ report += "PID: %s\n" % crashed_pid
+ report += "Signal: %s\n" % signal
+ report += "Hostname: %s\n" % hostname
+ report += "Time of the crash: %s\n" % time.ctime(float(crash_time))
+ report += "Program backtrace:\n%s\n" % backtrace
- report = """Autotest crash report
-
-Program: %(program)s
-PID: %(pid)s
-Signal: %(signal)s
-Hostname: %(hostname)s
-Time of the crash: %(time)s
-Program backtrace:
-%(backtrace)s
-""" % format_dict
-
- syslog.syslog(syslog.LOG_INFO,
- "Application %s, PID %s crashed" %
+ syslog.syslog("Application %s, PID %s crashed" %
(exe_path, crashed_pid))
# Now, for all results dir, let's create the directory if it doesn't
# exist, and write the core file and the report to it.
- syslog.syslog(syslog.LOG_INFO,
- "Writing core files and reports to %s" %
+ syslog.syslog("Writing core files and reports to %s" %
current_results_dir_list)
for result_dir in current_results_dir_list:
if not os.path.isdir(result_dir):
os.makedirs(result_dir)
core_path = os.path.join(result_dir, 'core')
- write_to_file(core_path, core_file)
+ core_path = write_to_file(core_path, core_file, compress=True)
report_path = os.path.join(result_dir, 'report')
write_to_file(report_path, report)
+ processing_succeed = True
except Exception, e:
syslog.syslog("Crash handler had a problem: %s" % e)
finally:
- if os.path.isdir(core_tmp_dir):
- shutil.rmtree(core_tmp_dir)
+ if processing_succeed:
+ if os.path.isdir(core_tmp_dir):
+ shutil.rmtree(core_tmp_dir)
+ else:
+ syslog.syslog("Crash handler failed to process the core file. "
+ "A copy of the file was kept at %s" %
+ core_tmp_path)