Blame src/plugins/abrt-action-check-oops-for-hw-error

Packit 8ea169
#!/usr/bin/python3 -u
Packit 8ea169
Packit 8ea169
import sys
Packit 8ea169
import os
Packit 8ea169
import locale
Packit 8ea169
import gettext
Packit 8ea169
import hashlib
Packit 8ea169
import re
Packit 8ea169
Packit 8ea169
GETTEXT_PROGNAME = "abrt"
Packit 8ea169
Packit 8ea169
_ = gettext.gettext
Packit 8ea169
Packit 8ea169
def file_has_string(filename, string):
Packit 8ea169
    try:
Packit 8ea169
        with open(filename, "r") as f:
Packit 8ea169
            for line in f:
Packit 8ea169
                if string in line:
Packit 8ea169
                    return True
Packit 8ea169
    except OSError as ex:
Packit 8ea169
        sys.stderr.write("Failed to read file '%s': %s\n"
Packit 8ea169
                         % (filename, str(ex)))
Packit 8ea169
    except ValueError as ex:
Packit 8ea169
        sys.stderr.write("Invalid data in file '%s': %s\n"
Packit 8ea169
                         % (filename, str(ex)))
Packit 8ea169
    return False
Packit 8ea169
Packit 8ea169
Packit 8ea169
def tail_with_search(filename, string, maxlen):
Packit 8ea169
    # return empty list on error
Packit 8ea169
    retval = []
Packit 8ea169
    try:
Packit 8ea169
        with open(filename, "r") as f:
Packit 8ea169
            l = []
Packit 8ea169
            for line in f:
Packit 8ea169
                if string in line:
Packit 8ea169
                    l.append(line)
Packit 8ea169
                    if len(l) > maxlen:
Packit 8ea169
                        del l[0]
Packit 8ea169
            retval = l
Packit 8ea169
    except OSError as ex:
Packit 8ea169
        sys.stderr.write("Failed to read file '%s': %s\n"
Packit 8ea169
                         % (filename, str(ex)))
Packit 8ea169
    except ValueError as ex:
Packit 8ea169
        sys.stderr.write("Invalid data in file '%s': %s\n"
Packit 8ea169
                         % (filename, str(ex)))
Packit 8ea169
    return retval
Packit 8ea169
Packit 8ea169
Packit 8ea169
def open_or_die(filename, mode):
Packit 8ea169
    try:
Packit 8ea169
        f = open(filename, mode)
Packit 8ea169
    except IOError as e:
Packit 8ea169
        sys.stderr.write(str(e) + "\n")
Packit 8ea169
        sys.exit(1)
Packit 8ea169
    return f
Packit 8ea169
Packit 8ea169
Packit 8ea169
if __name__ == "__main__":
Packit 8ea169
    try:
Packit 8ea169
        locale.setlocale(locale.LC_ALL, "")
Packit 8ea169
    except locale.Error:
Packit 8ea169
        os.environ['LC_ALL'] = 'C'
Packit 8ea169
        locale.setlocale(locale.LC_ALL, "")
Packit 8ea169
Packit 8ea169
    # Defeat "AttributeError: 'module' object has no attribute 'nl_langinfo'"
Packit 8ea169
    try:
Packit 8ea169
        gettext.bind_textdomain_codeset(GETTEXT_PROGNAME,
Packit 8ea169
                                        locale.nl_langinfo(locale.CODESET))
Packit 8ea169
    except AttributeError:
Packit 8ea169
        pass
Packit 8ea169
Packit 8ea169
    gettext.bindtextdomain(GETTEXT_PROGNAME, '/usr/share/locale')
Packit 8ea169
    gettext.textdomain(GETTEXT_PROGNAME)
Packit 8ea169
Packit 8ea169
    #
Packit 8ea169
    # So far we only look for Machine Check Exceptions here.
Packit 8ea169
    #
Packit 8ea169
Packit 8ea169
    # See if MCEs were seen
Packit 8ea169
    oops_mce = file_has_string("backtrace", "Machine check events logged");
Packit 8ea169
    vmcore_mce = file_has_string("backtrace", "Machine Check Exception:");
Packit 8ea169
    if not oops_mce and not vmcore_mce:
Packit 8ea169
        sys.exit(0)
Packit 8ea169
    #
Packit 8ea169
    # There was an MCE. IOW: it's not a bug, it's a HW error.
Packit 8ea169
    f = open_or_die("not-reportable", "w")
Packit 8ea169
    f.write(_(
Packit 8ea169
                "The kernel log indicates that hardware errors were detected.\n"
Packit 8ea169
                "This is most likely not a software problem.\n"
Packit 8ea169
    ))
Packit 8ea169
    f.close()
Packit 8ea169
Packit 8ea169
    oops_hash = hashlib.sha1()
Packit 8ea169
    with open("backtrace", "r") as btfile:
Packit 8ea169
        for line in btfile:
Packit 8ea169
            oops_hash.update(line.encode())
Packit 8ea169
Packit 8ea169
    with open_or_die("uuid", "w") as f:
Packit 8ea169
        f.write(oops_hash.hexdigest())
Packit 8ea169
Packit 8ea169
    with open_or_die("duphash", "w") as f:
Packit 8ea169
        f.write(oops_hash.hexdigest())
Packit 8ea169
Packit 8ea169
    res = tail_with_search("dmesg", "Linux version", 1)
Packit 8ea169
    if res:
Packit 8ea169
        kernel = re.sub(r"^.*Linux version ([^ ]+) .*$", r"\1", res[0]);
Packit 8ea169
        with open_or_die("kernel", "w") as krnlfile:
Packit 8ea169
            krnlfile.write(kernel)
Packit 8ea169
Packit 8ea169
    with open_or_die("mce", "w") as f:
Packit 8ea169
        f.write("fatal" if vmcore_mce else "non-fatal")
Packit 8ea169
Packit 8ea169
    # vmcore MCEs already have good backtrace element, nothing more to do
Packit 8ea169
    if vmcore_mce:
Packit 8ea169
        sys.exit(0)
Packit 8ea169
Packit 8ea169
    #
Packit 8ea169
    # Did mcelog logged it to /var/log/mcelog
Packit 8ea169
    # (RHEL6 by default does this)?
Packit 8ea169
    if os.path.exists("/var/log/mcelog"):
Packit 8ea169
        f = open_or_die("backtrace", "w")
Packit 8ea169
        f.write("The kernel log indicates that hardware errors were detected.\n")
Packit 8ea169
        f.write("/var/log/mcelog file may have more information.\n")
Packit 8ea169
        f.write("The last 20 lines of /var/log/mcelog are:\n")
Packit 8ea169
        f.write("=========================================\n")
Packit 8ea169
        #tail -n20 /var/log/mcelog 2>&1
Packit 8ea169
        l = tail_with_search("/var/log/mcelog", "", 20)
Packit 8ea169
        for line in l:
Packit 8ea169
            f.write(line)
Packit 8ea169
        f.close()
Packit 8ea169
        sys.exit(0)
Packit 8ea169
    #
Packit 8ea169
    # On RHEL7, mcelog is run so that its output ends up in syslog.
Packit 8ea169
    # Do we see that?
Packit 8ea169
    if file_has_string("/var/log/messages", "mcelog: Hardware event"):
Packit 8ea169
        f = open_or_die("backtrace", "w")
Packit 8ea169
        f.write("The kernel log indicates that hardware errors were detected.\n")
Packit 8ea169
        f.write("System log may have more information.\n")
Packit 8ea169
        f.write("The last 20 mcelog lines of system log are:\n")
Packit 8ea169
        f.write("==========================================\n")
Packit 8ea169
        #grep -Fi 'mcelog:' /var/log/messages | tail -n20 2>&1
Packit 8ea169
        l = tail_with_search("/var/log/messages", "mcelog:", 20)
Packit 8ea169
        for line in l:
Packit 8ea169
            f.write(line)
Packit 8ea169
        f.close()
Packit 8ea169
        sys.exit(0)
Packit 8ea169
    #
Packit 8ea169
    # Apparently, there is no running mcelog daemon!
Packit 8ea169
    # Let user know that he needs one.
Packit 8ea169
    f = open_or_die("backtrace", "w")
Packit 8ea169
    f.write("The kernel log indicates that hardware errors were detected.\n")
Packit 8ea169
    f.write("The data was saved by kernel for processing by the mcelog tool.\n")
Packit 8ea169
    f.write("However, neither /var/log/mcelog nor system log contain mcelog messages.\n")
Packit 8ea169
    f.write("Most likely reason is that mcelog is not installed or not configured\n")
Packit 8ea169
    f.write("to be started during boot.\n")
Packit 8ea169
    f.write("Without this tool running, the binary data saved by kernel\n")
Packit 8ea169
    f.write("is of limited usefulness.\n")
Packit 8ea169
    f.write("(You can save this data anyway by running 'cat </dev/mcelog >FILE').\n")
Packit 8ea169
    f.write("The recommended course of action is to install mcelog.\n")
Packit 8ea169
    f.write("If another hardware error would occur, a user-readable description\n")
Packit 8ea169
    f.write("of it will be saved in system log or /var/log/mcelog.\n")
Packit 8ea169
    f.close()