summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Arapov <aarapov@redhat.com>2009-03-26 16:47:00 +0100
committerAnton Arapov <aarapov@redhat.com>2009-03-26 16:47:00 +0100
commit6b54fffc7873f0006c19acc96f97b9781e1402ae (patch)
tree1bdab71a53afe311260ddaee415ffcda4b0611e3
parent4932e17099e311cb1b4bd20c807a2cfe38990d90 (diff)
downloadabrt-6b54fffc7873f0006c19acc96f97b9781e1402ae.tar.gz
abrt-6b54fffc7873f0006c19acc96f97b9781e1402ae.tar.xz
abrt-6b54fffc7873f0006c19acc96f97b9781e1402ae.zip
kerneloops - plugin: huge changeset, make things more c++-ish, configurable syslog
-rw-r--r--lib/Plugins/Kerneloops.conf4
-rw-r--r--lib/Plugins/Kerneloops.cpp180
-rw-r--r--lib/Plugins/Kerneloops.h14
-rw-r--r--lib/Plugins/KerneloopsSysLog.cpp213
-rw-r--r--lib/Plugins/KerneloopsSysLog.h32
5 files changed, 256 insertions, 187 deletions
diff --git a/lib/Plugins/Kerneloops.conf b/lib/Plugins/Kerneloops.conf
new file mode 100644
index 00000000..0022711d
--- /dev/null
+++ b/lib/Plugins/Kerneloops.conf
@@ -0,0 +1,4 @@
+# Kerneloops configuration.
+################################################################################
+
+SysLogFile = /var/log/messages
diff --git a/lib/Plugins/Kerneloops.cpp b/lib/Plugins/Kerneloops.cpp
index 07c8e066..8d7d5d69 100644
--- a/lib/Plugins/Kerneloops.cpp
+++ b/lib/Plugins/Kerneloops.cpp
@@ -22,22 +22,43 @@
* Anton Arapov <anton@redhat.com>
*/
+#include "Kerneloops.h"
+#include "KerneloopsSysLog.h"
#include "DebugDump.h"
-#include "DynamicLibrary.h"
+#include "Settings.h"
-#include <ctype.h>
#include <sstream>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <limits.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <asm/unistd.h>
-#include "Kerneloops.h"
-#include "KerneloopsDmesg.h"
+#define MAX(A,B) ((A) > (B) ? (A) : (B))
+
+CAnalyzerKerneloops::CAnalyzerKerneloops() :
+ m_sSysLogFile("/var/log/messages")
+{}
+
+void CAnalyzerKerneloops::WriteSysLog(int m_nCount)
+{
+ if (m_nCount > 0) {
+ openlog("abrt", 0, LOG_KERN);
+ syslog(LOG_WARNING, "Kerneloops: Reported %i kernel oopses to Abrt", m_nCount);
+ closelog();
+ }
+}
std::string CAnalyzerKerneloops::GetLocalUUID(const std::string& pDebugDumpDir)
{
std::string m_sOops;
std::stringstream m_sHash;
- CDebugDump dd;
- dd.Open(pDebugDumpDir);
- dd.LoadText(FILENAME_TEXTDATA1, m_sOops);
+ CDebugDump m_pDebugDump;
+ m_pDebugDump.Open(pDebugDumpDir);
+ m_pDebugDump.LoadText(FILENAME_TEXTDATA1, m_sOops);
/* An algorithm proposed by Donald E. Knuth in The Art Of Computer
* Programming Volume 3, under the topic of sorting and search
@@ -58,7 +79,150 @@ std::string CAnalyzerKerneloops::GetGlobalUUID(const std::string& pDebugDumpDir)
return GetLocalUUID(pDebugDumpDir);
}
+void CAnalyzerKerneloops::Report()
+{
+ CDebugDump m_pDebugDump;
+ char m_sPath[PATH_MAX];
+ std::list<COops> m_pOopsList;
+
+ time_t t = time(NULL);
+ if (((time_t) -1) == t)
+ {
+ fprintf(stderr, "Kerneloops: cannot get local time.\n");
+ perror("");
+ // TODO: throw -4
+ }
+
+ m_pOopsList = m_pSysLog.GetOopsList();
+ m_pSysLog.ClearOopsList();
+ while (!m_pOopsList.empty())
+ {
+ snprintf(m_sPath, sizeof(m_sPath), "%s/kerneloops-%d-%d", DEBUG_DUMPS_DIR, t, m_pOopsList.size());
+
+ COops m_pOops;
+ m_pOops = m_pOopsList.back();
+
+ try
+ {
+ m_pDebugDump.Create(m_sPath);
+ m_pDebugDump.SaveText(FILENAME_ANALYZER, "Kerneloops");
+ m_pDebugDump.SaveText(FILENAME_UID, "0");
+ m_pDebugDump.SaveText(FILENAME_EXECUTABLE, "kernel");
+ m_pDebugDump.SaveText(FILENAME_KERNEL, m_pOops.m_sVersion);
+ m_pDebugDump.SaveText(FILENAME_PACKAGE, "not_applicable");
+ m_pDebugDump.SaveText(FILENAME_TEXTDATA1, m_pOops.m_sData);
+ m_pDebugDump.Close();
+ }
+ catch (std::string sError)
+ {
+ fprintf(stderr, "Kerneloops: %s\n", sError.c_str());
+ // TODO: throw -2
+ }
+ m_pOopsList.pop_back();
+ }
+}
+
void CAnalyzerKerneloops::Init()
{
- scan_logs();
+ /* hack: release Init() */
+ pid_t pid = fork();
+ if (pid)
+ return;
+ // TODO: throw if we can't fork()
+
+ sched_yield();
+
+#ifdef PR_SET_TIMERSLACK
+ /*
+ * Signal the kernel that we're not timing critical
+ */
+ prctl(PR_SET_TIMERSLACK,1000*1000*1000, 0, 0, 0);
+#endif
+
+ /* we scan dmesg before /var/log/messages; dmesg is a more accurate source normally */
+ ScanDmesg();
+ /* during boot... don't go too fast and slow the system down */
+ sleep(10);
+ ScanSysLogFile(m_sSysLogFile.c_str(), 1);
+
+ while(1) {
+ sleep(10);
+ ScanDmesg();
+ }
+}
+
+void CAnalyzerKerneloops::ScanDmesg()
+{
+ int m_nFoundOopses;
+ char *buffer;
+
+ buffer = (char*)calloc(getpagesize()+1, 1);
+
+ syscall(__NR_syslog, 3, buffer, getpagesize());
+ m_nFoundOopses = m_pSysLog.ExtractOops(buffer, strlen(buffer), 0);
+ free(buffer);
+
+ if (m_nFoundOopses > 0)
+ Report();
+}
+
+void CAnalyzerKerneloops::ScanSysLogFile(const char *filename, int issyslog)
+{
+ char *buffer;
+ struct stat statb;
+ FILE *file;
+ int ret;
+ int m_nFoundOopses;
+ size_t buflen;
+
+ memset(&statb, 0, sizeof(statb));
+
+ ret = stat(filename, &statb);
+
+ if (statb.st_size < 1 || ret != 0)
+ return;
+
+ /*
+ * in theory there's a race here, since someone could spew
+ * to /var/log/messages before we read it in... we try to
+ * deal with it by reading at most 1023 bytes extra. If there's
+ * more than that.. any oops will be in dmesg anyway.
+ * Do not try to allocate an absurt amount of memory; ignore
+ * older log messages because they are unlikely to have
+ * sufficiently recent data to be useful. 32MB is more
+ * than enough; it's not worth looping through more log
+ * if the log is larger than that.
+ */
+ buflen = MAX(statb.st_size+1024, 32*1024*1024);
+ buffer = (char*)calloc(buflen, 1);
+ assert(buffer != NULL);
+
+ file = fopen(filename, "rm");
+ if (!file) {
+ free(buffer);
+ return;
+ }
+ fseek(file, -buflen, SEEK_END);
+ ret = fread(buffer, 1, buflen-1, file);
+ fclose(file);
+
+ if (ret > 0)
+ m_nFoundOopses = m_pSysLog.ExtractOops(buffer, buflen-1, issyslog);
+ free(buffer);
+
+ if (m_nFoundOopses > 0) {
+ Report();
+ WriteSysLog(m_nFoundOopses);
+ }
+}
+
+void CAnalyzerKerneloops::LoadSettings(const std::string& pPath)
+{
+ map_settings_t settings;
+ load_settings(pPath, settings);
+
+ if (settings.find("SysLogFile")!= settings.end())
+ {
+ m_sSysLogFile = settings["SysLogFile"];
+ }
}
diff --git a/lib/Plugins/Kerneloops.h b/lib/Plugins/Kerneloops.h
index 52cba4e5..7e0c0ac8 100644
--- a/lib/Plugins/Kerneloops.h
+++ b/lib/Plugins/Kerneloops.h
@@ -30,14 +30,26 @@
#include <string>
+#include "KerneloopsSysLog.h"
+
class CAnalyzerKerneloops : public CAnalyzer
{
+ private:
+ void WriteSysLog(int m_nCount);
+ void Report();
+ std::string m_sSysLogFile;
+ CSysLog m_pSysLog;
+
public:
+ CAnalyzerKerneloops();
virtual ~CAnalyzerKerneloops() {}
std::string GetLocalUUID(const std::string& pDebugDumpDir);
std::string GetGlobalUUID(const std::string& pDebugDumpDir);
- void CreateReport(const std::string& pDebugDumpDir) {}
void Init();
+ void CreateReport(const std::string& pDebugDumpDir) {}
+ void LoadSettings(const std::string& pPath);
+ void ScanDmesg();
+ void ScanSysLogFile(const char *filename, int issyslog);
};
PLUGIN_INFO(ANALYZER,
diff --git a/lib/Plugins/KerneloopsSysLog.cpp b/lib/Plugins/KerneloopsSysLog.cpp
index 67f16fc4..59e66870 100644
--- a/lib/Plugins/KerneloopsSysLog.cpp
+++ b/lib/Plugins/KerneloopsSysLog.cpp
@@ -24,22 +24,11 @@
* Arjan van de Ven <arjan@linux.intel.com>
*/
-#include <unistd.h>
+#include "KerneloopsSysLog.h"
+
+#include <list>
#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
-#include <assert.h>
-#include <syslog.h>
-#include <limits.h>
-#include <asm/unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include "DebugDump.h"
-#include "KerneloopsDmesg.h"
-
-
-#define MAX(A,B) ((A) > (B) ? (A) : (B))
/*
* This limits the number of oopses we'll submit per session;
@@ -48,47 +37,37 @@
*/
#define MAX_OOPS 16
-
-struct oops {
- struct oops *next;
- char *text;
- char *version;
-};
-
-/* we queue up oopses, and then submit in a batch.
- * This is useful to be able to cancel all submissions, in case
- * we later find our marker indicating we submitted everything so far already
- * previously.
- */
-static struct oops *queued_oopses;
-static int submitted;
-
static char **linepointer;
static char *linelevel;
static int linecount;
-void queue_oops(char *oops, char *version)
+CSysLog::CSysLog() :
+ m_nFoundOopses(0)
+{}
+
+void CSysLog::QueueOops(char *data, char *version)
{
- struct oops *newoops;
+ COops m_NewOops;
- if (submitted > MAX_OOPS)
+ if (m_nFoundOopses > MAX_OOPS)
return;
- newoops = (struct oops*)malloc(sizeof(struct oops));
- memset(newoops, 0, sizeof(struct oops));
- newoops->next = queued_oopses;
- newoops->text = strdup(oops);
- newoops->version = strdup(version);
- queued_oopses = newoops;
- submitted++;
+ m_NewOops.m_sData = strdup(data);
+ m_NewOops.m_sVersion = strdup(version);
+
+ m_OopsQueue.push_back(m_NewOops);
+ m_nFoundOopses++;
+}
+
+void CSysLog::ClearOopsList()
+{
+ m_OopsQueue.clear();
}
-static void write_logfile(int count)
+std::list<COops> CSysLog::GetOopsList()
{
- openlog("abrt", 0, LOG_KERN);
- syslog(LOG_WARNING, "Kerneloops hook: Reported %i kernel oopses to Abrt", count);
- closelog();
+ return m_OopsQueue;
}
/*
@@ -96,7 +75,7 @@ static void write_logfile(int count)
* (null terminated). The linepointer array is assumed to be
* allocated already.
*/
-static void fill_linepointers(char *buffer, int remove_syslog)
+void CSysLog::FillLinePointers(char *buffer, int remove_syslog)
{
char *c;
linecount = 0;
@@ -180,7 +159,7 @@ static void fill_linepointers(char *buffer, int remove_syslog)
/*
* extract_version tries to find the kernel version in given data
*/
-static inline int extract_version(char *linepointer, char *version)
+int CSysLog::ExtractVersion(char *linepointer, char *version)
{
int ret;
@@ -211,25 +190,26 @@ static inline int extract_version(char *linepointer, char *version)
/*
* extract_oops tries to find oops signatures in a log
*/
-static void extract_oops(char *buffer, size_t buflen, int remove_syslog)
+int CSysLog::ExtractOops(char *buffer, size_t buflen, int remove_syslog)
{
int i;
char prevlevel = 0;
int oopsstart = -1;
int oopsend;
int inbacktrace = 0;
+ int oopsesfound = 0;
linepointer = (char**)calloc(buflen+1, sizeof(char*));
if (!linepointer)
- return;
+ return 0;
linelevel = (char*)calloc(buflen+1, sizeof(char));
if (!linelevel) {
free(linepointer);
linepointer = NULL;
- return;
+ return 0;
}
- fill_linepointers(buffer, remove_syslog);
+ FillLinePointers(buffer, remove_syslog);
oopsend = linecount;
@@ -278,7 +258,7 @@ static void extract_oops(char *buffer, size_t buflen, int remove_syslog)
oopsstart = i;
if (strstr(c, "Oops:") && i >= 3)
oopsstart = i-3;
-#if 0
+#if DEBUG
/* debug information */
if (oopsstart >= 0) {
printf("Found start of oops at line %i\n", oopsstart);
@@ -369,13 +349,15 @@ static void extract_oops(char *buffer, size_t buflen, int remove_syslog)
is_version = 0;
for (q = oopsstart; q <= oopsend; q++) {
if (!is_version)
- is_version = extract_version(linepointer[q], version);
+ is_version = ExtractVersion(linepointer[q], version);
strcat(oops, linepointer[q]);
strcat(oops, "\n");
}
/* too short oopses are invalid */
- if (strlen(oops) > 100)
- queue_oops(oops, version);
+ if (strlen(oops) > 100) {
+ QueueOops(oops, version);
+ oopsesfound++;
+ }
oopsstart = -1;
inbacktrace = 0;
oopsend = linecount;
@@ -417,13 +399,15 @@ static void extract_oops(char *buffer, size_t buflen, int remove_syslog)
is_version = 0;
for (q = oopsstart; q <= oopsend; q++) {
if (!is_version)
- is_version = extract_version(linepointer[q], version);
+ is_version = ExtractVersion(linepointer[q], version);
strcat(oops, linepointer[q]);
strcat(oops, "\n");
}
/* too short oopses are invalid */
- if (strlen(oops) > 100)
- queue_oops(oops, version);
+ if (strlen(oops) > 100) {
+ QueueOops(oops, version);
+ oopsesfound++;
+ }
oopsstart = -1;
inbacktrace = 0;
oopsend = linecount;
@@ -434,121 +418,6 @@ static void extract_oops(char *buffer, size_t buflen, int remove_syslog)
free(linelevel);
linepointer = NULL;
linelevel = NULL;
-}
-
-void scan_dmesg(void __unused *unused)
-{
- char *buffer;
-
- buffer = (char*)calloc(getpagesize()+1, 1);
-
- syscall(__NR_syslog, 3, buffer, getpagesize());
- extract_oops(buffer, strlen(buffer), 0);
- free(buffer);
-}
-
-void scan_filename(char *filename, int issyslog)
-{
- char *buffer;
- struct stat statb;
- FILE *file;
- int ret;
- size_t buflen;
-
- memset(&statb, 0, sizeof(statb));
-
- ret = stat(filename, &statb);
-
- if (statb.st_size < 1 || ret != 0)
- return;
-
- /*
- * in theory there's a race here, since someone could spew
- * to /var/log/messages before we read it in... we try to
- * deal with it by reading at most 1023 bytes extra. If there's
- * more than that.. any oops will be in dmesg anyway.
- * Do not try to allocate an absurt amount of memory; ignore
- * older log messages because they are unlikely to have
- * sufficiently recent data to be useful. 32MB is more
- * than enough; it's not worth looping through more log
- * if the log is larger than that.
- */
- buflen = MAX(statb.st_size+1024, 32*1024*1024);
- buffer = (char*)calloc(buflen, 1);
- assert(buffer != NULL);
-
- file = fopen(filename, "rm");
- if (!file) {
- free(buffer);
- return;
- }
- fseek(file, -buflen, SEEK_END);
- ret = fread(buffer, 1, buflen-1, file);
- fclose(file);
-
- if (ret > 0)
- extract_oops(buffer, buflen-1, issyslog);
- free(buffer);
-}
-
-int scan_logs()
-{
- int ret;
- struct oops *oops;
- struct oops *queue;
- char path[PATH_MAX];
- int count;
- ret = 0;
-
- time_t t = time(NULL);
- if (((time_t) -1) == t)
- {
- fprintf(stderr, "Kerneloops: cannot get local time.\n");
- perror("");
- return -4;
- }
-
- /* scan dmesg and messages for oopses */
- scan_dmesg(NULL);
- scan_filename("/var/log/messages", 1);
-
- CDebugDump dd;
- queue = queued_oopses;
- queued_oopses = NULL;
- barrier();
- oops = queue;
- count = 0;
- while (oops) {
- struct oops *next;
-
- snprintf(path, sizeof(path), "%s/kerneloops-%d-%d", DEBUG_DUMPS_DIR, t, count);
- try
- {
- dd.Create(path);
- dd.SaveText(FILENAME_ANALYZER, "Kerneloops");
- dd.SaveText(FILENAME_UID, "0");
- dd.SaveText(FILENAME_EXECUTABLE, "kernel");
- dd.SaveText(FILENAME_KERNEL, oops->version);
- dd.SaveText(FILENAME_PACKAGE, "not_applicable");
- dd.SaveText(FILENAME_TEXTDATA1, oops->text);
- count++;
- dd.Close();
- }
- catch (std::string sError)
- {
- fprintf(stderr, "Kerneloops: %s\n", sError.c_str());
- ret = -2;
- }
- next = oops->next;
- free(oops->text);
- free(oops->version);
- free(oops);
- oops = next;
- }
-
- if (ret == 0)
- write_logfile(count);
-
- return ret;
+ return oopsesfound;
}
diff --git a/lib/Plugins/KerneloopsSysLog.h b/lib/Plugins/KerneloopsSysLog.h
index 95e5b49c..e0bf16ff 100644
--- a/lib/Plugins/KerneloopsSysLog.h
+++ b/lib/Plugins/KerneloopsSysLog.h
@@ -24,13 +24,33 @@
* Arjan van de Ven <arjan@linux.intel.com>
*/
-#ifndef __INCLUDE_GUARD_KERNELOOPSLIB_H_
-#define __INCLUDE_GUARD_KERNELOOPSLIB_H_
+#ifndef __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_
+#define __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_
-/* borrowed from the kernel */
-#define barrier() __asm__ __volatile__("": : :"memory")
-#define __unused __attribute__ ((__unused__))
+#include <string>
+#include <list>
-extern int scan_logs();
+class COops
+{
+ public:
+ std::string m_sData;
+ std::string m_sVersion;
+};
+
+class CSysLog
+{
+ private:
+ void QueueOops(char *data, char *version);
+ int ExtractVersion(char *linepointer, char *version);
+ void FillLinePointers(char *buffer, int remove_syslog);
+ std::list<COops> m_OopsQueue;
+ int m_nFoundOopses;
+
+ public:
+ CSysLog();
+ std::list<COops> GetOopsList();
+ void ClearOopsList();
+ int ExtractOops(char *buffer, size_t buflen, int remove_syslog);
+};
#endif