diff options
-rw-r--r-- | lib/plugins/Kerneloops.cpp | 201 | ||||
-rw-r--r-- | lib/plugins/Kerneloops.h | 8 | ||||
-rw-r--r-- | lib/plugins/KerneloopsReporter.cpp | 138 | ||||
-rw-r--r-- | lib/plugins/KerneloopsReporter.h | 18 | ||||
-rw-r--r-- | lib/plugins/KerneloopsScanner.h | 10 | ||||
-rw-r--r-- | lib/plugins/KerneloopsSysLog.cpp | 664 |
6 files changed, 538 insertions, 501 deletions
diff --git a/lib/plugins/Kerneloops.cpp b/lib/plugins/Kerneloops.cpp index 379197b2..2ffc2e34 100644 --- a/lib/plugins/Kerneloops.cpp +++ b/lib/plugins/Kerneloops.cpp @@ -25,117 +25,126 @@ static unsigned hash_oops_str(const char *oops_ptr) { - unsigned char old_c; - unsigned char c = 0; - unsigned hash = 0; + unsigned char old_c; + unsigned char c = 0; + unsigned hash = 0; - /* Special-case: if the first line is of form: - * WARNING: at net/wireless/core.c:614 wdev_cleanup_work+0xe9/0x120 [cfg80211]() (Not tainted) - * then hash only "file:line func+ofs/len" part. - */ - if (strncmp(oops_ptr, "WARNING: at ", sizeof("WARNING: at ")-1) == 0) { - const char *p = oops_ptr + sizeof("WARNING: at ")-1; - p = strchr(p, ' '); /* skip filename:NNN */ - if (p) { - p = strchrnul(p + 1, ' '); /* skip function_name+0xNN/0xNNN */ - oops_ptr += sizeof("WARNING: at ")-1; - while (oops_ptr < p) { - c = *oops_ptr++; - hash = ((hash << 5) ^ (hash >> 27)) ^ c; - } - return hash; - } - } + /* Special-case: if the first line is of form: + * WARNING: at net/wireless/core.c:614 wdev_cleanup_work+0xe9/0x120 [cfg80211]() (Not tainted) + * then hash only "file:line func+ofs/len" part. + */ + if (strncmp(oops_ptr, "WARNING: at ", sizeof("WARNING: at ")-1) == 0) + { + const char *p = oops_ptr + sizeof("WARNING: at ")-1; + p = strchr(p, ' '); /* skip filename:NNN */ + if (p) + { + p = strchrnul(p + 1, ' '); /* skip function_name+0xNN/0xNNN */ + oops_ptr += sizeof("WARNING: at ")-1; + while (oops_ptr < p) + { + c = *oops_ptr++; + hash = ((hash << 5) ^ (hash >> 27)) ^ c; + } + return hash; + } + } - while (1) { - old_c = c; - c = *oops_ptr++; - if (!c) - break; - if (c == '\n') { - // Exclude some lines which have process name - in some oops classes - // process name is irrelevant and changes with every oops. - // Lines we filter out: - // Pid: 8003, comm: Xorg Not tainted (2.6.27.9-159.fc10.i686 #1) - // Process Xorg (pid: 8003, ti=f0a0c000 task=f2380000 task.ti=f0a0c000) - if (strncmp(oops_ptr, "Pid: ", 5) == 0 - || strncmp(oops_ptr, "Process ", 8) == 0 - ) { - while (*oops_ptr && *oops_ptr != '\n') - oops_ptr++; - continue; - } - } - if (!isalnum(old_c)) { - if (c >= '0' && c <= '9') { - // Convert all (possibly hex) numbers to just one '0' - if (c == '0' && *oops_ptr == 'x') // "0xSOMETHING" - oops_ptr++; - while (isxdigit(*oops_ptr)) - oops_ptr++; - c = '0'; - } else - if ((c|0x20) >= 'a' && (c|0x20) <= 'f') { - // This *may be* a hex number without 0x prefix: "f0a0c000" - // Check that it indeed is, and replace with '0' - const char *oops_ptr2 = oops_ptr; - while (isxdigit(*oops_ptr2)) - oops_ptr2++; - // Does it end in a letter which is not a hex digit? - // (Example: "abcw" is not a hex number, "abc " is) - if (!isalpha(*oops_ptr2)) { - // It's "abc " case. Skip the "abc" string - oops_ptr = oops_ptr2; - c = '0'; - } - // else: hash the string as-is - } - } - // TODO: Drop call trace tail - in interrupt-driven oopses, - // everything before interrupt is irrelevant. - // Example of call trace part of oops: - // Call Trace: - // [<f88e11c7>] ? radeon_cp_resume+0x7d/0xbc [radeon] - // [<f88745f8>] ? drm_ioctl+0x1b0/0x225 [drm] - // [<f88e114a>] ? radeon_cp_resume+0x0/0xbc [radeon] - // [<c049b1c0>] ? vfs_ioctl+0x50/0x69 - // [<c049b414>] ? do_vfs_ioctl+0x23b/0x247 - // [<c0460a56>] ? audit_syscall_entry+0xf9/0x123 - // [<c049b460>] ? sys_ioctl+0x40/0x5c - // [<c0403c76>] ? syscall_call+0x7/0xb + while (1) + { + old_c = c; + c = *oops_ptr++; + if (!c) + break; + if (c == '\n') + { + // Exclude some lines which have process name - in some oops classes + // process name is irrelevant and changes with every oops. + // Lines we filter out: + // Pid: 8003, comm: Xorg Not tainted (2.6.27.9-159.fc10.i686 #1) + // Process Xorg (pid: 8003, ti=f0a0c000 task=f2380000 task.ti=f0a0c000) + if (strncmp(oops_ptr, "Pid: ", 5) == 0 + || strncmp(oops_ptr, "Process ", 8) == 0 + ) { + while (*oops_ptr && *oops_ptr != '\n') + oops_ptr++; + continue; + } + } + if (!isalnum(old_c)) + { + if (c >= '0' && c <= '9') + { + // Convert all (possibly hex) numbers to just one '0' + if (c == '0' && *oops_ptr == 'x') // "0xSOMETHING" + oops_ptr++; + while (isxdigit(*oops_ptr)) + oops_ptr++; + c = '0'; + } + else if ((c|0x20) >= 'a' && (c|0x20) <= 'f') + { + // This *may be* a hex number without 0x prefix: "f0a0c000" + // Check that it indeed is, and replace with '0' + const char *oops_ptr2 = oops_ptr; + while (isxdigit(*oops_ptr2)) + oops_ptr2++; + // Does it end in a letter which is not a hex digit? + // (Example: "abcw" is not a hex number, "abc " is) + if (!isalpha(*oops_ptr2)) + { + // It's "abc " case. Skip the "abc" string + oops_ptr = oops_ptr2; + c = '0'; + } + // else: hash the string as-is + } + } + // TODO: Drop call trace tail - in interrupt-driven oopses, + // everything before interrupt is irrelevant. + // Example of call trace part of oops: + // Call Trace: + // [<f88e11c7>] ? radeon_cp_resume+0x7d/0xbc [radeon] + // [<f88745f8>] ? drm_ioctl+0x1b0/0x225 [drm] + // [<f88e114a>] ? radeon_cp_resume+0x0/0xbc [radeon] + // [<c049b1c0>] ? vfs_ioctl+0x50/0x69 + // [<c049b414>] ? do_vfs_ioctl+0x23b/0x247 + // [<c0460a56>] ? audit_syscall_entry+0xf9/0x123 + // [<c049b460>] ? sys_ioctl+0x40/0x5c + // [<c0403c76>] ? syscall_call+0x7/0xb - /* An algorithm proposed by Donald E. Knuth in The Art Of Computer - * Programming Volume 3, under the topic of sorting and search - * chapter 6.4. - */ - hash = ((hash << 5) ^ (hash >> 27)) ^ c; - } - return hash; + /* An algorithm proposed by Donald E. Knuth in The Art Of Computer + * Programming Volume 3, under the topic of sorting and search + * chapter 6.4. + */ + hash = ((hash << 5) ^ (hash >> 27)) ^ c; + } + return hash; } std::string CAnalyzerKerneloops::GetLocalUUID(const char *pDebugDumpDir) { - VERB3 log("Getting local universal unique identification"); + VERB3 log("Getting local universal unique identification"); - std::string oops; - CDebugDump dd; - if (!dd.Open(pDebugDumpDir)) - { - VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir); - return std::string(""); - } + std::string oops; + CDebugDump dd; + if (!dd.Open(pDebugDumpDir)) + { + VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir); + return std::string(""); + } - dd.LoadText(FILENAME_BACKTRACE, oops); + dd.LoadText(FILENAME_BACKTRACE, oops); - unsigned hash = hash_oops_str(oops.c_str()); - hash &= 0x7FFFFFFF; + unsigned hash = hash_oops_str(oops.c_str()); + hash &= 0x7FFFFFFF; - return to_string(hash); + return to_string(hash); } std::string CAnalyzerKerneloops::GetGlobalUUID(const char *pDebugDumpDir) { - return GetLocalUUID(pDebugDumpDir); + return GetLocalUUID(pDebugDumpDir); } PLUGIN_INFO(ANALYZER, diff --git a/lib/plugins/Kerneloops.h b/lib/plugins/Kerneloops.h index 2160f444..cac2c526 100644 --- a/lib/plugins/Kerneloops.h +++ b/lib/plugins/Kerneloops.h @@ -33,10 +33,10 @@ class CAnalyzerKerneloops : public CAnalyzer { - public: - virtual std::string GetLocalUUID(const char *pDebugDumpDir); - virtual std::string GetGlobalUUID(const char *pDebugDumpDir); - virtual void CreateReport(const char *pDebugDumpDir, int force) {} + public: + virtual std::string GetLocalUUID(const char *pDebugDumpDir); + virtual std::string GetGlobalUUID(const char *pDebugDumpDir); + virtual void CreateReport(const char *pDebugDumpDir, int force) {} }; #endif diff --git a/lib/plugins/KerneloopsReporter.cpp b/lib/plugins/KerneloopsReporter.cpp index 2b4df3a0..3af8a932 100644 --- a/lib/plugins/KerneloopsReporter.cpp +++ b/lib/plugins/KerneloopsReporter.cpp @@ -26,105 +26,107 @@ /* helpers */ static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) { - size *= nmemb; + size *= nmemb; /* - char *c, *c1, *c2; - - log("received: '%*.*s'\n", (int)size, (int)size, (char*)ptr); - c = (char*)xzalloc(size + 1); - memcpy(c, ptr, size); - c1 = strstr(c, "201 "); - if (c1) { - c1 += 4; - c2 = strchr(c1, '\n'); - if (c2) - *c2 = 0; - } - free(c); + char *c, *c1, *c2; + + log("received: '%*.*s'\n", (int)size, (int)size, (char*)ptr); + c = (char*)xzalloc(size + 1); + memcpy(c, ptr, size); + c1 = strstr(c, "201 "); + if (c1) + { + c1 += 4; + c2 = strchr(c1, '\n'); + if (c2) + *c2 = 0; + } + free(c); */ - return size; + return size; } /* Send oops data to kerneloops.org-style site, using HTTP POST */ /* Returns 0 on success */ static CURLcode http_post_to_kerneloops_site(const char *url, const char *oopsdata) { - CURLcode ret; - CURL *handle; - struct curl_httppost *post = NULL; - struct curl_httppost *last = NULL; + CURLcode ret; + CURL *handle; + struct curl_httppost *post = NULL; + struct curl_httppost *last = NULL; - handle = xcurl_easy_init(); - curl_easy_setopt(handle, CURLOPT_URL, url); + handle = xcurl_easy_init(); + curl_easy_setopt(handle, CURLOPT_URL, url); - curl_formadd(&post, &last, - CURLFORM_COPYNAME, "oopsdata", - CURLFORM_COPYCONTENTS, oopsdata, - CURLFORM_END); - curl_formadd(&post, &last, - CURLFORM_COPYNAME, "pass_on_allowed", - CURLFORM_COPYCONTENTS, "yes", - CURLFORM_END); + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "oopsdata", + CURLFORM_COPYCONTENTS, oopsdata, + CURLFORM_END); + curl_formadd(&post, &last, + CURLFORM_COPYNAME, "pass_on_allowed", + CURLFORM_COPYCONTENTS, "yes", + CURLFORM_END); - curl_easy_setopt(handle, CURLOPT_HTTPPOST, post); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writefunction); + curl_easy_setopt(handle, CURLOPT_HTTPPOST, post); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writefunction); - ret = curl_easy_perform(handle); + ret = curl_easy_perform(handle); - curl_formfree(post); - curl_easy_cleanup(handle); + curl_formfree(post); + curl_easy_cleanup(handle); - return ret; + return ret; } /* class CKerneloopsReporter */ CKerneloopsReporter::CKerneloopsReporter() : - m_sSubmitURL("http://submit.kerneloops.org/submitoops.php") + m_sSubmitURL("http://submit.kerneloops.org/submitoops.php") {} std::string CKerneloopsReporter::Report(const map_crash_data_t& pCrashData, const map_plugin_settings_t& pSettings, const char *pArgs) { - CURLcode ret; - - update_client(_("Creating and submitting a report...")); - - map_crash_data_t::const_iterator it = pCrashData.find(FILENAME_BACKTRACE); - if (it != pCrashData.end()) { - ret = http_post_to_kerneloops_site( - m_sSubmitURL.c_str(), - it->second[CD_CONTENT].c_str() - ); - } - - if (ret != CURLE_OK) { - char* err_str = xasprintf("Kernel oops has not been sent due to %s", curl_easy_strerror(ret)); - CABRTException e(EXCEP_PLUGIN, err_str); - free(err_str); - throw e; - } - /* Server replies with: - * 200 thank you for submitting the kernel oops information - * RemoteIP: 34192fd15e34bf60fac6a5f01bba04ddbd3f0558 - * - no URL or bug ID apparently... - */ - return "Kernel oops report was uploaded"; + CURLcode ret; + + update_client(_("Creating and submitting a report...")); + + map_crash_data_t::const_iterator it = pCrashData.find(FILENAME_BACKTRACE); + if (it != pCrashData.end()) + { + ret = http_post_to_kerneloops_site( + m_sSubmitURL.c_str(), + it->second[CD_CONTENT].c_str() + ); + } + + if (ret != CURLE_OK) + { + char* err_str = xasprintf("Kernel oops has not been sent due to %s", curl_easy_strerror(ret)); + CABRTException e(EXCEP_PLUGIN, err_str); + free(err_str); + throw e; + } + /* Server replies with: + * 200 thank you for submitting the kernel oops information + * RemoteIP: 34192fd15e34bf60fac6a5f01bba04ddbd3f0558 + * - no URL or bug ID apparently... + */ + return "Kernel oops report was uploaded"; } void CKerneloopsReporter::SetSettings(const map_plugin_settings_t& pSettings) { - m_pSettings = pSettings; - - map_plugin_settings_t::const_iterator end = pSettings.end(); - map_plugin_settings_t::const_iterator it; - it = pSettings.find("SubmitURL"); - if (it != end) { - m_sSubmitURL = it->second; - } + m_pSettings = pSettings; + + map_plugin_settings_t::const_iterator end = pSettings.end(); + map_plugin_settings_t::const_iterator it; + it = pSettings.find("SubmitURL"); + if (it != end) + m_sSubmitURL = it->second; } //ok to delete? diff --git a/lib/plugins/KerneloopsReporter.h b/lib/plugins/KerneloopsReporter.h index cb939d0d..679e5b0b 100644 --- a/lib/plugins/KerneloopsReporter.h +++ b/lib/plugins/KerneloopsReporter.h @@ -34,18 +34,18 @@ class CKerneloopsReporter : public CReporter { - private: - std::string m_sSubmitURL; + private: + std::string m_sSubmitURL; - public: - CKerneloopsReporter(); + public: + CKerneloopsReporter(); - virtual void SetSettings(const map_plugin_settings_t& pSettings); + virtual void SetSettings(const map_plugin_settings_t& pSettings); //ok to delete? -// virtual const map_plugin_settings_t& GetSettings(); - virtual std::string Report(const map_crash_data_t& pCrashData, - const map_plugin_settings_t& pSettings, - const char *pArgs); +// virtual const map_plugin_settings_t& GetSettings(); + virtual std::string Report(const map_crash_data_t& pCrashData, + const map_plugin_settings_t& pSettings, + const char *pArgs); }; #endif diff --git a/lib/plugins/KerneloopsScanner.h b/lib/plugins/KerneloopsScanner.h index 0904146e..2bddb0f4 100644 --- a/lib/plugins/KerneloopsScanner.h +++ b/lib/plugins/KerneloopsScanner.h @@ -32,11 +32,11 @@ class CKerneloopsScanner : public CAction { -private: - time_t m_syslog_last_change; -public: - CKerneloopsScanner(); - virtual void Run(const char *pActionDir, const char *pArgs, int force); + private: + time_t m_syslog_last_change; + public: + CKerneloopsScanner(); + virtual void Run(const char *pActionDir, const char *pArgs, int force); }; #endif diff --git a/lib/plugins/KerneloopsSysLog.cpp b/lib/plugins/KerneloopsSysLog.cpp index 66cce416..8fdd1ac7 100644 --- a/lib/plugins/KerneloopsSysLog.cpp +++ b/lib/plugins/KerneloopsSysLog.cpp @@ -23,7 +23,7 @@ static void queue_oops(vector_string_t &vec, const char *data, const char *version) { - vec.push_back(ssprintf("%s\n%s", version, data)); + vec.push_back(ssprintf("%s\n%s", version, data)); } /* @@ -31,336 +31,362 @@ static void queue_oops(vector_string_t &vec, const char *data, const char *versi */ static int extract_version(const char *linepointer, char *version) { - int ret; - - ret = 0; - if (strstr(linepointer, "Pid") - || strstr(linepointer, "comm") - || strstr(linepointer, "CPU") - || strstr(linepointer, "REGS") - || strstr(linepointer, "EFLAGS") - ) { - char* start; - char* end; - - start = strstr((char*)linepointer, "2.6."); - if (start) { - end = strchr(start, ')'); - if (!end) - end = strchrnul(start, ' '); - strncpy(version, start, end-start); - ret = 1; - } - } - - if (!ret) - strncpy(version, "undefined", 9); - - return ret; + int ret; + + ret = 0; + if (strstr(linepointer, "Pid") + || strstr(linepointer, "comm") + || strstr(linepointer, "CPU") + || strstr(linepointer, "REGS") + || strstr(linepointer, "EFLAGS") + ) { + char* start; + char* end; + + start = strstr((char*)linepointer, "2.6."); + if (start) + { + end = strchr(start, ')'); + if (!end) + end = strchrnul(start, ' '); + strncpy(version, start, end-start); + ret = 1; + } + } + + if (!ret) + strncpy(version, "undefined", 9); + + return ret; } /* * extract_oops tries to find oops signatures in a log */ struct line_info { - char *ptr; - char level; + char *ptr; + char level; }; + static int record_oops(vector_string_t &oopses, struct line_info* lines_info, int oopsstart, int oopsend) { - int q; - int len; - int is_version; - char *oops; - char *version; - - len = 2; - for (q = oopsstart; q <= oopsend; q++) - len += strlen(lines_info[q].ptr) + 1; - - oops = (char*)xzalloc(len); - version = (char*)xzalloc(len); - - is_version = 0; - for (q = oopsstart; q <= oopsend; q++) { - if (!is_version) - is_version = extract_version(lines_info[q].ptr, version); - if (lines_info[q].ptr[0]) { - strcat(oops, lines_info[q].ptr); - strcat(oops, "\n"); - } - } - int rv = 1; - /* too short oopses are invalid */ - if (strlen(oops) > 100) { - queue_oops(oopses, oops, version); - } else { - VERB3 log("Dropped oops: too short"); - rv = 0; - } - free(oops); - free(version); - return rv; + int q; + int len; + int is_version; + char *oops; + char *version; + + len = 2; + for (q = oopsstart; q <= oopsend; q++) + len += strlen(lines_info[q].ptr) + 1; + + oops = (char*)xzalloc(len); + version = (char*)xzalloc(len); + + is_version = 0; + for (q = oopsstart; q <= oopsend; q++) + { + if (!is_version) + is_version = extract_version(lines_info[q].ptr, version); + + if (lines_info[q].ptr[0]) + { + strcat(oops, lines_info[q].ptr); + strcat(oops, "\n"); + } + } + int rv = 1; + /* too short oopses are invalid */ + if (strlen(oops) > 100) + queue_oops(oopses, oops, version); + else + { + VERB3 log("Dropped oops: too short"); + rv = 0; + } + free(oops); + free(version); + return rv; } #define REALLOC_CHUNK 1000 int extract_oopses(vector_string_t &oopses, char *buffer, size_t buflen) { - char *c; - int linecount = 0; - int lines_info_alloc = 0; - struct line_info *lines_info = NULL; - - /* Split buffer into lines */ - - if (buflen != 0) - buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */ - c = buffer; - while (c < buffer + buflen) { - char linelevel; - char *c9; - char *colon; - - c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */ - assert(c9); - *c9 = '\0'; /* turn the \n into a string termination */ - if (c9 == c) - goto next_line; - - /* Is it a syslog file (/var/log/messages or similar)? - * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx", - * some users run syslog in non-C locale: - * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah" - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!! - * We detect it by checking for N:NN:NN pattern in first 15 chars - * (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled") - */ - colon = strchr(c, ':'); - if (colon && colon > c && colon < c + 15 - && isdigit(colon[-1]) /* N:... */ - && isdigit(colon[1]) /* ...N:NN:... */ - && isdigit(colon[2]) - && colon[3] == ':' - && isdigit(colon[4]) /* ...N:NN:NN... */ - && isdigit(colon[5]) - ) { - /* It's syslog file, not a bare dmesg */ - - /* Skip non-kernel lines */ - char *kernel_str = strstr(c, "kernel: "); - if (kernel_str == NULL) { - /* if we see our own marker: - * "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt" - * we know we submitted everything upto here already */ - if (strstr(c, "abrt:") && strstr(c, "Abrt")) { - VERB3 log("Found our marker at line %d, restarting line count from 0", linecount); - linecount = 0; - lines_info_alloc = 0; - free(lines_info); - lines_info = NULL; - } - goto next_line; - } - c = kernel_str + sizeof("kernel: ")-1; - } - - linelevel = 0; - /* store and remove kernel log level */ - if (*c == '<' && c[1] && c[2] == '>') { - linelevel = c[1]; - c += 3; - } - /* remove jiffies time stamp counter if present */ - if (*c == '[') { - char *c2 = strchr(c, '.'); - char *c3 = strchr(c, ']'); - if (c2 && c3 && (c2 < c3) && (c3-c) < 14 && (c2-c) < 8) { - c = c3 + 1; - if (*c == ' ') - c++; - } - } - if (linecount >= lines_info_alloc) { - lines_info_alloc += REALLOC_CHUNK; - lines_info = (line_info*)xrealloc(lines_info, - lines_info_alloc * sizeof(struct line_info)); - } - lines_info[linecount].ptr = c; - lines_info[linecount].level = linelevel; - linecount++; + char *c; + int linecount = 0; + int lines_info_alloc = 0; + struct line_info *lines_info = NULL; + + /* Split buffer into lines */ + + if (buflen != 0) + buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */ + c = buffer; + while (c < buffer + buflen) + { + char linelevel; + char *c9; + char *colon; + + c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */ + assert(c9); + *c9 = '\0'; /* turn the \n into a string termination */ + if (c9 == c) + goto next_line; + + /* Is it a syslog file (/var/log/messages or similar)? + * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx", + * some users run syslog in non-C locale: + * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah" + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!! + * We detect it by checking for N:NN:NN pattern in first 15 chars + * (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled") + */ + colon = strchr(c, ':'); + if (colon && colon > c && colon < c + 15 + && isdigit(colon[-1]) /* N:... */ + && isdigit(colon[1]) /* ...N:NN:... */ + && isdigit(colon[2]) + && colon[3] == ':' + && isdigit(colon[4]) /* ...N:NN:NN... */ + && isdigit(colon[5]) + ) { + /* It's syslog file, not a bare dmesg */ + + /* Skip non-kernel lines */ + char *kernel_str = strstr(c, "kernel: "); + if (kernel_str == NULL) + { + /* if we see our own marker: + * "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt" + * we know we submitted everything upto here already */ + if (strstr(c, "abrt:") && strstr(c, "Abrt")) + { + VERB3 log("Found our marker at line %d, restarting line count from 0", linecount); + linecount = 0; + lines_info_alloc = 0; + free(lines_info); + lines_info = NULL; + } + goto next_line; + } + c = kernel_str + sizeof("kernel: ")-1; + } + + linelevel = 0; + /* store and remove kernel log level */ + if (*c == '<' && c[1] && c[2] == '>') + { + linelevel = c[1]; + c += 3; + } + /* remove jiffies time stamp counter if present */ + if (*c == '[') + { + char *c2 = strchr(c, '.'); + char *c3 = strchr(c, ']'); + if (c2 && c3 && (c2 < c3) && (c3-c) < 14 && (c2-c) < 8) + { + c = c3 + 1; + if (*c == ' ') + c++; + } + } + if (linecount >= lines_info_alloc) + { + lines_info_alloc += REALLOC_CHUNK; + lines_info = (line_info*)xrealloc(lines_info, + lines_info_alloc * sizeof(struct line_info)); + } + lines_info[linecount].ptr = c; + lines_info[linecount].level = linelevel; + linecount++; next_line: - c = c9 + 1; - } - - /* Analyze lines */ - - int i; - char prevlevel = 0; - int oopsstart = -1; - int inbacktrace = 0; - int oopsesfound = 0; - - i = 0; - while (i < linecount) { - char *curline = lines_info[i].ptr; - - if (curline == NULL) { - i++; - continue; - } - while (*curline == ' ') - curline++; - - if (oopsstart < 0) { - /* find start-of-oops markers */ - if (strstr(curline, "general protection fault:")) - oopsstart = i; - else if (strstr(curline, "BUG:")) - oopsstart = i; - else if (strstr(curline, "kernel BUG at")) - oopsstart = i; - else if (strstr(curline, "do_IRQ: stack overflow:")) - oopsstart = i; - else if (strstr(curline, "RTNL: assertion failed")) - oopsstart = i; - else if (strstr(curline, "Eeek! page_mapcount(page) went negative!")) - oopsstart = i; - else if (strstr(curline, "near stack overflow (cur:")) - oopsstart = i; - else if (strstr(curline, "double fault:")) - oopsstart = i; - else if (strstr(curline, "Badness at")) - oopsstart = i; - else if (strstr(curline, "NETDEV WATCHDOG")) - oopsstart = i; - else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated message */ - oopsstart = i; - else if (strstr(curline, "Unable to handle kernel")) - oopsstart = i; - else if (strstr(curline, "sysctl table check failed")) - oopsstart = i; - else if (strstr(curline, "INFO: possible recursive locking detected")) - oopsstart = i; - // Not needed: "--[ cut here ]--" is always followed - // by "Badness at", "kernel BUG at", or "WARNING: at" string - //else if (strstr(curline, "------------[ cut here ]------------")) - // oopsstart = i; - else if (strstr(curline, "list_del corruption.")) - oopsstart = i; - else if (strstr(curline, "list_add corruption.")) - oopsstart = i; - if (strstr(curline, "Oops:") && i >= 3) - oopsstart = i-3; - - if (oopsstart >= 0) { - /* debug information */ - VERB3 { - log("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr); - if (oopsstart != i) - log("Trigger line is %d: '%s'", i, c); - } - /* try to find the end marker */ - int i2 = i + 1; - while (i2 < linecount && i2 < (i+50)) { - if (strstr(lines_info[i2].ptr, "---[ end trace")) { - inbacktrace = 1; - i = i2; - break; - } - i2++; - } - } - } - - /* Are we entering a call trace part? */ - /* a call trace starts with "Call Trace:" or with the " [<.......>] function+0xFF/0xAA" pattern */ - if (oopsstart >= 0 && !inbacktrace) { - if (strstr(curline, "Call Trace:")) - inbacktrace = 1; - else - if (strnlen(curline, 9) > 8 - && curline[0] == '[' && curline[1] == '<' - && strstr(curline, ">]") - && strstr(curline, "+0x") - && strstr(curline, "/0x") - ) { - inbacktrace = 1; - } - } - - /* Are we at the end of an oops? */ - else if (oopsstart >= 0 && inbacktrace) { - int oopsend = INT_MAX; - - /* line needs to start with " [" or have "] [" if it is still a call trace */ - /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41 [radeon]" */ - if (curline[0] != '[' - && !strstr(curline, "] [") - && !strstr(curline, "--- Exception") - && !strstr(curline, "LR =") - && !strstr(curline, "<#DF>") - && !strstr(curline, "<IRQ>") - && !strstr(curline, "<EOI>") - && !strstr(curline, "<<EOE>>") - && strncmp(curline, "Code: ", 6) != 0 - && strncmp(curline, "RIP ", 4) != 0 - && strncmp(curline, "RSP ", 4) != 0 - ) { - oopsend = i-1; /* not a call trace line */ - } - /* oops lines are always more than 8 chars long */ - else if (strnlen(curline, 8) < 8) - oopsend = i-1; - /* single oopses are of the same loglevel */ - else if (lines_info[i].level != prevlevel) - oopsend = i-1; - else if (strstr(curline, "Instruction dump:")) - oopsend = i; - /* if a new oops starts, this one has ended */ - else if (strstr(curline, "WARNING: at ") && oopsstart != i) /* WARN_ON() generated message */ - oopsend = i-1; - else if (strstr(curline, "Unable to handle") && oopsstart != i) - oopsend = i-1; - /* kernel end-of-oops marker (not including marker itself) */ - else if (strstr(curline, "---[ end trace")) - oopsend = i-1; - - if (oopsend <= i) { - VERB3 log("End of oops at line %d (%d): '%s'", oopsend, i, lines_info[oopsend].ptr); - if (record_oops(oopses, lines_info, oopsstart, oopsend)) - oopsesfound++; - oopsstart = -1; - inbacktrace = 0; - } - } - - prevlevel = lines_info[i].level; - i++; - - if (oopsstart >= 0) { - /* Do we have a suspiciously long oops? Cancel it */ - if (i-oopsstart > 60) { - inbacktrace = 0; - oopsstart = -1; - VERB3 log("Dropped oops, too long"); - continue; - } - if (!inbacktrace && i-oopsstart > 40) { - /*inbacktrace = 0; - already is */ - oopsstart = -1; - VERB3 log("Dropped oops, too long"); - continue; - } - } - } /* while (i < linecount) */ - - /* process last oops if we have one */ - if (oopsstart >= 0 && inbacktrace) { - int oopsend = i-1; - VERB3 log("End of oops at line %d (end of file): '%s'", oopsend, lines_info[oopsend].ptr); - if (record_oops(oopses, lines_info, oopsstart, oopsend)) - oopsesfound++; - } - - free(lines_info); - return oopsesfound; + c = c9 + 1; + } + + /* Analyze lines */ + + int i; + char prevlevel = 0; + int oopsstart = -1; + int inbacktrace = 0; + int oopsesfound = 0; + + i = 0; + while (i < linecount) + { + char *curline = lines_info[i].ptr; + + if (curline == NULL) + { + i++; + continue; + } + while (*curline == ' ') + curline++; + + if (oopsstart < 0) + { + /* find start-of-oops markers */ + if (strstr(curline, "general protection fault:")) + oopsstart = i; + else if (strstr(curline, "BUG:")) + oopsstart = i; + else if (strstr(curline, "kernel BUG at")) + oopsstart = i; + else if (strstr(curline, "do_IRQ: stack overflow:")) + oopsstart = i; + else if (strstr(curline, "RTNL: assertion failed")) + oopsstart = i; + else if (strstr(curline, "Eeek! page_mapcount(page) went negative!")) + oopsstart = i; + else if (strstr(curline, "near stack overflow (cur:")) + oopsstart = i; + else if (strstr(curline, "double fault:")) + oopsstart = i; + else if (strstr(curline, "Badness at")) + oopsstart = i; + else if (strstr(curline, "NETDEV WATCHDOG")) + oopsstart = i; + else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated message */ + oopsstart = i; + else if (strstr(curline, "Unable to handle kernel")) + oopsstart = i; + else if (strstr(curline, "sysctl table check failed")) + oopsstart = i; + else if (strstr(curline, "INFO: possible recursive locking detected")) + oopsstart = i; + // Not needed: "--[ cut here ]--" is always followed + // by "Badness at", "kernel BUG at", or "WARNING: at" string + //else if (strstr(curline, "------------[ cut here ]------------")) + // oopsstart = i; + else if (strstr(curline, "list_del corruption.")) + oopsstart = i; + else if (strstr(curline, "list_add corruption.")) + oopsstart = i; + if (strstr(curline, "Oops:") && i >= 3) + oopsstart = i-3; + + if (oopsstart >= 0) + { + /* debug information */ + VERB3 { + log("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr); + if (oopsstart != i) + log("Trigger line is %d: '%s'", i, c); + } + /* try to find the end marker */ + int i2 = i + 1; + while (i2 < linecount && i2 < (i+50)) + { + if (strstr(lines_info[i2].ptr, "---[ end trace")) + { + inbacktrace = 1; + i = i2; + break; + } + i2++; + } + } + } + + /* Are we entering a call trace part? */ + /* a call trace starts with "Call Trace:" or with the " [<.......>] function+0xFF/0xAA" pattern */ + if (oopsstart >= 0 && !inbacktrace) + { + if (strstr(curline, "Call Trace:")) + inbacktrace = 1; + else + if (strnlen(curline, 9) > 8 + && curline[0] == '[' && curline[1] == '<' + && strstr(curline, ">]") + && strstr(curline, "+0x") + && strstr(curline, "/0x") + ) { + inbacktrace = 1; + } + } + + /* Are we at the end of an oops? */ + else if (oopsstart >= 0 && inbacktrace) + { + int oopsend = INT_MAX; + + /* line needs to start with " [" or have "] [" if it is still a call trace */ + /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41 [radeon]" */ + if (curline[0] != '[' + && !strstr(curline, "] [") + && !strstr(curline, "--- Exception") + && !strstr(curline, "LR =") + && !strstr(curline, "<#DF>") + && !strstr(curline, "<IRQ>") + && !strstr(curline, "<EOI>") + && !strstr(curline, "<<EOE>>") + && strncmp(curline, "Code: ", 6) != 0 + && strncmp(curline, "RIP ", 4) != 0 + && strncmp(curline, "RSP ", 4) != 0 + ) { + oopsend = i-1; /* not a call trace line */ + } + /* oops lines are always more than 8 chars long */ + else if (strnlen(curline, 8) < 8) + oopsend = i-1; + /* single oopses are of the same loglevel */ + else if (lines_info[i].level != prevlevel) + oopsend = i-1; + else if (strstr(curline, "Instruction dump:")) + oopsend = i; + /* if a new oops starts, this one has ended */ + else if (strstr(curline, "WARNING: at ") && oopsstart != i) /* WARN_ON() generated message */ + oopsend = i-1; + else if (strstr(curline, "Unable to handle") && oopsstart != i) + oopsend = i-1; + /* kernel end-of-oops marker (not including marker itself) */ + else if (strstr(curline, "---[ end trace")) + oopsend = i-1; + + if (oopsend <= i) + { + VERB3 log("End of oops at line %d (%d): '%s'", oopsend, i, lines_info[oopsend].ptr); + if (record_oops(oopses, lines_info, oopsstart, oopsend)) + oopsesfound++; + oopsstart = -1; + inbacktrace = 0; + } + } + + prevlevel = lines_info[i].level; + i++; + + if (oopsstart >= 0) + { + /* Do we have a suspiciously long oops? Cancel it */ + if (i-oopsstart > 60) + { + inbacktrace = 0; + oopsstart = -1; + VERB3 log("Dropped oops, too long"); + continue; + } + if (!inbacktrace && i-oopsstart > 40) + { + /*inbacktrace = 0; - already is */ + oopsstart = -1; + VERB3 log("Dropped oops, too long"); + continue; + } + } + } /* while (i < linecount) */ + + /* process last oops if we have one */ + if (oopsstart >= 0 && inbacktrace) + { + int oopsend = i-1; + VERB3 log("End of oops at line %d (end of file): '%s'", oopsend, lines_info[oopsend].ptr); + if (record_oops(oopses, lines_info, oopsstart, oopsend)) + oopsesfound++; + } + + free(lines_info); + return oopsesfound; } |