summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJiri Moskovcak <jmoskovc@redhat.com>2010-11-10 17:01:31 +0100
committerJiri Moskovcak <jmoskovc@redhat.com>2010-11-10 18:27:05 +0100
commit3fce116492052267e5e1a634e5404b1b518f7ef3 (patch)
tree3160a2d429987573004fb8166d40542b76a7315b /src
parent9d2cb4518c3a8a72ccc714ddbc131aaa84506092 (diff)
downloadabrt-3fce116492052267e5e1a634e5404b1b518f7ef3.tar.gz
abrt-3fce116492052267e5e1a634e5404b1b518f7ef3.tar.xz
abrt-3fce116492052267e5e1a634e5404b1b518f7ef3.zip
move files from lib/plugins to src/plugins
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/daemon/Daemon.cpp5
-rw-r--r--src/daemon/Makefile.am193
-rw-r--r--src/hooks/Makefile.am2
-rw-r--r--src/plugins/Bugzilla.conf12
-rw-r--r--src/plugins/Bugzilla.cpp155
-rw-r--r--src/plugins/Bugzilla.glade246
-rw-r--r--src/plugins/Bugzilla.h37
-rw-r--r--src/plugins/CCpp.conf44
-rw-r--r--src/plugins/CCpp.cpp279
-rw-r--r--src/plugins/CCpp.h49
-rw-r--r--src/plugins/FileTransfer.conf35
-rw-r--r--src/plugins/FileTransfer.cpp367
-rw-r--r--src/plugins/FileTransfer.h46
-rw-r--r--src/plugins/Kerneloops.conf13
-rw-r--r--src/plugins/Kerneloops.cpp31
-rw-r--r--src/plugins/Kerneloops.h38
-rw-r--r--src/plugins/KerneloopsReporter.cpp143
-rw-r--r--src/plugins/KerneloopsReporter.glade118
-rw-r--r--src/plugins/KerneloopsReporter.h47
-rw-r--r--src/plugins/KerneloopsScanner.cpp214
-rw-r--r--src/plugins/KerneloopsScanner.h42
-rw-r--r--src/plugins/KerneloopsSysLog.cpp383
-rw-r--r--src/plugins/KerneloopsSysLog.h35
-rw-r--r--src/plugins/Logger.conf8
-rw-r--r--src/plugins/Logger.glade135
-rw-r--r--src/plugins/Mailx.conf17
-rw-r--r--src/plugins/Mailx.cpp153
-rw-r--r--src/plugins/Mailx.glade184
-rw-r--r--src/plugins/Mailx.h48
-rw-r--r--src/plugins/Makefile.am316
-rw-r--r--src/plugins/Python.conf1
-rw-r--r--src/plugins/Python.cpp30
-rw-r--r--src/plugins/Python.h30
-rw-r--r--src/plugins/RHTSupport.conf11
-rw-r--r--src/plugins/RHTSupport.cpp147
-rw-r--r--src/plugins/RHTSupport.glade213
-rw-r--r--src/plugins/RHTSupport.h38
-rw-r--r--src/plugins/ReportUploader.conf23
-rw-r--r--src/plugins/ReportUploader.cpp517
-rw-r--r--src/plugins/ReportUploader.glade249
-rw-r--r--src/plugins/ReportUploader.h55
-rw-r--r--src/plugins/SOSreport.conf1
-rw-r--r--src/plugins/SOSreport.cpp169
-rw-r--r--src/plugins/SOSreport.h31
-rw-r--r--src/plugins/SQLite3.conf4
-rw-r--r--src/plugins/SQLite3.cpp742
-rw-r--r--src/plugins/SQLite3.h58
-rw-r--r--src/plugins/abrt-Bugzilla.743
-rw-r--r--src/plugins/abrt-FileTransfer.772
-rw-r--r--src/plugins/abrt-KerneloopsReporter.740
-rw-r--r--src/plugins/abrt-KerneloopsScanner.746
-rw-r--r--src/plugins/abrt-Logger.744
-rw-r--r--src/plugins/abrt-Mailx.757
-rw-r--r--src/plugins/abrt-ReportUploader.755
-rw-r--r--src/plugins/abrt-SQLite3.736
-rw-r--r--src/plugins/abrt-action-analyze-c.c (renamed from src/daemon/abrt-action-analyze-c.c)0
-rw-r--r--src/plugins/abrt-action-analyze-oops.c (renamed from src/daemon/abrt-action-analyze-oops.c)0
-rw-r--r--src/plugins/abrt-action-analyze-python.c (renamed from src/daemon/abrt-action-analyze-python.c)0
-rw-r--r--src/plugins/abrt-action-bugzilla.cpp (renamed from src/daemon/abrt-action-bugzilla.cpp)0
-rw-r--r--src/plugins/abrt-action-generate-backtrace.c (renamed from src/daemon/abrt-action-generate-backtrace.c)0
-rwxr-xr-xsrc/plugins/abrt-action-install-debuginfo (renamed from src/daemon/abrt-action-install-debuginfo)0
-rw-r--r--src/plugins/abrt-action-kerneloops.cpp (renamed from src/daemon/abrt-action-kerneloops.cpp)0
-rw-r--r--src/plugins/abrt-action-print.cpp (renamed from src/daemon/abrt-action-print.cpp)0
-rw-r--r--src/plugins/abrt-action-rhtsupport.cpp (renamed from src/daemon/abrt-action-rhtsupport.cpp)0
-rw-r--r--src/plugins/abrt-plugins.743
-rw-r--r--src/plugins/abrt_rh_support.c (renamed from src/daemon/abrt_rh_support.c)0
-rw-r--r--src/plugins/abrt_rh_support.h (renamed from src/daemon/abrt_rh_support.h)0
68 files changed, 5968 insertions, 184 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 00227a47..f6117250 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1 +1 @@
-SUBDIRS = hooks btparser daemon applet gui cli
+SUBDIRS = hooks btparser daemon applet gui cli plugins
diff --git a/src/daemon/Daemon.cpp b/src/daemon/Daemon.cpp
index a30b2d97..72bb54bf 100644
--- a/src/daemon/Daemon.cpp
+++ b/src/daemon/Daemon.cpp
@@ -843,6 +843,11 @@ int main(int argc, char** argv)
if (!getenv("PATH"))
putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
+ /* need to add LIBEXEC_DIR to PATH, because otherwise abrt-action-*
+ * is not found by exec()
+ */
+ putenv(xasprintf("PATH=%s:%s", LIBEXEC_DIR, getenv("PATH")));
+
putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
msg_prefix = "abrtd"; /* for log(), error_msg() and such */
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
index a939798c..072f7f17 100644
--- a/src/daemon/Makefile.am
+++ b/src/daemon/Makefile.am
@@ -1,21 +1,13 @@
bin_SCRIPTS = \
- abrt-action-install-debuginfo \
abrt-handle-upload
-
-sbin_PROGRAMS = abrtd \
- abrt-server \
- abrt-action-analyze-c \
- abrt-action-analyze-python \
- abrt-action-analyze-oops \
- abrt-action-generate-backtrace \
+libexec_PROGRAMS = \
abrt-action-save-package-data
bin_PROGRAMS = \
- abrt-handle-crashdump \
- abrt-action-bugzilla \
- abrt-action-rhtsupport \
- abrt-action-kerneloops \
- abrt-action-print
+ abrt-handle-crashdump
+
+sbin_PROGRAMS = abrtd \
+ abrt-server
abrtd_SOURCES = \
PluginManager.h PluginManager.cpp \
@@ -35,6 +27,7 @@ abrtd_CPPFLAGS = \
-DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -DLIBEXEC_DIR=\"$(LIBEXEC_DIR)\" \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
$(ENABLE_SOCKET_OR_DBUS) \
@@ -63,45 +56,9 @@ abrt_server_CPPFLAGS = \
abrt_server_LDADD = \
../../lib/utils/libABRTUtils.la
-abrt_action_analyze_c_SOURCES = \
- abrt-action-analyze-c.c
-abrt_action_analyze_c_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- -D_GNU_SOURCE \
- -Wall -Werror
-abrt_action_analyze_c_LDADD = \
- ../../lib/utils/libABRTUtils.la
-
-abrt_action_analyze_python_SOURCES = \
- abrt-action-analyze-python.c
-abrt_action_analyze_python_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- -D_GNU_SOURCE \
- -Wall -Werror
-abrt_action_analyze_python_LDADD = \
- ../../lib/utils/libABRTUtils.la
-
-abrt_action_analyze_oops_SOURCES = \
- abrt-action-analyze-oops.c
-abrt_action_analyze_oops_CPPFLAGS = \
+abrt_handle_crashdump_SOURCES = \
+ abrt-handle-crashdump.c
+abrt_handle_crashdump_CPPFLAGS = \
-I$(srcdir)/../../inc \
-I$(srcdir)/../../lib/utils \
-DBIN_DIR=\"$(bindir)\" \
@@ -114,28 +71,9 @@ abrt_action_analyze_oops_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
-D_GNU_SOURCE \
-Wall -Werror
-abrt_action_analyze_oops_LDADD = \
+abrt_handle_crashdump_LDADD = \
../../lib/utils/libABRTUtils.la
-abrt_action_generate_backtrace_SOURCES = \
- abrt-action-generate-backtrace.c
-abrt_action_generate_backtrace_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- -D_GNU_SOURCE \
- -Wall -Werror
-abrt_action_generate_backtrace_LDADD = \
- ../../lib/utils/libABRTUtils.la \
- ../btparser/libbtparser.la
-
abrt_action_save_package_data_SOURCES = \
rpm.h rpm.c \
Settings.h Settings.cpp \
@@ -160,115 +98,6 @@ abrt_action_save_package_data_LDADD = \
../../lib/utils/libABRTdUtils.la \
../../lib/utils/libABRTUtils.la
-abrt_handle_crashdump_SOURCES = \
- abrt-handle-crashdump.c
-abrt_handle_crashdump_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- -D_GNU_SOURCE \
- -Wall -Werror
-abrt_handle_crashdump_LDADD = \
- ../../lib/utils/libABRTUtils.la
-
-abrt_action_bugzilla_SOURCES = \
- abrt-action-bugzilla.cpp
-abrt_action_bugzilla_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- $(GLIB_CFLAGS) \
- -D_GNU_SOURCE \
- -Wall -Werror
-abrt_action_bugzilla_LDADD = \
- $(GLIB_LIBS) \
- ../../lib/utils/libABRT_web_utils.la \
- ../../lib/utils/libABRTdUtils.la \
- ../../lib/utils/libABRTUtils.la
-
-abrt_action_rhtsupport_SOURCES = \
- abrt_rh_support.h abrt_rh_support.c \
- abrt-action-rhtsupport.cpp
-abrt_action_rhtsupport_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- $(GLIB_CFLAGS) \
- $(XMLRPC_CFLAGS) $(XMLRPC_CLIENT_CFLAGS) \
- -D_GNU_SOURCE \
- -Wall -Werror
-abrt_action_rhtsupport_LDFLAGS = -ltar
-abrt_action_rhtsupport_LDADD = \
- $(GLIB_LIBS) \
- $(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS) \
- ../../lib/utils/libABRT_web_utils.la \
- ../../lib/utils/libABRTdUtils.la \
- ../../lib/utils/libABRTUtils.la
-
-abrt_action_kerneloops_SOURCES = \
- abrt-action-kerneloops.cpp
-abrt_action_kerneloops_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- $(GLIB_CFLAGS) \
- -D_GNU_SOURCE \
- -Wall -Werror
-# libABRTdUtils is used only because of LoadPluginSettings:
-abrt_action_kerneloops_LDADD = \
- ../../lib/utils/libABRT_web_utils.la \
- ../../lib/utils/libABRTdUtils.la \
- ../../lib/utils/libABRTUtils.la
-
-abrt_action_print_SOURCES = \
- abrt-action-print.cpp
-abrt_action_print_CPPFLAGS = \
- -I$(srcdir)/../../inc \
- -I$(srcdir)/../../lib/utils \
- -DBIN_DIR=\"$(bindir)\" \
- -DVAR_RUN=\"$(VAR_RUN)\" \
- -DCONF_DIR=\"$(CONF_DIR)\" \
- -DLOCALSTATEDIR='"$(localstatedir)"' \
- -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
- -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
- -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
- -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
- $(GLIB_CFLAGS) \
- -D_GNU_SOURCE \
- -Wall -Werror
-# libABRTdUtils is used only because of make_description_logger:
-abrt_action_print_LDADD = \
- ../../lib/utils/libABRTdUtils.la \
- ../../lib/utils/libABRTUtils.la
-
dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/
dist_dbusabrtconf_DATA = dbus-abrt.conf
@@ -286,7 +115,7 @@ dist_comredhatabrtservice_DATA = com.redhat.abrt.service
man_MANS = abrtd.8 abrt.conf.5
-EXTRA_DIST = $(man_MANS) abrt-action-install-debuginfo abrt-handle-upload
+EXTRA_DIST = $(man_MANS) abrt-handle-upload
if HAVE_SYSTEMD
dist_systemdsystemunit_DATA = \
diff --git a/src/hooks/Makefile.am b/src/hooks/Makefile.am
index 52c151ba..d20fad91 100644
--- a/src/hooks/Makefile.am
+++ b/src/hooks/Makefile.am
@@ -20,7 +20,7 @@ dumpoops_SOURCES = \
dumpoops_CPPFLAGS = \
-I$(srcdir)/../../inc \
-I$(srcdir)/../../lib/utils \
- -I$(srcdir)/../../lib/plugins \
+ -I$(srcdir)/../plugins \
-DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
-DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
diff --git a/src/plugins/Bugzilla.conf b/src/plugins/Bugzilla.conf
new file mode 100644
index 00000000..76e0d1d8
--- /dev/null
+++ b/src/plugins/Bugzilla.conf
@@ -0,0 +1,12 @@
+# Description: Reports bugs to bugzilla
+
+Enabled = yes
+
+# Bugzilla URL
+BugzillaURL = https://bugzilla.redhat.com/
+# yes means that ssl certificates will be checked
+SSLVerify = yes
+# your login has to exist, if you don have any, please create one
+Login =
+# your password
+Password =
diff --git a/src/plugins/Bugzilla.cpp b/src/plugins/Bugzilla.cpp
new file mode 100644
index 00000000..452d7a58
--- /dev/null
+++ b/src/plugins/Bugzilla.cpp
@@ -0,0 +1,155 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "abrtlib.h"
+#include "crash_types.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+#include "Bugzilla.h"
+
+using namespace std;
+
+CReporterBugzilla::CReporterBugzilla()
+{
+ m_pSettings["BugzillaURL"] = "https://bugzilla.redhat.com";
+ m_pSettings["Login"] = "";
+ m_pSettings["Password"] = "";
+ m_pSettings["SSLVerify"] = "yes";
+ m_pSettings["RatingRequired"] = "yes";
+}
+
+CReporterBugzilla::~CReporterBugzilla()
+{
+}
+
+void CReporterBugzilla::SetSettings(const map_plugin_settings_t& pSettings)
+{
+//BUG! This gets called when user's keyring contains login data,
+//then it takes precedence over /etc/abrt/plugins/Bugzilla.conf.
+//I got a case when keyring had a STALE password, and there was no way
+//for me to know that it is being used. Moreover, when I discovered it
+//(by hacking abrt source!), I don't know how to purge it from the keyring.
+//At the very least, log("SOMETHING") here.
+
+ /* Can't simply do this:
+
+ m_pSettings = pSettings;
+
+ * - it will erase keys which aren't present in pSettings.
+ * Example: if Bugzilla.conf doesn't have "Login = foo",
+ * then there's no pSettings["Login"] and m_pSettings = pSettings
+ * will nuke default m_pSettings["Login"] = "",
+ * making GUI think that we have no "Login" key at all
+ * and thus never overriding it - even if it *has* an override!
+ */
+
+ map_plugin_settings_t::iterator it = m_pSettings.begin();
+ while (it != m_pSettings.end())
+ {
+ map_plugin_settings_t::const_iterator override = pSettings.find(it->first);
+ if (override != pSettings.end())
+ {
+ VERB3 log(" 3 settings[%s]='%s'", it->first.c_str(), it->second.c_str());
+ it->second = override->second;
+ }
+ it++;
+ }
+}
+
+string CReporterBugzilla::Report(const map_crash_data_t& crash_data,
+ const map_plugin_settings_t& settings,
+ const char *args)
+{
+ /* abrt-action-bugzilla [-s] -c /etc/arbt/Bugzilla.conf -c - -d pCrashData.dir NULL */
+ char *argv[9];
+ char **pp = argv;
+ *pp++ = (char*)"abrt-action-bugzilla";
+
+//We want to consume output, so don't redirect to syslog.
+// if (logmode & LOGMODE_SYSLOG)
+// *pp++ = (char*)"-s";
+//TODO: the actions<->daemon interaction will be changed anyway...
+
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)(PLUGINS_CONF_DIR"/Bugzilla."PLUGINS_CONF_EXTENSION);
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)"-";
+ *pp++ = (char*)"-d";
+ *pp++ = (char*)get_crash_data_item_content_or_NULL(crash_data, CD_DUMPDIR);
+ *pp = NULL;
+ int pipefds[2];
+ pid_t pid = fork_execv_on_steroids(EXECFLG_INPUT + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
+ argv,
+ pipefds,
+ /* unsetenv_vec: */ NULL,
+ /* dir: */ NULL,
+ /* uid(unused): */ 0
+ );
+
+ /* Write the configuration to stdin */
+ map_plugin_settings_t::const_iterator it = settings.begin();
+ while (it != settings.end())
+ {
+ full_write_str(pipefds[1], it->first.c_str());
+ full_write_str(pipefds[1], "=");
+ full_write_str(pipefds[1], it->second.c_str());
+ full_write_str(pipefds[1], "\n");
+ it++;
+ }
+ close(pipefds[1]);
+
+ FILE *fp = fdopen(pipefds[0], "r");
+ if (!fp)
+ die_out_of_memory();
+
+ /* Consume log from stdout */
+ string bug_status;
+ char *buf;
+ while ((buf = xmalloc_fgetline(fp)) != NULL)
+ {
+ if (strncmp(buf, "STATUS:", 7) == 0)
+ bug_status = buf + 7;
+ else
+ if (strncmp(buf, "EXCEPT:", 7) == 0)
+ {
+ CABRTException e(EXCEP_PLUGIN, "%s", buf + 7);
+ free(buf);
+ fclose(fp);
+ waitpid(pid, NULL, 0);
+ throw e;
+ }
+ update_client("%s", buf);
+ free(buf);
+ }
+
+ fclose(fp); /* this also closes pipefds[0] */
+ /* wait for child to actually exit, and prevent leaving a zombie behind */
+ waitpid(pid, NULL, 0);
+
+ return bug_status;
+}
+
+PLUGIN_INFO(REPORTER,
+ CReporterBugzilla,
+ "Bugzilla",
+ "0.0.4",
+ _("Reports bugs to bugzilla"),
+ "npajkovs@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ PLUGINS_LIB_DIR"/Bugzilla.glade");
diff --git a/src/plugins/Bugzilla.glade b/src/plugins/Bugzilla.glade
new file mode 100644
index 00000000..cabdd06a
--- /dev/null
+++ b/src/plugins/Bugzilla.glade
@@ -0,0 +1,246 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">12</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="icon_name">abrt</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="lBugzillaURL">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Bugzilla URL:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lLogin">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Login(email):</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lPassword">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password:</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_BugzillaURL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Login">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cb_Password">
+ <property name="label" translatable="yes">Show password</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_SSLVerify">
+ <property name="label" translatable="yes">SSL verify</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Bugzilla plugin configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">Don't have an account yet?</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xpad">5</property>
+ <property name="label" translatable="yes">You can create it &lt;a href="https://bugzilla.redhat.com/createaccount.cgi"&gt;here&lt;/a&gt;</property>
+ <property name="use_markup">True</property>
+ <property name="selectable">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="bApply">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button2</action-widget>
+ <action-widget response="-10">bApply</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAction" id="action1"/>
+</interface>
diff --git a/src/plugins/Bugzilla.h b/src/plugins/Bugzilla.h
new file mode 100644
index 00000000..d7f3acf0
--- /dev/null
+++ b/src/plugins/Bugzilla.h
@@ -0,0 +1,37 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef BUGZILLA_H_
+#define BUGZILLA_H_
+
+#include "plugin.h"
+#include "reporter.h"
+
+class CReporterBugzilla : public CReporter
+{
+ public:
+ CReporterBugzilla();
+ virtual ~CReporterBugzilla();
+
+ virtual std::string Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs);
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+};
+
+#endif /* BUGZILLA_H_ */
diff --git a/src/plugins/CCpp.conf b/src/plugins/CCpp.conf
new file mode 100644
index 00000000..4af91470
--- /dev/null
+++ b/src/plugins/CCpp.conf
@@ -0,0 +1,44 @@
+# Configuration file for CCpp hook and plugin
+Enabled = yes
+
+# If you also want to dump file named "core"
+# in crashed process' current dir, set to "yes"
+MakeCompatCore = yes
+
+# Do you want a copy of crashed binary be saved?
+# (useful, for example, when _deleted binary_ segfaults)
+SaveBinaryImage = no
+
+# Generate backtrace
+Backtrace = yes
+# How long to wait for gdb to finish. Default is 60 seconds.
+GdbTimeoutSec = 120
+
+# Generate backtrace for crashes uploaded from remote machines.
+# Note that for reliable backtrace generation, your local machine
+# needs to have the crashed executable and all libraries it uses,
+# and they need to be the same versions as on remote machines.
+# If you cannot ensure that, it's better to set this option to "no"
+BacktraceRemotes = no
+
+# Generate memory map too (IGNORED FOR NOW)
+MemoryMap = no
+
+# How to get debuginfo: install, mount
+## install - download and install debuginfo packages
+## mount - mount fedora NFS with debug info
+## (IGNORED FOR NOW)
+DebugInfo = install
+
+# If this option is set to "yes",
+# debuginfos will be installed to @@LOCALSTATEDIR@@/cache/abrt-di
+InstallDebugInfo = yes
+
+# Additional directories to search for debuginfos.
+# For example, you can list a network-mounted shared store
+# of all debuginfos here.
+# ReadonlyLocalDebugInfoDirs = /path1:/path2:...
+
+# Keep @@LOCALSTATEDIR@@/cache/abrt-di
+# from growing out-of-bounds.
+DebugInfoCacheMB = 4000
diff --git a/src/plugins/CCpp.cpp b/src/plugins/CCpp.cpp
new file mode 100644
index 00000000..fad9cf62
--- /dev/null
+++ b/src/plugins/CCpp.cpp
@@ -0,0 +1,279 @@
+/*
+ CCpp.cpp
+
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <set>
+#include "abrtlib.h"
+#include "CCpp.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+#include "Polkit.h"
+
+using namespace std;
+
+#define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern"
+#define CORE_PATTERN "|"CCPP_HOOK_PATH" "DEBUG_DUMPS_DIR" %p %s %u %c"
+#define CORE_PIPE_LIMIT_IFACE "/proc/sys/kernel/core_pipe_limit"
+/* core_pipe_limit specifies how many dump_helpers might run at the same time
+0 - means unlimited, but the it's not guaranteed that /proc/<pid> of crashing
+process might not be available for dump_helper
+4 - means that 4 dump_helpers can run at the same time, which should be enough
+for ABRT, we can miss some crashes, but what are the odds that more processes
+crash at the same time? This value has been recommended by nhorman
+*/
+#define CORE_PIPE_LIMIT "4"
+
+#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di"
+
+CAnalyzerCCpp::CAnalyzerCCpp() :
+ m_bBacktrace(true),
+ m_bBacktraceRemotes(false),
+ m_bMemoryMap(false),
+ m_bInstallDebugInfo(true),
+ m_nDebugInfoCacheMB(4000),
+ m_nGdbTimeoutSec(60)
+{}
+
+/*
+ this is just a workaround until kernel changes it's behavior
+ when handling pipes in core_pattern
+*/
+#ifdef HOSTILE_KERNEL
+#define CORE_SIZE_PATTERN "Max core file size=1:unlimited"
+static int isdigit_str(char *str)
+{
+ do {
+ if (*str < '0' || *str > '9')
+ return 0;
+ } while (*++str);
+ return 1;
+}
+
+static int set_limits()
+{
+ DIR *dir = opendir("/proc");
+ if (!dir) {
+ /* this shouldn't fail, but to be safe.. */
+ return 1;
+ }
+
+ struct dirent *ent;
+ while ((ent = readdir(dir)) != NULL) {
+ if (!isdigit_str(ent->d_name))
+ continue;
+
+ char limits_name[sizeof("/proc/%s/limits") + sizeof(long)*3];
+ snprintf(limits_name, sizeof(limits_name), "/proc/%s/limits", ent->d_name);
+ FILE *limits_fp = fopen(limits_name, "r");
+ if (!limits_fp) {
+ break;
+ }
+
+ char line[128];
+ char *ulimit_c = NULL;
+ while (1) {
+ if (fgets(line, sizeof(line)-1, limits_fp) == NULL)
+ break;
+ if (strncmp(line, "Max core file size", sizeof("Max core file size")-1) == 0) {
+ ulimit_c = skip_whitespace(line + sizeof("Max core file size")-1);
+ skip_non_whitespace(ulimit_c)[0] = '\0';
+ break;
+ }
+ }
+ fclose(limits_fp);
+ if (!ulimit_c || ulimit_c[0] != '0' || ulimit_c[1] != '\0') {
+ /*process has nonzero ulimit -c, so need to modify it*/
+ continue;
+ }
+ /* echo -n 'Max core file size=1:unlimited' >/proc/PID/limits */
+ int fd = open(limits_name, O_WRONLY);
+ if (fd >= 0) {
+ errno = 0;
+ /*full_*/
+ ssize_t n = write(fd, CORE_SIZE_PATTERN, sizeof(CORE_SIZE_PATTERN)-1);
+ if (n < sizeof(CORE_SIZE_PATTERN)-1)
+ log("warning: can't write core_size limit to: %s", limits_name);
+ close(fd);
+ }
+ else
+ {
+ log("warning: can't open %s for writing", limits_name);
+ }
+ }
+ closedir(dir);
+ return 0;
+}
+#endif /* HOSTILE_KERNEL */
+
+void CAnalyzerCCpp::Init()
+{
+ FILE *fp = fopen(CORE_PATTERN_IFACE, "r");
+ if (fp)
+ {
+ char line[PATH_MAX];
+ if (fgets(line, sizeof(line), fp))
+ m_sOldCorePattern = line;
+ fclose(fp);
+ }
+ if (m_sOldCorePattern[0] == '|')
+ {
+ if (m_sOldCorePattern == CORE_PATTERN)
+ {
+ log("warning: %s already contains %s, "
+ "did abrt daemon crash recently?",
+ CORE_PATTERN_IFACE, CORE_PATTERN);
+ /* There is no point in "restoring" CORE_PATTERN_IFACE
+ * to CORE_PATTERN on exit. Will restore to a default value:
+ */
+ m_sOldCorePattern = "core";
+ } else {
+ log("warning: %s was already set to run a crash analyser (%s), "
+ "abrt may interfere with it",
+ CORE_PATTERN_IFACE, CORE_PATTERN);
+ }
+ }
+#ifdef HOSTILE_KERNEL
+ if (set_limits() != 0)
+ log("warning: failed to set core_size limit, ABRT won't detect crashes in"
+ "compiled apps");
+#endif
+
+ fp = fopen(CORE_PATTERN_IFACE, "w");
+ if (fp)
+ {
+ fputs(CORE_PATTERN, fp);
+ fclose(fp);
+ }
+
+ /* read the core_pipe_limit and change it if it's == 0
+ otherwise the abrt-hook-ccpp won't be able to read /proc/<pid>
+ of the crashing process
+ */
+ fp = fopen(CORE_PIPE_LIMIT_IFACE, "r");
+ if (fp)
+ {
+ /* we care only about the first char, if it's
+ * not '0' then we don't have to change it,
+ * because it means that it's already != 0
+ */
+ char pipe_limit[2];
+ if (!fgets(pipe_limit, sizeof(pipe_limit), fp))
+ pipe_limit[0] = '1'; /* not 0 */
+ fclose(fp);
+ if (pipe_limit[0] == '0')
+ {
+ fp = fopen(CORE_PIPE_LIMIT_IFACE, "w");
+ if (fp)
+ {
+ fputs(CORE_PIPE_LIMIT, fp);
+ fclose(fp);
+ }
+ else
+ {
+ log("warning: failed to set core_pipe_limit, ABRT won't detect"
+ "crashes in compiled apps if kernel > 2.6.31");
+ }
+ }
+ }
+}
+
+void CAnalyzerCCpp::DeInit()
+{
+ /* no need to restore the core_pipe_limit, because it's only used
+ when there is s pipe in core_pattern
+ */
+ FILE *fp = fopen(CORE_PATTERN_IFACE, "w");
+ if (fp)
+ {
+ fputs(m_sOldCorePattern.c_str(), fp);
+ fclose(fp);
+ }
+}
+
+void CAnalyzerCCpp::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("Backtrace");
+ if (it != end)
+ {
+ m_bBacktrace = string_to_bool(it->second.c_str());
+ }
+ it = pSettings.find("BacktraceRemotes");
+ if (it != end)
+ {
+ m_bBacktraceRemotes = string_to_bool(it->second.c_str());
+ }
+ it = pSettings.find("MemoryMap");
+ if (it != end)
+ {
+ m_bMemoryMap = string_to_bool(it->second.c_str());
+ }
+ it = pSettings.find("DebugInfo");
+ if (it != end)
+ {
+ m_sDebugInfo = it->second;
+ }
+ it = pSettings.find("DebugInfoCacheMB");
+ if (it != end)
+ {
+ m_nDebugInfoCacheMB = xatou(it->second.c_str());
+ }
+ it = pSettings.find("GdbTimeoutSec");
+ if (it != end)
+ {
+ m_nGdbTimeoutSec = xatoi_u(it->second.c_str());
+ }
+ it = pSettings.find("InstallDebugInfo");
+ if (it == end) //compat, remove after 0.0.11
+ it = pSettings.find("InstallDebuginfo");
+ if (it != end)
+ {
+ m_bInstallDebugInfo = string_to_bool(it->second.c_str());
+ }
+ m_sDebugInfoDirs = DEBUGINFO_CACHE_DIR;
+ it = pSettings.find("ReadonlyLocalDebugInfoDirs");
+ if (it != end)
+ {
+ m_sDebugInfoDirs += ':';
+ m_sDebugInfoDirs += it->second;
+ }
+}
+
+//ok to delete?
+//const map_plugin_settings_t& CAnalyzerCCpp::GetSettings()
+//{
+// m_pSettings["MemoryMap"] = m_bMemoryMap ? "yes" : "no";
+// m_pSettings["DebugInfo"] = m_sDebugInfo;
+// m_pSettings["DebugInfoCacheMB"] = to_string(m_nDebugInfoCacheMB);
+// m_pSettings["InstallDebugInfo"] = m_bInstallDebugInfo ? "yes" : "no";
+//
+// return m_pSettings;
+//}
+
+PLUGIN_INFO(ANALYZER,
+ CAnalyzerCCpp,
+ "CCpp",
+ "0.0.1",
+ _("Analyzes crashes in C/C++ programs"),
+ "zprikryl@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ "");
diff --git a/src/plugins/CCpp.h b/src/plugins/CCpp.h
new file mode 100644
index 00000000..e95b4d09
--- /dev/null
+++ b/src/plugins/CCpp.h
@@ -0,0 +1,49 @@
+/*
+ CCpp.h - header file for C/C++ analyzer plugin
+ - it can get UUID and memory maps from core files
+
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef CCPP_H_
+#define CCPP_H_
+
+#include <string>
+#include "plugin.h"
+#include "analyzer.h"
+
+class CAnalyzerCCpp : public CAnalyzer
+{
+ private:
+ bool m_bBacktrace;
+ bool m_bBacktraceRemotes;
+ bool m_bMemoryMap;
+ bool m_bInstallDebugInfo;
+ unsigned m_nDebugInfoCacheMB;
+ unsigned m_nGdbTimeoutSec;
+ std::string m_sOldCorePattern;
+ std::string m_sDebugInfo;
+ std::string m_sDebugInfoDirs;
+
+ public:
+ CAnalyzerCCpp();
+ virtual void Init();
+ virtual void DeInit();
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+};
+
+#endif /* CCPP */
diff --git a/src/plugins/FileTransfer.conf b/src/plugins/FileTransfer.conf
new file mode 100644
index 00000000..111c1c4b
--- /dev/null
+++ b/src/plugins/FileTransfer.conf
@@ -0,0 +1,35 @@
+# Configuration of the FileTransfer reporter plugin.
+Enabled = yes
+
+# The plugin is invoked in the abrt.conf file, usually in the
+# ActionsAndReporters option and/or the [cron] section.
+# There are two modes of invocation:
+#
+# * Specify FileTransfer(one) in ActionsAndReporters directive.
+# Immediately after crash is detected, the plugin transfers
+# crash data to the server specified via URL directive in this file.
+#
+# * Specify FileTransfer(store) in ActionsAndReporters directive
+# and add "HH:MM = FileTransfer" line in [cron] section.
+# At the time of the crash, the plugin stores a record of it
+# in its internal list. When specified time is reached,
+# the plugin iterates through its internal list and sends
+# every recorded crash to the specified URL.
+# After that, the internal list is cleared.
+
+
+# URL to upload the files to
+# supported: ftp, ftps, http, https, scp, sftp, tftp, file
+# for example: ftp://user:password@server.name/directory
+# or: scp://user:password@server.name:port/directory etc.
+# for testing: file:///tmp/test_directory
+URL =
+
+# Archive type, one of .zip, .tar.gz or .tar.bz2
+ArchiveType = .tar.gz
+
+# How many times we try to upload the file
+RetryCount = 3
+
+# How long we wait between we retry the upload (in seconds)
+RetryDelay = 20
diff --git a/src/plugins/FileTransfer.cpp b/src/plugins/FileTransfer.cpp
new file mode 100644
index 00000000..d964bc9d
--- /dev/null
+++ b/src/plugins/FileTransfer.cpp
@@ -0,0 +1,367 @@
+/*
+ FileTransfer.cpp
+
+ Copyright (C) 2009 Daniel Novotny (dnovotny@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+#include <libtar.h>
+#include <bzlib.h>
+#include <zlib.h>
+#include "abrtlib.h"
+#include "abrt_curl.h"
+#include "FileTransfer.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+
+using namespace std;
+
+#define HBLEN 255
+#define FILETRANSFER_DIRLIST DEBUG_DUMPS_DIR "/FileTransferDirlist.txt"
+
+CFileTransfer::CFileTransfer()
+:
+ m_sArchiveType(".tar.gz"),
+ m_nRetryCount(3),
+ m_nRetryDelay(20)
+{
+}
+
+void CFileTransfer::SendFile(const char *pURL, const char *pFilename)
+{
+ int len = strlen(pURL);
+ if (len == 0)
+ {
+ error_msg(_("FileTransfer: URL not specified"));
+ return;
+ }
+
+ update_client(_("Sending archive %s to %s"), pFilename, pURL);
+
+ char *whole_url = concat_path_file(pURL, strrchr(pFilename, '/') ? : pFilename);
+
+ int count = m_nRetryCount;
+ while (1)
+ {
+ FILE *f = fopen(pFilename, "r");
+ if (!f)
+ {
+ free(whole_url);
+ throw CABRTException(EXCEP_PLUGIN, "Can't open archive file '%s'", pFilename);
+ }
+
+ struct stat buf;
+ fstat(fileno(f), &buf); /* never fails */
+
+ CURL *curl = xcurl_easy_init();
+ /* enable uploading */
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+ /* specify target */
+ curl_easy_setopt(curl, CURLOPT_URL, whole_url);
+ /* FILE handle: passed to the default callback, it will fread() it */
+ curl_easy_setopt(curl, CURLOPT_READDATA, f);
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size);
+
+ /* everything is done here; result 0 means success */
+ int result = curl_easy_perform(curl);
+
+ curl_easy_cleanup(curl);
+ fclose(f);
+ if (result == 0 || --count <= 0)
+ break;
+ /* retry the upload if not succesful, wait a bit before next try */
+ sleep(m_nRetryDelay);
+ }
+ free(whole_url);
+}
+
+static void create_tar(const char *archive_name, const char *directory)
+{
+ TAR *tar;
+
+ if (tar_open(&tar, (char *)archive_name, NULL, O_WRONLY | O_CREAT, 0644, TAR_GNU) != 0)
+ {
+ return;
+ }
+ tar_append_tree(tar, (char *)directory, (char*)".");
+ tar_close(tar);
+}
+
+static void create_targz(const char *archive_name, const char *directory)
+{
+ char *name_without_gz = xstrdup(archive_name);
+ strrchr(name_without_gz, '.')[0] = '\0';
+
+ create_tar(name_without_gz, directory);
+
+ int fd = open(name_without_gz, O_RDONLY);
+ if (fd < 0)
+ {
+ remove(name_without_gz);
+ free(name_without_gz);
+ return;
+ }
+
+ gzFile gz = gzopen(archive_name, "w");
+ if (gz == NULL)
+ {
+ close(fd);
+ remove(name_without_gz);
+ free(name_without_gz);
+ return;
+ }
+
+ char buf[BUFSIZ];
+ ssize_t bytesRead;
+ while ((bytesRead = full_read(fd, buf, BUFSIZ)) > 0)
+ {
+ gzwrite(gz, buf, bytesRead); // TODO: check that return value == bytesRead
+ }
+
+ gzclose(gz);
+ close(fd);
+ remove(name_without_gz);
+ free(name_without_gz);
+}
+
+static void create_tarbz2(const char * archive_name, const char * directory)
+{
+ char *name_without_bz2 = xstrdup(archive_name);
+ strrchr(name_without_bz2, '.')[0] = '\0';
+
+ create_tar(name_without_bz2, directory);
+
+ int tarFD = open(name_without_bz2, O_RDONLY);
+ if (tarFD == -1)
+ {
+ remove(name_without_bz2);
+ free(name_without_bz2);
+ return;
+ }
+ FILE *f = fopen(archive_name, "w");
+ if (f == NULL)
+ {
+ close(tarFD);
+ remove(name_without_bz2);
+ free(name_without_bz2);
+ return;
+ }
+ int bzError;
+ BZFILE *bz = BZ2_bzWriteOpen(&bzError, f, /*BLOCK_MULTIPLIER:*/ 7, 0, 0);
+ if (bz == NULL)
+ {
+ fclose(f);
+ close(tarFD);
+ remove(name_without_bz2);
+ free(name_without_bz2);
+ return;
+ }
+
+ char buf[BUFSIZ];
+ ssize_t bytesRead;
+ while ((bytesRead = read(tarFD, buf, BUFSIZ)) > 0)
+ {
+ BZ2_bzWrite(&bzError, bz, buf, bytesRead);
+ }
+
+ BZ2_bzWriteClose(&bzError, bz, 0, NULL, NULL);
+ fclose(f);
+ close(tarFD);
+ remove(name_without_bz2);
+ free(name_without_bz2);
+}
+
+void CFileTransfer::CreateArchive(const char *pArchiveName, const char *pDir)
+{
+ if (m_sArchiveType == ".tar")
+ {
+ create_tar(pArchiveName, pDir);
+ }
+ else if (m_sArchiveType == ".tar.gz")
+ {
+ create_targz(pArchiveName, pDir);
+ }
+ else if (m_sArchiveType == ".tar.bz2")
+ {
+ create_tarbz2(pArchiveName, pDir);
+ }
+ else
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Unknown/unsupported archive type %s", m_sArchiveType.c_str());
+ }
+}
+
+/* Returns the last component of the directory path.
+ * Careful to not return "" on "/path/path2/", but "path2".
+ */
+static string DirBase(const char *pStr)
+{
+ int end = strlen(pStr);
+ if (end > 1 && pStr[end-1] == '/')
+ {
+ end--;
+ }
+ int beg = end;
+ while (beg > 0 && pStr[beg-1] != '/')
+ {
+ beg--;
+ }
+ return string(pStr + beg, end - beg);
+}
+
+void CFileTransfer::Run(const char *pActionDir, const char *pArgs, int force)
+{
+ if (strcmp(pArgs, "store") == 0)
+ {
+ /* Remember pActiveDir for later sending */
+ FILE *dirlist = fopen(FILETRANSFER_DIRLIST, "a");
+ if (!dirlist)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Can't open "FILETRANSFER_DIRLIST);
+ }
+ fprintf(dirlist, "%s\n", pActionDir);
+ fclose(dirlist);
+ VERB3 log("Remembered '%s' for future file transfer", pActionDir);
+ return;
+ }
+
+ update_client(_("FileTransfer: Creating a report..."));
+
+ char hostname[HBLEN];
+ gethostname(hostname, HBLEN-1);
+ hostname[HBLEN-1] = '\0';
+
+ char tmpdir_name[] = "/tmp/abrtuploadXXXXXX";
+ /* mkdtemp does mkdir(xxx, 0700), should be safe (is it?) */
+ if (mkdtemp(tmpdir_name) == NULL)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Can't mkdir a temporary directory in /tmp");
+ }
+
+ if (strcmp(pArgs, "one") == 0)
+ {
+ /* Just send one archive */
+ string archivename = ssprintf("%s/%s-%s%s", tmpdir_name, hostname, DirBase(pActionDir).c_str(), m_sArchiveType.c_str());
+ try
+ {
+ CreateArchive(archivename.c_str(), pActionDir);
+ SendFile(m_sURL.c_str(), archivename.c_str());
+ }
+ catch (CABRTException& e)
+ {
+ error_msg(_("Cannot create and send an archive: %s"), e.what());
+ }
+ unlink(archivename.c_str());
+ }
+ else
+ {
+ /* Tar up and send all remebered directories */
+ FILE *dirlist = fopen(FILETRANSFER_DIRLIST, "r");
+ if (!dirlist)
+ {
+ /* not an error */
+ VERB3 log("No saved crashes to transfer");
+ goto del_tmp_dir;
+ }
+
+ char *dirname;
+ while ((dirname = xmalloc_fgetline(dirlist)) != NULL)
+ {
+ string archivename = ssprintf("%s/%s-%s%s", tmpdir_name, hostname, DirBase(dirname).c_str(), m_sArchiveType.c_str());
+ try
+ {
+ VERB3 log("Creating archive '%s' of dir '%s'", archivename.c_str(), dirname);
+ CreateArchive(archivename.c_str(), dirname);
+ VERB3 log("Sending archive to '%s'", m_sURL.c_str());
+ SendFile(m_sURL.c_str(), archivename.c_str());
+ }
+ catch (CABRTException& e)
+ {
+ error_msg(_("Cannot create and send an archive: %s"), e.what());
+ }
+ VERB3 log("Deleting archive '%s'", archivename.c_str());
+ unlink(archivename.c_str());
+ free(dirname);
+ }
+
+ fclose(dirlist);
+ /* all the files we're able to send should be sent now,
+ starting over with clean table */
+ unlink(FILETRANSFER_DIRLIST);
+ }
+
+ del_tmp_dir:
+ rmdir(tmpdir_name);
+}
+
+void CFileTransfer::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("URL");
+ if (it != end)
+ {
+ m_sURL = it->second;
+ }
+
+ it = pSettings.find("RetryCount");
+ if (it != end)
+ {
+ m_nRetryCount = xatoi_u(it->second.c_str());
+ }
+
+ it = pSettings.find("RetryDelay");
+ if (it != end)
+ {
+ m_nRetryDelay = xatoi_u(it->second.c_str());
+ }
+
+ it = pSettings.find("ArchiveType");
+ if (it != end)
+ {
+ /* currently supporting .tar, .tar.gz, .tar.bz2 and .zip */
+ m_sArchiveType = it->second;
+ if (m_sArchiveType[0] != '.')
+ {
+ m_sArchiveType = "." + m_sArchiveType;
+ }
+ }
+}
+
+//ok to delete?
+//const map_plugin_settings_t& CFileTransfer::GetSettings()
+//{
+// m_pSettings["URL"] = m_sURL;
+// m_pSettings["RetryCount"] = to_string(m_nRetryCount);
+// m_pSettings["RetryDelay"] = to_string(m_nRetryDelay);
+// m_pSettings["ArchiveType"] = m_sArchiveType;
+//
+// return m_pSettings;
+//}
+
+PLUGIN_INFO(ACTION,
+ CFileTransfer,
+ "FileTransfer",
+ "0.0.6",
+ _("Sends a report via FTP or SCTP"),
+ "dnovotny@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ "");
diff --git a/src/plugins/FileTransfer.h b/src/plugins/FileTransfer.h
new file mode 100644
index 00000000..17bebf3d
--- /dev/null
+++ b/src/plugins/FileTransfer.h
@@ -0,0 +1,46 @@
+/*
+ FileTransfer.h - header file for the file transfer plugin
+ - it uploads the file via ftp or sctp
+
+ Copyright (C) 2009 Daniel Novotny (dnovotny@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef FILETRANSFER_H_
+#define FILETRANSFER_H_
+
+#include <string>
+#include "plugin.h"
+#include "action.h"
+
+class CFileTransfer : public CAction
+{
+ private:
+ std::string m_sURL;
+ std::string m_sArchiveType;
+ int m_nRetryCount;
+ int m_nRetryDelay;
+
+ void CreateArchive(const char *pArchiveName, const char *pDir);
+ void SendFile(const char *pURL, const char *pFilename);
+
+ public:
+ CFileTransfer();
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+ virtual void Run(const char *pActionDir, const char *pArgs, int force);
+};
+
+#endif /* FILETRANSFER_H_ */
diff --git a/src/plugins/Kerneloops.conf b/src/plugins/Kerneloops.conf
new file mode 100644
index 00000000..67ad07b9
--- /dev/null
+++ b/src/plugins/Kerneloops.conf
@@ -0,0 +1,13 @@
+Enabled = yes
+
+# Do we want kernel oopses to be visible to any user?
+# Set to "yes" for compatibility with kerneloops.org tool.
+InformAllUsers = yes
+
+# Kerneloops Scanner configuration
+##################################
+SysLogFile = /var/log/messages
+
+# KerneloopsReporter configuration
+##################################
+SubmitURL = http://submit.kerneloops.org/submitoops.php
diff --git a/src/plugins/Kerneloops.cpp b/src/plugins/Kerneloops.cpp
new file mode 100644
index 00000000..37cab992
--- /dev/null
+++ b/src/plugins/Kerneloops.cpp
@@ -0,0 +1,31 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Authors:
+ Anton Arapov <anton@redhat.com>
+ Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "abrtlib.h"
+#include "Kerneloops.h"
+#include "abrt_exception.h"
+
+PLUGIN_INFO(ANALYZER,
+ CAnalyzerKerneloops,
+ "Kerneloops",
+ "0.0.2",
+ _("Analyzes kernel oopses"),
+ "anton@redhat.com",
+ "https://people.redhat.com/aarapov",
+ "");
diff --git a/src/plugins/Kerneloops.h b/src/plugins/Kerneloops.h
new file mode 100644
index 00000000..914f1fc8
--- /dev/null
+++ b/src/plugins/Kerneloops.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007, Intel Corporation
+ * Copyright 2009, Red Hat Inc.
+ *
+ * This file is part of Abrt.
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Anton Arapov <anton@redhat.com>
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_GUARD_KERNELOOPS_H_
+#define __INCLUDE_GUARD_KERNELOOPS_H_
+
+#include "plugin.h"
+#include "analyzer.h"
+#include <string>
+
+class CAnalyzerKerneloops : public CAnalyzer
+{
+};
+
+#endif
diff --git a/src/plugins/KerneloopsReporter.cpp b/src/plugins/KerneloopsReporter.cpp
new file mode 100644
index 00000000..ae459737
--- /dev/null
+++ b/src/plugins/KerneloopsReporter.cpp
@@ -0,0 +1,143 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Authors:
+ Anton Arapov <anton@redhat.com>
+ Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#include "abrtlib.h"
+#include "comm_layer_inner.h"
+#include "abrt_exception.h"
+#include "KerneloopsReporter.h"
+
+using namespace std;
+
+CKerneloopsReporter::CKerneloopsReporter()
+{
+ m_pSettings["SubmitURL"] = "http://submit.kerneloops.org/submitoops.php";
+}
+
+CKerneloopsReporter::~CKerneloopsReporter()
+{
+}
+
+void CKerneloopsReporter::SetSettings(const map_plugin_settings_t& pSettings)
+{
+ /* Can't simply do this:
+
+ m_pSettings = pSettings;
+
+ * - it will erase keys which aren't present in pSettings.
+ * Example: if Bugzilla.conf doesn't have "Login = foo",
+ * then there's no pSettings["Login"] and m_pSettings = pSettings
+ * will nuke default m_pSettings["Login"] = "",
+ * making GUI think that we have no "Login" key at all
+ * and thus never overriding it - even if it *has* an override!
+ */
+
+ map_plugin_settings_t::iterator it = m_pSettings.begin();
+ while (it != m_pSettings.end())
+ {
+ map_plugin_settings_t::const_iterator override = pSettings.find(it->first);
+ if (override != pSettings.end())
+ {
+ VERB3 log(" kerneloops settings[%s]='%s'", it->first.c_str(), it->second.c_str());
+ it->second = override->second;
+ }
+ it++;
+ }
+}
+
+string CKerneloopsReporter::Report(const map_crash_data_t& crash_data,
+ const map_plugin_settings_t& settings,
+ const char *args)
+{
+ /* abrt-action-kerneloops [-s] -c /etc/arbt/Kerneloops.conf -c - -d pCrashData.dir NULL */
+ char *argv[9];
+ char **pp = argv;
+ *pp++ = (char*)"abrt-action-kerneloops";
+
+//We want to consume output, so don't redirect to syslog.
+// if (logmode & LOGMODE_SYSLOG)
+// *pp++ = (char*)"-s";
+//TODO: the actions<->daemon interaction will be changed anyway...
+
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)(PLUGINS_CONF_DIR"/Kerneloops."PLUGINS_CONF_EXTENSION);
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)"-";
+ *pp++ = (char*)"-d";
+ *pp++ = (char*)get_crash_data_item_content_or_NULL(crash_data, CD_DUMPDIR);
+ *pp = NULL;
+ int pipefds[2];
+ pid_t pid = fork_execv_on_steroids(EXECFLG_INPUT + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
+ argv,
+ pipefds,
+ /* unsetenv_vec: */ NULL,
+ /* dir: */ NULL,
+ /* uid(unused): */ 0
+ );
+
+ /* Write the configuration to stdin */
+ map_plugin_settings_t::const_iterator it = settings.begin();
+ while (it != settings.end())
+ {
+ full_write_str(pipefds[1], it->first.c_str());
+ full_write_str(pipefds[1], "=");
+ full_write_str(pipefds[1], it->second.c_str());
+ full_write_str(pipefds[1], "\n");
+ it++;
+ }
+ close(pipefds[1]);
+
+ FILE *fp = fdopen(pipefds[0], "r");
+ if (!fp)
+ die_out_of_memory();
+
+ /* Consume log from stdout */
+ string bug_status;
+ char *buf;
+ while ((buf = xmalloc_fgetline(fp)) != NULL)
+ {
+ if (strncmp(buf, "STATUS:", 7) == 0)
+ bug_status = buf + 7;
+ else
+ if (strncmp(buf, "EXCEPT:", 7) == 0)
+ {
+ CABRTException e(EXCEP_PLUGIN, "%s", buf + 7);
+ free(buf);
+ fclose(fp);
+ waitpid(pid, NULL, 0);
+ throw e;
+ }
+ update_client("%s", buf);
+ free(buf);
+ }
+
+ fclose(fp); /* this also closes pipefds[0] */
+ /* wait for child to actually exit, and prevent leaving a zombie behind */
+ waitpid(pid, NULL, 0);
+
+ return bug_status;
+}
+
+PLUGIN_INFO(REPORTER,
+ CKerneloopsReporter,
+ "KerneloopsReporter",
+ "0.0.1",
+ _("Sends kernel oops information to kerneloops.org"),
+ "anton@redhat.com",
+ "http://people.redhat.com/aarapov",
+ PLUGINS_LIB_DIR"/KerneloopsReporter.glade");
diff --git a/src/plugins/KerneloopsReporter.glade b/src/plugins/KerneloopsReporter.glade
new file mode 100644
index 00000000..1ba287b8
--- /dev/null
+++ b/src/plugins/KerneloopsReporter.glade
@@ -0,0 +1,118 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">12</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="icon_name">abrt</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="lSubmitURL">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Submit URL:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_SubmitURL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Kerneloops Reporter plugin configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button2</action-widget>
+ <action-widget response="-10">button1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/src/plugins/KerneloopsReporter.h b/src/plugins/KerneloopsReporter.h
new file mode 100644
index 00000000..e0f4a1bb
--- /dev/null
+++ b/src/plugins/KerneloopsReporter.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2007, Intel Corporation
+ * Copyright 2009, Red Hat Inc.
+ *
+ * This file is part of Abrt.
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Anton Arapov <anton@redhat.com>
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_GUARD_KERNELOOPSREPORTER_H_
+#define __INCLUDE_GUARD_KERNELOOPSREPORTER_H_
+
+#include "plugin.h"
+#include "reporter.h"
+
+#include <string>
+
+class CKerneloopsReporter : public CReporter
+{
+ public:
+ CKerneloopsReporter();
+ ~CKerneloopsReporter();
+
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+ virtual std::string Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs);
+};
+
+#endif
diff --git a/src/plugins/KerneloopsScanner.cpp b/src/plugins/KerneloopsScanner.cpp
new file mode 100644
index 00000000..d187daa9
--- /dev/null
+++ b/src/plugins/KerneloopsScanner.cpp
@@ -0,0 +1,214 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Authors:
+ Anton Arapov <anton@redhat.com>
+ Arjan van de Ven <arjan@linux.intel.com>
+*/
+#include <syslog.h>
+#include <asm/unistd.h> /* __NR_syslog */
+#include <glib.h>
+#include "abrtlib.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+#include "KerneloopsSysLog.h"
+#include "KerneloopsScanner.h"
+
+// TODO: https://fedorahosted.org/abrt/ticket/78
+
+static int scan_dmesg(GList **oopsList)
+{
+ VERB1 log("Scanning dmesg");
+
+ /* syslog(3) - read the last len bytes from the log buffer
+ * (non-destructively), but dont read more than was written
+ * into the buffer since the last"clear ring buffer" cmd.
+ * Returns the number of bytes read.
+ */
+ char *buffer = (char*)xzalloc(16*1024);
+ syscall(__NR_syslog, 3, buffer, 16*1024 - 1); /* always NUL terminated */
+ int cnt_FoundOopses = extract_oopses(oopsList, buffer, strlen(buffer));
+ free(buffer);
+
+ return cnt_FoundOopses;
+}
+
+
+/* "dumpoops" tool uses these two functions too */
+extern "C" {
+
+int scan_syslog_file(GList **oopsList, const char *filename, time_t *last_changed_p)
+{
+ VERB1 log("Scanning syslog file '%s'", filename);
+
+ char *buffer;
+ struct stat statb;
+ int fd;
+ int cnt_FoundOopses;
+ ssize_t sz;
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ statb.st_size = 0; /* paranoia */
+ if (fstat(fd, &statb) != 0 || statb.st_size < 1)
+ {
+ close(fd);
+ return 0;
+ }
+
+ if (last_changed_p != NULL)
+ {
+ if (*last_changed_p == statb.st_mtime)
+ {
+ VERB1 log("Syslog file '%s' hasn't changed since last scan, skipping", filename);
+ close(fd);
+ return 0;
+ }
+ *last_changed_p = statb.st_mtime;
+ }
+
+ /*
+ * In theory we have 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 10kbytes extra. If there's
+ * more than that.. any oops will be in dmesg anyway.
+ * Do not try to allocate an absurd 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.
+ */
+ sz = statb.st_size + 10*1024;
+ if (statb.st_size > (32*1024*1024 - 10*1024))
+ {
+ xlseek(fd, statb.st_size - (32*1024*1024 - 10*1024), SEEK_SET);
+ sz = 32*1024*1024;
+ }
+ buffer = (char*)xzalloc(sz);
+ sz = full_read(fd, buffer, sz);
+ close(fd);
+
+ cnt_FoundOopses = 0;
+ if (sz > 0)
+ cnt_FoundOopses = extract_oopses(oopsList, buffer, sz);
+ free(buffer);
+
+ return cnt_FoundOopses;
+}
+
+/* returns number of errors */
+int save_oops_to_debug_dump(GList **oopsList)
+{
+ unsigned countdown = 16; /* do not report hundreds of oopses */
+ unsigned idx = g_list_length(*oopsList);
+ time_t t = time(NULL);
+ pid_t my_pid = getpid();
+
+ VERB1 log("Saving %u oopses as crash dump dirs", idx >= countdown ? countdown-1 : idx);
+
+ int errors = 0;
+
+ while (idx != 0 && --countdown != 0)
+ {
+ char path[sizeof(DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu") + 3 * sizeof(long)*3];
+ sprintf(path, DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu-%lu", (long)t, (long)my_pid, (long)idx);
+
+ char *first_line = (char*)g_list_nth_data(*oopsList,--idx);
+ char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
+ *second_line++ = '\0';
+
+ struct dump_dir *dd = dd_create(path, /*uid:*/ 0);
+ if (dd)
+ {
+ dd_save_text(dd, FILENAME_ANALYZER, "Kerneloops");
+ dd_save_text(dd, FILENAME_EXECUTABLE, "kernel");
+ dd_save_text(dd, FILENAME_KERNEL, first_line);
+ dd_save_text(dd, FILENAME_CMDLINE, "not_applicable");
+ dd_save_text(dd, FILENAME_BACKTRACE, second_line);
+ /* Optional, makes generated bz more informative */
+ strchrnul(second_line, '\n')[0] = '\0';
+ dd_save_text(dd, FILENAME_REASON, second_line);
+ dd_close(dd);
+ }
+ else
+ errors++;
+ }
+
+ return errors;
+}
+
+} /* extern "C" */
+
+
+CKerneloopsScanner::CKerneloopsScanner()
+{
+ int cnt_FoundOopses;
+ m_syslog_last_change = 0;
+
+ /* Scan dmesg, on first call only */
+ GList *oopsList = NULL;
+ cnt_FoundOopses = scan_dmesg(&oopsList);
+ if (cnt_FoundOopses > 0)
+ {
+ int errors = save_oops_to_debug_dump(&oopsList);
+ if (errors > 0)
+ log("%d errors while dumping oopses", errors);
+ }
+}
+
+void CKerneloopsScanner::Run(const char *pActionDir, const char *pArgs, int force)
+{
+ const char *syslog_file = "/var/log/messages";
+ map_plugin_settings_t::const_iterator it = m_pSettings.find("SysLogFile");
+ if (it != m_pSettings.end())
+ syslog_file = it->second.c_str();
+
+ GList *oopsList = NULL;
+ int cnt_FoundOopses = scan_syslog_file(&oopsList, syslog_file, &m_syslog_last_change);
+ if (cnt_FoundOopses > 0)
+ {
+ int errors = save_oops_to_debug_dump(&oopsList);
+ if (errors > 0)
+ log("%d errors while dumping oopses", errors);
+ /*
+ * This marker in syslog file prevents us from
+ * re-parsing old oopses (any oops before it is
+ * ignored by scan_syslog_file()). The only problem
+ * is that we can't be sure here that syslog_file
+ * is the file where syslog(xxx) stuff ends up.
+ */
+ openlog("abrt", 0, LOG_KERN);
+ syslog(LOG_WARNING,
+ "Kerneloops: Reported %u kernel oopses to Abrt",
+ cnt_FoundOopses);
+ closelog();
+ }
+
+ for (GList *li = oopsList; li != NULL; li = g_list_next(li))
+ free((char*)li->data);
+ g_list_free(oopsList);
+}
+
+PLUGIN_INFO(ACTION,
+ CKerneloopsScanner,
+ "KerneloopsScanner",
+ "0.0.1",
+ _("Periodically scans for and saves kernel oopses"),
+ "anton@redhat.com",
+ "http://people.redhat.com/aarapov",
+ "");
diff --git a/src/plugins/KerneloopsScanner.h b/src/plugins/KerneloopsScanner.h
new file mode 100644
index 00000000..2bddb0f4
--- /dev/null
+++ b/src/plugins/KerneloopsScanner.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007, Intel Corporation
+ * Copyright 2009, Red Hat Inc.
+ *
+ * This file is part of Abrt.
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Anton Arapov <anton@redhat.com>
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef KERNELOOPSSCANNER_H_
+#define KERNELOOPSSCANNER_H_
+
+#include "abrt_types.h"
+#include "plugin.h"
+#include "action.h"
+
+class CKerneloopsScanner : public CAction
+{
+ private:
+ time_t m_syslog_last_change;
+ public:
+ CKerneloopsScanner();
+ virtual void Run(const char *pActionDir, const char *pArgs, int force);
+};
+
+#endif
diff --git a/src/plugins/KerneloopsSysLog.cpp b/src/plugins/KerneloopsSysLog.cpp
new file mode 100644
index 00000000..68f309bc
--- /dev/null
+++ b/src/plugins/KerneloopsSysLog.cpp
@@ -0,0 +1,383 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Authors:
+ Anton Arapov <anton@redhat.com>
+ Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "abrtlib.h"
+#include "KerneloopsSysLog.h"
+#include <glib.h>
+
+static void queue_oops(GList **vec, const char *data, const char *version)
+{
+ char *ver_data = xasprintf("%s\n%s", version, data);
+ *vec = g_list_append(*vec, ver_data);
+}
+
+/*
+ * extract_version tries to find the kernel version in given data
+ */
+static char *extract_version(const char *linepointer)
+{
+ 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, ' ');
+ return xstrndup(start, end-start);
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * extract_oops tries to find oops signatures in a log
+ */
+struct line_info {
+ char *ptr;
+ char level;
+};
+
+static int record_oops(GList **oopses, struct line_info* lines_info, int oopsstart, int oopsend)
+{
+ int q;
+ int len;
+ char *oops;
+ char *version;
+
+ len = 2;
+ for (q = oopsstart; q <= oopsend; q++)
+ len += strlen(lines_info[q].ptr) + 1;
+
+ oops = (char*)xzalloc(len);
+
+ version = NULL;
+ for (q = oopsstart; q <= oopsend; q++)
+ {
+ if (!version)
+ version = extract_version(lines_info[q].ptr);
+
+ 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 ? version : "undefined");
+ else
+ {
+ VERB3 log("Dropped oops: too short");
+ rv = 0;
+ }
+ free(oops);
+ free(version);
+ return rv;
+}
+#define REALLOC_CHUNK 1000
+int extract_oopses(GList **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++;
+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;
+}
diff --git a/src/plugins/KerneloopsSysLog.h b/src/plugins/KerneloopsSysLog.h
new file mode 100644
index 00000000..d8b4d32b
--- /dev/null
+++ b/src/plugins/KerneloopsSysLog.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2007, Intel Corporation
+ * Copyright 2009, Red Hat Inc.
+ *
+ * This file is part of Abrt.
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Anton Arapov <anton@redhat.com>
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_
+#define __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_
+
+#include "abrt_types.h"
+#include <glib.h>
+
+int extract_oopses(GList **oopses, char *buffer, size_t buflen);
+
+#endif
diff --git a/src/plugins/Logger.conf b/src/plugins/Logger.conf
new file mode 100644
index 00000000..aadd3515
--- /dev/null
+++ b/src/plugins/Logger.conf
@@ -0,0 +1,8 @@
+# Description: Writes report to a file
+
+# Configuration for Logger plugin
+Enabled = yes
+
+LogPath = /var/log/abrt.log
+
+AppendLogs = yes
diff --git a/src/plugins/Logger.glade b/src/plugins/Logger.glade
new file mode 100644
index 00000000..a0a909a4
--- /dev/null
+++ b/src/plugins/Logger.glade
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">12</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="icon_name">abrt</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="lLogPath">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Logger file:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_LogPath">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_AppendLogs">
+ <property name="label" translatable="yes">Append new logs</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Logger plugin configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button2</action-widget>
+ <action-widget response="-10">button1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/src/plugins/Mailx.conf b/src/plugins/Mailx.conf
new file mode 100644
index 00000000..1d946427
--- /dev/null
+++ b/src/plugins/Mailx.conf
@@ -0,0 +1,17 @@
+# Description: Sends an email with a report (using mailx command)
+
+# Configuration to Email reporter plugin
+Enabled = yes
+
+# In abrt.conf, plugin takes one parameter: subject (in "" if you need to embed spaces).
+# If it isn't specified, then a default subject is taken from this file
+Subject = "[abrt] crash report"
+
+# Your Email
+EmailFrom = user@localhost
+
+# Email To
+EmailTo = root@localhost
+
+# Warning! enabling this may cause sending a lot of MB via email
+SendBinaryData = no
diff --git a/src/plugins/Mailx.cpp b/src/plugins/Mailx.cpp
new file mode 100644
index 00000000..255c873d
--- /dev/null
+++ b/src/plugins/Mailx.cpp
@@ -0,0 +1,153 @@
+/*
+ Mailx.cpp
+
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "abrtlib.h"
+#include "Mailx.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+
+#define MAILX_COMMAND "/bin/mailx"
+
+CMailx::CMailx()
+{
+ m_email_from = xstrdup("user@localhost");
+ m_email_to = xstrdup("root@localhost");
+ m_subject = xstrdup("[abrt] full crash report");
+ m_send_binary_data = false;
+}
+
+CMailx::~CMailx()
+{
+ free(m_email_from);
+ free(m_email_to);
+ free(m_subject);
+}
+
+static void exec_and_feed_input(uid_t uid, const char* text, char **args)
+{
+ int pipein[2];
+
+ pid_t child = fork_execv_on_steroids(
+ EXECFLG_INPUT | EXECFLG_QUIET | EXECFLG_SETGUID,
+ args,
+ pipein,
+ /*unsetenv_vec:*/ NULL,
+ /*dir:*/ NULL,
+ uid);
+
+ full_write_str(pipein[1], text);
+ close(pipein[1]);
+
+ waitpid(child, NULL, 0); /* wait for command completion */
+}
+
+static char** append_str_to_vector(char **vec, unsigned &size, const char *str)
+{
+ //log("old vec: %p", vec);
+ vec = (char**) xrealloc(vec, (size+2) * sizeof(vec[0]));
+ vec[size] = xstrdup(str);
+ //log("new vec: %p, added [%d] %p", vec, size, vec[size]);
+ size++;
+ vec[size] = NULL;
+ return vec;
+}
+
+std::string CMailx::Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs)
+{
+ SetSettings(pSettings);
+ char **args = NULL;
+ unsigned arg_size = 0;
+ args = append_str_to_vector(args, arg_size, MAILX_COMMAND);
+
+ char *dsc = make_dsc_mailx(pCrashData);
+
+ map_crash_data_t::const_iterator it;
+ for (it = pCrashData.begin(); it != pCrashData.end(); it++)
+ {
+ if (it->second[CD_TYPE] == CD_BIN && m_send_binary_data)
+ {
+ args = append_str_to_vector(args, arg_size, "-a");
+ args = append_str_to_vector(args, arg_size, it->second[CD_CONTENT].c_str());
+ }
+ }
+
+ args = append_str_to_vector(args, arg_size, "-s");
+ args = append_str_to_vector(args, arg_size, (pArgs[0] != '\0' ? pArgs : m_subject));
+ args = append_str_to_vector(args, arg_size, "-r");
+ args = append_str_to_vector(args, arg_size, m_email_from);
+ args = append_str_to_vector(args, arg_size, m_email_to);
+
+ update_client(_("Sending an email..."));
+ const char *uid_str = get_crash_data_item_content_or_NULL(pCrashData, CD_UID);
+ exec_and_feed_input(xatoi_u(uid_str), dsc, args);
+
+ free(dsc);
+
+ while (*args)
+ {
+ free(*args++);
+ }
+ args -= arg_size;
+ free(args);
+
+ return ssprintf("Email was sent to: %s", m_email_to);
+}
+
+void CMailx::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("Subject");
+ if (it != end)
+ {
+ free(m_subject);
+ m_subject = xstrdup(it->second.c_str());
+ }
+ it = pSettings.find("EmailFrom");
+ if (it != end)
+ {
+ free(m_email_from);
+ m_email_from = xstrdup(it->second.c_str());
+ }
+ it = pSettings.find("EmailTo");
+ if (it != end)
+ {
+ free(m_email_to);
+ m_email_to = xstrdup(it->second.c_str());
+ }
+ it = pSettings.find("SendBinaryData");
+ if (it != end)
+ {
+ m_send_binary_data = string_to_bool(it->second.c_str());
+ }
+}
+
+PLUGIN_INFO(REPORTER,
+ CMailx,
+ "Mailx",
+ "0.0.2",
+ _("Sends an email with a report (via mailx command)"),
+ "zprikryl@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ PLUGINS_LIB_DIR"/Mailx.glade");
diff --git a/src/plugins/Mailx.glade b/src/plugins/Mailx.glade
new file mode 100644
index 00000000..656204b5
--- /dev/null
+++ b/src/plugins/Mailx.glade
@@ -0,0 +1,184 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">12</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="icon_name">abrt</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="lSubject">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Subject:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Subject">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_EmailFrom">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lEmailFrom">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Your Email:</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lEmailTo">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Recipient's Email:</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_EmailTo">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_SendBinaryData">
+ <property name="label" translatable="yes">Send Binary Data</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Mailx plugin configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button2</action-widget>
+ <action-widget response="-10">button1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/src/plugins/Mailx.h b/src/plugins/Mailx.h
new file mode 100644
index 00000000..326a6371
--- /dev/null
+++ b/src/plugins/Mailx.h
@@ -0,0 +1,48 @@
+/*
+ Mailx.h - header file for Mailx reporter plugin
+ - it simple sends an email to specific address via mailx command
+
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef MAILX_H_
+#define MAILX_H_
+
+#include <string>
+#include "plugin.h"
+#include "reporter.h"
+
+class CMailx : public CReporter
+{
+ private:
+ char *m_email_from;
+ char *m_email_to;
+ char *m_subject;
+ bool m_send_binary_data;
+
+ public:
+ CMailx();
+ ~CMailx();
+
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+
+ virtual std::string Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs);
+};
+
+#endif
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
new file mode 100644
index 00000000..2cb85709
--- /dev/null
+++ b/src/plugins/Makefile.am
@@ -0,0 +1,316 @@
+INC_PATH=$(srcdir)/../../inc
+UTILS_PATH=$(srcdir)/../../lib/utils
+AM_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH)
+pluginslibdir=$(PLUGINS_LIB_DIR)
+libexec_SCRIPTS = \
+ abrt-action-install-debuginfo
+
+pluginslib_LTLIBRARIES = \
+ libCCpp.la \
+ libMailx.la \
+ libSQLite3.la \
+ libKerneloopsScanner.la\
+ libKerneloops.la \
+ libKerneloopsReporter.la \
+ libSOSreport.la \
+ libBugzilla.la \
+ libRHTSupport.la \
+ libReportUploader.la \
+ libPython.la \
+ libFileTransfer.la
+
+dist_pluginslib_DATA = \
+ Logger.glade \
+ Mailx.glade \
+ Bugzilla.glade \
+ RHTSupport.glade \
+ ReportUploader.glade \
+ KerneloopsReporter.glade
+
+pluginsconfdir = $(PLUGINS_CONF_DIR)
+dist_pluginsconf_DATA = \
+ CCpp.conf \
+ Mailx.conf \
+ SQLite3.conf \
+ Logger.conf \
+ Kerneloops.conf \
+ Bugzilla.conf \
+ RHTSupport.conf \
+ ReportUploader.conf \
+ FileTransfer.conf \
+ Python.conf \
+ SOSreport.conf
+
+man_MANS = \
+ abrt-FileTransfer.7 \
+ abrt-Bugzilla.7 \
+ abrt-KerneloopsScanner.7 \
+ abrt-KerneloopsReporter.7 \
+ abrt-Logger.7 \
+ abrt-Mailx.7 \
+ abrt-plugins.7 \
+ abrt-SQLite3.7 \
+ abrt-ReportUploader.7
+
+EXTRA_DIST = $(man_MANS) abrt-action-install-debuginfo
+
+$(DESTDIR)/$(DEBUG_INFO_DIR):
+ $(mkdir_p) '$@'
+
+install-data-hook: $(DESTDIR)/$(DEBUG_INFO_DIR)
+ sed 's: = /var/: = $(localstatedir)/:g' -i \
+ $(DESTDIR)$(sysconfdir)/abrt/plugins/SQLite3.conf \
+ $(DESTDIR)$(sysconfdir)/abrt/plugins/Logger.conf
+
+# CCpp
+libCCpp_la_SOURCES = CCpp.cpp CCpp.h
+libCCpp_la_LDFLAGS = -avoid-version
+libCCpp_la_CPPFLAGS = -Wall -Werror \
+ -I$(INC_PATH) -I$(UTILS_PATH) \
+ -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"'
+# -DHOSTILE_KERNEL
+
+# Kerneloops
+libKerneloops_la_SOURCES = Kerneloops.cpp Kerneloops.h
+libKerneloops_la_LDFLAGS = -avoid-version
+libKerneloops_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH)
+
+# KerneloopsReporter
+libKerneloopsReporter_la_SOURCES = KerneloopsReporter.cpp KerneloopsReporter.h
+libKerneloopsReporter_la_LDFLAGS = -avoid-version
+libKerneloopsReporter_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\"
+
+# KerneloopsScanner
+libKerneloopsScanner_la_SOURCES = KerneloopsScanner.cpp KerneloopsScanner.h KerneloopsSysLog.cpp KerneloopsSysLog.h
+libKerneloopsScanner_la_LDFLAGS = -avoid-version $(GLIB_LIBS)
+libKerneloopsScanner_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" $(GLIB_CFLAGS)
+
+# Mailx
+libMailx_la_SOURCES = Mailx.cpp Mailx.h
+libMailx_la_LDFLAGS = -avoid-version
+libMailx_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" -DLOCALSTATEDIR='"$(localstatedir)"'
+
+# SQLite3
+libSQLite3_la_SOURCES = SQLite3.cpp SQLite3.h
+libSQLite3_la_LDFLAGS = -avoid-version
+libSQLite3_la_LIBADD = $(SQLITE3_LIBS) $(GLIB_LIBS)
+libSQLite3_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) $(SQLITE3_CFLAGS) -DLOCALSTATEDIR='"$(localstatedir)"' $(GLIB_CFLAGS)
+
+# SOSreport
+libSOSreport_la_SOURCES = SOSreport.cpp SOSreport.h
+libSOSreport_la_LDFLAGS = -avoid-version
+
+# Bugzilla
+libBugzilla_la_SOURCES = Bugzilla.h Bugzilla.cpp
+libBugzilla_la_LIBADD =
+libBugzilla_la_LDFLAGS = -avoid-version
+libBugzilla_la_CPPFLAGS = \
+ -I$(INC_PATH) -I$(UTILS_PATH) \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\"
+
+# RHTSupport
+libRHTSupport_la_SOURCES = RHTSupport.h RHTSupport.cpp
+libRHTSupport_la_LIBADD =
+libRHTSupport_la_LDFLAGS = -avoid-version
+libRHTSupport_la_CPPFLAGS = \
+ -I$(INC_PATH) -I$(UTILS_PATH) \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"'
+
+# ReportUploader
+libReportUploader_la_SOURCES = ReportUploader.h ReportUploader.cpp
+libReportUploader_la_LDFLAGS = -avoid-version
+libReportUploader_la_LIBADD = $(CURL_LIBS)
+libReportUploader_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) $(CURL_CFLAGS) -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\"
+
+# Python
+libPython_la_SOURCES = Python.h Python.cpp
+#libPython_la_LIBADD = $(NSS_LIBS)
+libPython_la_LDFLAGS = -avoid-version
+libPython_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH)
+
+# FileTrasfer
+libFileTransfer_la_SOURCES = FileTransfer.cpp FileTransfer.h
+libFileTransfer_la_LDFLAGS = -avoid-version -ltar -lbz2 -lz
+libFileTransfer_la_LIBADD = $(CURL_LIBS)
+libFileTransfer_la_CPPFLAGS = -I$(INC_PATH) -I$(UTILS_PATH) $(CURL_CFLAGS) -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\"
+
+libexec_PROGRAMS = \
+ abrt-action-analyze-c \
+ abrt-action-analyze-python \
+ abrt-action-analyze-oops \
+ abrt-action-generate-backtrace \
+ abrt-action-bugzilla \
+ abrt-action-rhtsupport \
+ abrt-action-kerneloops \
+ abrt-action-print
+
+abrt_action_analyze_c_SOURCES = \
+ abrt-action-analyze-c.c
+abrt_action_analyze_c_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_analyze_c_LDADD = \
+ ../../lib/utils/libABRTUtils.la
+
+abrt_action_analyze_python_SOURCES = \
+ abrt-action-analyze-python.c
+abrt_action_analyze_python_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_analyze_python_LDADD = \
+ ../../lib/utils/libABRTUtils.la
+
+abrt_action_analyze_oops_SOURCES = \
+ abrt-action-analyze-oops.c
+abrt_action_analyze_oops_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_analyze_oops_LDADD = \
+ ../../lib/utils/libABRTUtils.la
+
+abrt_action_generate_backtrace_SOURCES = \
+ abrt-action-generate-backtrace.c
+abrt_action_generate_backtrace_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_generate_backtrace_LDADD = \
+ ../../lib/utils/libABRTUtils.la \
+ ../btparser/libbtparser.la
+
+abrt_action_bugzilla_SOURCES = \
+ abrt-action-bugzilla.cpp
+abrt_action_bugzilla_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ $(GLIB_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_bugzilla_LDADD = \
+ $(GLIB_LIBS) \
+ ../../lib/utils/libABRT_web_utils.la \
+ ../../lib/utils/libABRTdUtils.la \
+ ../../lib/utils/libABRTUtils.la
+
+abrt_action_rhtsupport_SOURCES = \
+ abrt_rh_support.h abrt_rh_support.c \
+ abrt-action-rhtsupport.cpp
+abrt_action_rhtsupport_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ $(GLIB_CFLAGS) \
+ $(XMLRPC_CFLAGS) $(XMLRPC_CLIENT_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_action_rhtsupport_LDFLAGS = -ltar
+abrt_action_rhtsupport_LDADD = \
+ $(GLIB_LIBS) \
+ $(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS) \
+ ../../lib/utils/libABRT_web_utils.la \
+ ../../lib/utils/libABRTdUtils.la \
+ ../../lib/utils/libABRTUtils.la
+
+abrt_action_kerneloops_SOURCES = \
+ abrt-action-kerneloops.cpp
+abrt_action_kerneloops_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ $(GLIB_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+# libABRTdUtils is used only because of LoadPluginSettings:
+abrt_action_kerneloops_LDADD = \
+ ../../lib/utils/libABRT_web_utils.la \
+ ../../lib/utils/libABRTdUtils.la \
+ ../../lib/utils/libABRTUtils.la
+
+abrt_action_print_SOURCES = \
+ abrt-action-print.cpp
+abrt_action_print_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ $(GLIB_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+# libABRTdUtils is used only because of make_description_logger:
+abrt_action_print_LDADD = \
+ ../../lib/utils/libABRTdUtils.la \
+ ../../lib/utils/libABRTUtils.la
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
diff --git a/src/plugins/Python.conf b/src/plugins/Python.conf
new file mode 100644
index 00000000..3201c6da
--- /dev/null
+++ b/src/plugins/Python.conf
@@ -0,0 +1 @@
+Enabled = yes
diff --git a/src/plugins/Python.cpp b/src/plugins/Python.cpp
new file mode 100644
index 00000000..e955b5fb
--- /dev/null
+++ b/src/plugins/Python.cpp
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "abrtlib.h"
+#include "Python.h"
+#include "abrt_exception.h"
+
+PLUGIN_INFO(ANALYZER,
+ CAnalyzerPython,
+ "Python",
+ "0.0.1",
+ _("Analyzes crashes in Python programs"),
+ "zprikryl@redhat.com, jmoskovc@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ "");
diff --git a/src/plugins/Python.h b/src/plugins/Python.h
new file mode 100644
index 00000000..3f01d2c6
--- /dev/null
+++ b/src/plugins/Python.h
@@ -0,0 +1,30 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef PYTHON_H_
+#define PYTHON_H_
+
+#include <string>
+#include "plugin.h"
+#include "analyzer.h"
+
+class CAnalyzerPython : public CAnalyzer
+{
+};
+
+#endif /* PYTHON_H_ */
diff --git a/src/plugins/RHTSupport.conf b/src/plugins/RHTSupport.conf
new file mode 100644
index 00000000..ecd5992a
--- /dev/null
+++ b/src/plugins/RHTSupport.conf
@@ -0,0 +1,11 @@
+# Description: Reports crashes to Red Hat support
+
+Enabled = yes
+
+URL = https://api.access.redhat.com/rs
+# No means that ssl certificates will not be checked
+SSLVerify = yes
+# Your login has to exist
+Login =
+# Your password
+Password =
diff --git a/src/plugins/RHTSupport.cpp b/src/plugins/RHTSupport.cpp
new file mode 100644
index 00000000..3732afe3
--- /dev/null
+++ b/src/plugins/RHTSupport.cpp
@@ -0,0 +1,147 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "abrtlib.h"
+#include "crash_types.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+#include "RHTSupport.h"
+
+using namespace std;
+
+CReporterRHticket::CReporterRHticket()
+{
+ m_pSettings["URL"] = "https://api.access.redhat.com/rs";
+ m_pSettings["Login"] = "";
+ m_pSettings["Password"] = "";
+ m_pSettings["SSLVerify"] = "yes";
+}
+
+CReporterRHticket::~CReporterRHticket()
+{
+}
+
+void CReporterRHticket::SetSettings(const map_plugin_settings_t& pSettings)
+{
+ /* Can't simply do this:
+
+ m_pSettings = pSettings;
+
+ * - it will erase keys which aren't present in pSettings.
+ * Example: if Bugzilla.conf doesn't have "Login = foo",
+ * then there's no pSettings["Login"] and m_pSettings = pSettings
+ * will nuke default m_pSettings["Login"] = "",
+ * making GUI think that we have no "Login" key at all
+ * and thus never overriding it - even if it *has* an override!
+ */
+
+ map_plugin_settings_t::iterator it = m_pSettings.begin();
+ while (it != m_pSettings.end())
+ {
+ map_plugin_settings_t::const_iterator override = pSettings.find(it->first);
+ if (override != pSettings.end())
+ {
+ VERB3 log(" rhtsupport settings[%s]='%s'", it->first.c_str(), it->second.c_str());
+ it->second = override->second;
+ }
+ it++;
+ }
+}
+
+string CReporterRHticket::Report(const map_crash_data_t& crash_data,
+ const map_plugin_settings_t& settings,
+ const char *args)
+{
+ /* abrt-action-rhtsupport [-s] -c /etc/arbt/RHTSupport.conf -c - -d pCrashData.dir NULL */
+ char *argv[9];
+ char **pp = argv;
+ *pp++ = (char*)"abrt-action-rhtsupport";
+
+//We want to consume output, so don't redirect to syslog.
+// if (logmode & LOGMODE_SYSLOG)
+// *pp++ = (char*)"-s";
+//TODO: the actions<->daemon interaction will be changed anyway...
+
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)(PLUGINS_CONF_DIR"/RHTSupport."PLUGINS_CONF_EXTENSION);
+ *pp++ = (char*)"-c";
+ *pp++ = (char*)"-";
+ *pp++ = (char*)"-d";
+ *pp++ = (char*)get_crash_data_item_content_or_NULL(crash_data, CD_DUMPDIR);
+ *pp = NULL;
+ int pipefds[2];
+ pid_t pid = fork_execv_on_steroids(EXECFLG_INPUT + EXECFLG_OUTPUT + EXECFLG_ERR2OUT,
+ argv,
+ pipefds,
+ /* unsetenv_vec: */ NULL,
+ /* dir: */ NULL,
+ /* uid(unused): */ 0
+ );
+
+ /* Write the configuration to stdin */
+ map_plugin_settings_t::const_iterator it = settings.begin();
+ while (it != settings.end())
+ {
+ full_write_str(pipefds[1], it->first.c_str());
+ full_write_str(pipefds[1], "=");
+ full_write_str(pipefds[1], it->second.c_str());
+ full_write_str(pipefds[1], "\n");
+ it++;
+ }
+ close(pipefds[1]);
+
+ FILE *fp = fdopen(pipefds[0], "r");
+ if (!fp)
+ die_out_of_memory();
+
+ /* Consume log from stdout */
+ string bug_status;
+ char *buf;
+ while ((buf = xmalloc_fgetline(fp)) != NULL)
+ {
+ if (strncmp(buf, "STATUS:", 7) == 0)
+ bug_status = buf + 7;
+ else
+ if (strncmp(buf, "EXCEPT:", 7) == 0)
+ {
+ CABRTException e(EXCEP_PLUGIN, "%s", buf + 7);
+ free(buf);
+ fclose(fp);
+ waitpid(pid, NULL, 0);
+ throw e;
+ }
+ update_client("%s", buf);
+ free(buf);
+ }
+
+ fclose(fp); /* this also closes pipefds[0] */
+ /* wait for child to actually exit, and prevent leaving a zombie behind */
+ waitpid(pid, NULL, 0);
+
+ return bug_status;
+}
+
+PLUGIN_INFO(REPORTER,
+ CReporterRHticket,
+ "RHticket",
+ "0.0.4",
+ _("Reports bugs to Red Hat support"),
+ "Denys Vlasenko <dvlasenk@redhat.com>",
+ "https://fedorahosted.org/abrt/wiki",
+ PLUGINS_LIB_DIR"/RHTSupport.glade");
diff --git a/src/plugins/RHTSupport.glade b/src/plugins/RHTSupport.glade
new file mode 100644
index 00000000..64fd6c26
--- /dev/null
+++ b/src/plugins/RHTSupport.glade
@@ -0,0 +1,213 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">12</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="icon_name">abrt</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="lURL">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">RHTSupport URL:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lLogin">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Login:</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lPassword">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password:</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_URL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Login">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cb_Password">
+ <property name="label" translatable="yes">Show password</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_SSLVerify">
+ <property name="label" translatable="yes">SSL verify</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;RHTSupport plugin configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="bApply">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button2</action-widget>
+ <action-widget response="-10">bApply</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAction" id="action1"/>
+</interface>
diff --git a/src/plugins/RHTSupport.h b/src/plugins/RHTSupport.h
new file mode 100644
index 00000000..2338732f
--- /dev/null
+++ b/src/plugins/RHTSupport.h
@@ -0,0 +1,38 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat Inc
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef RHTICKET_H_
+#define RHTICKET_H_
+
+#include "plugin.h"
+#include "reporter.h"
+
+class CReporterRHticket: public CReporter
+{
+ public:
+ CReporterRHticket();
+ virtual ~CReporterRHticket();
+
+ virtual std::string Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs);
+
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+};
+
+#endif
diff --git a/src/plugins/ReportUploader.conf b/src/plugins/ReportUploader.conf
new file mode 100644
index 00000000..7a7b9133
--- /dev/null
+++ b/src/plugins/ReportUploader.conf
@@ -0,0 +1,23 @@
+# Description: Packs crash data into .tar.gz file, optionally uploads it via FTP/SCP/etc
+
+Enabled = yes
+
+# Customer = "Example Inc."
+# Ticket = IT12345
+# Encrypt = yes
+# If set to "no" or commented out,
+# compressed ticket data will be copied to /tmp:
+# Upload = yes
+
+# If "Upload = yes", URL to upload the files to.
+# supported: ftp, ftps, http, https, scp, sftp, tftp, file
+# for example: ftp://user:password@server.name/directory
+# or: scp://user:password@server.name:port/directory etc.
+# for testing: file:///tmp/test_directory
+# URL =
+
+# How many times we try to upload the file
+# RetryCount = 3
+
+# How long we wait between we retry the upload (in seconds)
+# RetryDelay = 20
diff --git a/src/plugins/ReportUploader.cpp b/src/plugins/ReportUploader.cpp
new file mode 100644
index 00000000..4100e996
--- /dev/null
+++ b/src/plugins/ReportUploader.cpp
@@ -0,0 +1,517 @@
+/*
+ ReportUploader.cpp
+
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "abrtlib.h"
+#include "abrt_curl.h"
+#include "ReportUploader.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+
+using namespace std;
+
+
+CReportUploader::CReportUploader() :
+ m_bEncrypt(false),
+ m_bUpload(false),
+ m_nRetryCount(3),
+ m_nRetryDelay(20)
+{}
+
+CReportUploader::~CReportUploader()
+{}
+
+
+static void RunCommand(const char *cmd)
+{
+ int retcode = system(cmd);
+ if (retcode)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "'%s' exited with %d", cmd, retcode);
+ }
+}
+
+static string ReadCommand(const char *cmd)
+{
+ FILE* fp = popen(cmd, "r");
+ if (!fp)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", cmd);
+ }
+
+ string result;
+ char *buff;
+ while ((buff = xmalloc_fgetline(fp)) != NULL)
+ {
+ result += buff;
+ free(buff);
+ }
+
+ int retcode = pclose(fp);
+ if (retcode)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "'%s' exited with %d", cmd, retcode);
+ }
+
+ return result;
+}
+
+static void WriteCommand(const char *cmd, const char *input)
+{
+ FILE* fp = popen(cmd, "w");
+ if (!fp)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "error running '%s'", cmd);
+ }
+
+ /* Hoping it's not too big to get us forever blocked... */
+ fputs(input, fp);
+
+ int retcode = pclose(fp);
+ if (retcode)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "'%s' exited with %d", cmd, retcode);
+ }
+}
+
+void CReportUploader::SendFile(const char *pURL, const char *pFilename, int retry_count, int retry_delay)
+{
+ if (pURL[0] == '\0')
+ {
+ error_msg(_("FileTransfer: URL not specified"));
+ return;
+ }
+
+ update_client(_("Sending archive %s to %s"), pFilename, pURL);
+
+ const char *base = (strrchr(pFilename, '/') ? : pFilename-1) + 1;
+ char *whole_url = concat_path_file(pURL, base);
+ int count = retry_count;
+ int result;
+ while (1)
+ {
+ FILE* f = fopen(pFilename, "r");
+ if (!f)
+ {
+ free(whole_url);
+ throw CABRTException(EXCEP_PLUGIN, "Can't open archive file '%s'", pFilename);
+ }
+ struct stat buf;
+ fstat(fileno(f), &buf); /* never fails */
+ CURL* curl = xcurl_easy_init();
+ /* enable uploading */
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+ /* specify target */
+ curl_easy_setopt(curl, CURLOPT_URL, whole_url);
+ curl_easy_setopt(curl, CURLOPT_READDATA, f);
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size);
+ /* everything is done here; result 0 means success */
+ result = curl_easy_perform(curl);
+ /* goodbye */
+ curl_easy_cleanup(curl);
+ fclose(f);
+ if (result != 0)
+ {
+ update_client(_("Sending failed, trying again. %s"), curl_easy_strerror((CURLcode)result));
+ }
+ if (result == 0 || --count <= 0)
+ break;
+ /* retry the upload if not succesful, wait a bit before next try */
+ sleep(retry_delay);
+ }
+ free(whole_url);
+
+ if (count <= 0 && result != 0)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Curl can not send a ticket");
+ }
+}
+
+
+static void write_str_to_file(const char *str, const char *path, const char *fname)
+{
+ char *ofile_name = concat_path_file(path, fname);
+ FILE *ofile = fopen(ofile_name, "w");
+ if (!ofile)
+ {
+ CABRTException e(EXCEP_PLUGIN, "Can't open '%s'", ofile_name);
+ free(ofile_name);
+ throw e;
+ }
+ free(ofile_name);
+ fputs(str, ofile);
+ fclose(ofile);
+}
+
+string CReportUploader::Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs)
+{
+ string customer_name;
+ string ticket_name;
+ string upload_url;
+ bool do_encrypt;
+ bool do_upload;
+ int retry_count;
+ int retry_delay;
+
+ /* if parse_settings fails it returns an empty map so we need to use defaults */
+ map_plugin_settings_t settings = parse_settings(pSettings);
+ // Get ticket name, customer name, and do_encrypt from config settings
+ if (!settings.empty())
+ {
+ customer_name = settings["Customer"];
+ ticket_name = settings["Ticket"];
+ upload_url = settings["URL"];
+ do_encrypt = string_to_bool(settings["Encrypt"].c_str());
+ do_upload = string_to_bool(settings["Upload"].c_str());
+ retry_count = xatoi_u(settings["RetryCount"].c_str());
+ retry_delay = xatoi_u(settings["RetryDelay"].c_str());
+ }
+ else
+ {
+ customer_name = m_sCustomer;
+ ticket_name = m_sTicket;
+ upload_url = m_sURL;
+ do_encrypt = m_bEncrypt;
+ do_upload = m_bUpload;
+ retry_count = m_nRetryCount;
+ retry_delay = m_nRetryDelay;
+ }
+ update_client(_("Creating a ReportUploader report..."));
+
+ bool have_ticket_name = (ticket_name != "");
+ if (!have_ticket_name)
+ {
+ ticket_name = "ReportUploader-newticket";
+ }
+
+ // Format the time to add to the file name
+ char timebuf[256];
+ time_t curtime = time(NULL);
+ strftime(timebuf, sizeof(timebuf), "-%Y%m%d%H%M%S", gmtime(&curtime));
+
+ // Create a tmp work directory, and within that
+ // create the "<ticketname>-yyyymmddhhmmss" directory
+ // which will be the root of the tarball
+ string file_name = ticket_name + timebuf;
+
+ char tmpdir_name[] = "/tmp/abrtuploadXXXXXX";
+ if (mkdtemp(tmpdir_name) == NULL)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Can't mkdir a temporary directory in /tmp");
+ }
+
+ char *tmptar_name = concat_path_file(tmpdir_name, file_name.c_str());
+ if (mkdir(tmptar_name, 0700))
+ {
+ CABRTException e(EXCEP_PLUGIN, "Can't mkdir '%s'", tmptar_name);
+ free(tmptar_name);
+ throw e;
+ }
+
+ // Copy each entry into the tarball root.
+ // Files are simply copied, strings are written to a file
+ // TODO: some files are totally useless:
+ // "Reported", "Message" (plugin's output), "DumpDir",
+ // "Description" (package description) - maybe skip those?
+ map_crash_data_t::const_iterator it;
+ for (it = pCrashData.begin(); it != pCrashData.end(); it++)
+ {
+ const char *content = it->second[CD_CONTENT].c_str();
+ if (it->second[CD_TYPE] == CD_TXT)
+ {
+ write_str_to_file(content, tmptar_name, it->first.c_str());
+ }
+ else if (it->second[CD_TYPE] == CD_BIN)
+ {
+ char *ofile_name = concat_path_file(tmptar_name, it->first.c_str());
+ if (copy_file(content, ofile_name, 0644) < 0)
+ {
+ CABRTException e(EXCEP_PLUGIN,
+ "Can't copy '%s' to '%s'",
+ content, ofile_name
+ );
+ free(tmptar_name);
+ free(ofile_name);
+ throw e;
+ }
+ free(ofile_name);
+ }
+ }
+
+ // add ticket_name and customer name to tarball
+ if (have_ticket_name)
+ {
+ write_str_to_file(ticket_name.c_str(), tmptar_name, "TICKET");
+ }
+ if (customer_name != "")
+ {
+ write_str_to_file(customer_name.c_str(), tmptar_name, "CUSTOMER");
+ }
+
+ // Create the compressed tarball
+ string outfile_basename = file_name + ".tar.gz";
+ char *outfile_name = concat_path_file(tmpdir_name, outfile_basename.c_str());
+ string cmd = ssprintf("tar -C %s --create --gzip --file=%s %s", tmpdir_name, outfile_name, file_name.c_str());
+ RunCommand(cmd.c_str());
+
+ // encrypt if requested
+ string key;
+ if (do_encrypt)
+ {
+ key = ReadCommand("openssl rand -base64 48");
+
+ string infile_name = outfile_name;
+ outfile_basename += ".aes";
+ outfile_name = append_to_malloced_string(outfile_name, ".aes");
+
+ cmd = ssprintf("openssl aes-128-cbc -in %s -out %s -pass stdin", infile_name.c_str(), outfile_name);
+ WriteCommand(cmd.c_str(), key.c_str());
+ }
+
+ // generate md5sum
+ cmd = ssprintf("cd %s; md5sum <%s", tmpdir_name, outfile_basename.c_str());
+ string md5sum = ReadCommand(cmd.c_str());
+
+ // upload or cp to /tmp
+ if (do_upload)
+ {
+ // FIXME: SendFile isn't working sometime (scp)
+ SendFile(upload_url.c_str(), outfile_name, retry_count, retry_delay);
+ }
+ else
+ {
+ cmd = ssprintf("cp %s /tmp/", outfile_name);
+ RunCommand(cmd.c_str());
+ }
+
+ // generate a reciept telling md5sum and encryption key
+ // note: do not internationalize these strings!
+ string msg;
+ if (have_ticket_name)
+ {
+ msg += "Please copy this into ticket: ";
+ msg += ticket_name;
+ msg += '\n';
+ msg += "========cut here========\n";
+ }
+ else
+ {
+ msg += "Please send this to your technical support:\n";
+ msg += "========cut here========\n";
+ }
+ if (do_upload)
+ {
+ msg += "RHUPLOAD: This report was sent to ";
+ msg += upload_url;
+ msg += '\n';
+ }
+ else
+ {
+ msg += "RHUPLOAD: This report was copied into /tmp/:\n";
+ }
+ if (have_ticket_name)
+ {
+ msg += "TICKET: ";
+ msg += ticket_name;
+ msg += '\n';
+ }
+ msg += "FILE: ";
+ msg += outfile_basename;
+ msg += "\nMD5SUM: ";
+ msg += md5sum;
+ msg += '\n';
+ if (do_encrypt)
+ {
+ msg += "KEY: aes-128-cbc\n";
+ msg += key;
+ msg += '\n';
+ }
+ msg += "==========end===========\n";
+
+ // warn the client (why _warn_? it's not an error, maybe update_client?):
+ //error_msg("%s", msg.c_str());
+
+ // delete the temporary directory
+ cmd = ssprintf("rm -rf %s", tmpdir_name);
+ RunCommand(cmd.c_str());
+
+ free(tmptar_name);
+ free(outfile_name);
+
+ return msg;
+}
+
+static bool is_string_safe(const char *str)
+{
+ const char *p = str;
+ while (*p)
+ {
+ unsigned char c = *p;
+ if ((c < '0' || c > '9')
+ && c != '_'
+ && c != '-'
+ ) {
+ c |= 0x20; // tolower
+ if (c < 'a' || c > 'z')
+ {
+ return false;
+ }
+ }
+ // only 0-9, -, _, A-Z, a-z reach this point
+ p++;
+ }
+ return true;
+}
+
+void CReportUploader::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("Customer");
+ if (it != end)
+ {
+ m_sCustomer = it->second;
+ }
+ // We use m_sTicket as part of filename,
+ // and we use resulting filename in system("cd %s; ...", filename) etc,
+ // so we are very paraniod about allowed chars
+ it = pSettings.find("Ticket");
+ if (it != end && is_string_safe(it->second.c_str()))
+ {
+ m_sTicket = it->second;
+ }
+ it = pSettings.find("URL");
+ if (it != end)
+ {
+ m_sURL = it->second;
+ }
+ it = pSettings.find("Encrypt");
+ if (it != end)
+ {
+ m_bEncrypt = string_to_bool(it->second.c_str());
+ }
+ it = pSettings.find("Upload");
+ if (it != end)
+ {
+ m_bUpload = string_to_bool(it->second.c_str());
+ }
+ it = pSettings.find("RetryCount");
+ if (it != end)
+ {
+ m_nRetryCount = xatoi_u(it->second.c_str());
+ }
+ it = pSettings.find("RetryDelay");
+ if (it != end)
+ {
+ m_nRetryDelay = xatoi_u(it->second.c_str());
+ }
+}
+
+const map_plugin_settings_t& CReportUploader::GetSettings()
+{
+ m_pSettings["Customer"] = m_sCustomer;
+ m_pSettings["Ticket"] = m_sTicket;
+ m_pSettings["URL"] = m_sURL;
+ m_pSettings["Encrypt"] = m_bEncrypt ? "yes" : "no";
+ m_pSettings["Upload"] = m_bUpload ? "yes" : "no";
+ m_pSettings["RetryCount"] = to_string(m_nRetryCount);
+ m_pSettings["RetryDelay"] = to_string(m_nRetryDelay);
+
+ return m_pSettings;
+}
+
+//todo: make static
+map_plugin_settings_t CReportUploader::parse_settings(const map_plugin_settings_t& pSettings)
+{
+ map_plugin_settings_t plugin_settings;
+
+ map_plugin_settings_t::const_iterator end = pSettings.end();
+ map_plugin_settings_t::const_iterator it;
+
+ it = pSettings.find("Customer");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["Customer"] = it->second;
+
+ it = pSettings.find("Ticket");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["Ticket"] = it->second;
+
+ it = pSettings.find("URL");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["URL"] = it->second;
+
+ it = pSettings.find("Encrypt");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["Encrypt"] = it->second;
+
+ it = pSettings.find("Upload");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["Upload"] = it->second;
+
+ it = pSettings.find("RetryCount");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["RetryCount"] = it->second;
+
+ it = pSettings.find("RetryDelay");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["RetryDelay"] = it->second;
+
+ VERB1 log("User settings ok, using them instead of defaults");
+ return plugin_settings;
+}
+
+PLUGIN_INFO(REPORTER,
+ CReportUploader,
+ "ReportUploader",
+ "0.0.1",
+ _("Packs crash data into .tar.gz file, optionally uploads it via FTP/SCP/etc"),
+ "gavin@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ PLUGINS_LIB_DIR"/ReportUploader.glade");
diff --git a/src/plugins/ReportUploader.glade b/src/plugins/ReportUploader.glade
new file mode 100644
index 00000000..c2bbd470
--- /dev/null
+++ b/src/plugins/ReportUploader.glade
@@ -0,0 +1,249 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">5</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="icon_name">abrt</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">7</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Customer:</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Ticket:</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">URL:</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Customer">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Ticket">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_URL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Retry count:</property>
+ </object>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_RetryCount">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Retry delay:</property>
+ </object>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_RetryDelay">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_Encrypt">
+ <property name="label" translatable="yes">Use encryption</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_Upload">
+ <property name="label" translatable="yes">Upload</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Report Uploader plugin configuration&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="bApply">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">button2</action-widget>
+ <action-widget response="-10">bApply</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAction" id="action1"/>
+</interface>
diff --git a/src/plugins/ReportUploader.h b/src/plugins/ReportUploader.h
new file mode 100644
index 00000000..4ff780b8
--- /dev/null
+++ b/src/plugins/ReportUploader.h
@@ -0,0 +1,55 @@
+/*
+ ReportUploader.h
+
+ Attach a configureable Ticket Number and Customer name to a report.
+ Create a compressed, optionally encrypted, tarball.
+ Upload tarball to configureable URL.
+
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef REPORTUPLOADER_H_
+#define REPORTUPLAODER_H_
+
+#include "plugin.h"
+#include "reporter.h"
+
+class CReportUploader : public CReporter
+{
+ private:
+ std::string m_sCustomer;
+ std::string m_sTicket;
+ std::string m_sURL;
+ bool m_bEncrypt;
+ bool m_bUpload;
+ int m_nRetryCount;
+ int m_nRetryDelay;
+
+ void SendFile(const char *pURL, const char *pFilename, int retry_count, int retry_delay);
+ map_plugin_settings_t parse_settings(const map_plugin_settings_t& pSettings);
+
+ public:
+ CReportUploader();
+ virtual ~CReportUploader();
+ virtual const map_plugin_settings_t& GetSettings();
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+
+ virtual std::string Report(const map_crash_data_t& pCrashData,
+ const map_plugin_settings_t& pSettings,
+ const char *pArgs);
+};
+
+#endif
diff --git a/src/plugins/SOSreport.conf b/src/plugins/SOSreport.conf
new file mode 100644
index 00000000..3201c6da
--- /dev/null
+++ b/src/plugins/SOSreport.conf
@@ -0,0 +1 @@
+Enabled = yes
diff --git a/src/plugins/SOSreport.cpp b/src/plugins/SOSreport.cpp
new file mode 100644
index 00000000..36a768fd
--- /dev/null
+++ b/src/plugins/SOSreport.cpp
@@ -0,0 +1,169 @@
+/*
+ SOSreport.cpp
+
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "abrtlib.h"
+#include "abrt_exception.h"
+#include "SOSreport.h"
+#include "abrt_exception.h"
+#include "comm_layer_inner.h"
+
+using namespace std;
+
+static char *ParseFilename(char *p)
+{
+ /*
+ the sosreport's filename is embedded in sosreport's output.
+ It appears on the line after the string in 'sosreport_filename_marker',
+ it has leading spaces, and a trailing newline. This function trims
+ any leading and trailing whitespace from the filename.
+ */
+ static const char sosreport_filename_marker[] =
+ "Your sosreport has been generated and saved in:";
+
+ p = strstr(p, sosreport_filename_marker);
+ if (!p)
+ return p;
+ p = skip_whitespace(p + sizeof(sosreport_filename_marker)-1);
+ char *end = strchrnul(p, '\n');
+ while (end > p && isspace(*end))
+ *end-- = '\0';
+ return p[0] == '/' ? p : NULL;
+}
+
+void CActionSOSreport::Run(const char *pActionDir, const char *pArgs, int force)
+{
+ if (!force)
+ {
+ struct dump_dir *dd = dd_opendir(pActionDir, /*flags:*/ 0);
+ if (!dd)
+ return;
+
+ bool bt_exists = dd_exist(dd, "sosreport.tar.bz2") || dd_exist(dd, "sosreport.tar.xz");
+ if (bt_exists)
+ {
+ VERB3 log("%s already exists, not regenerating", "sosreport.tar.bz2");
+ return;
+ }
+ dd_close(dd);
+ }
+
+ static const char command_default[] =
+ "cd -- '%s' || exit 1;"
+ "nice sosreport --tmp-dir . --batch"
+ " --only=anaconda --only=bootloader"
+ " --only=devicemapper --only=filesys --only=hardware --only=kernel"
+ " --only=libraries --only=memory --only=networking --only=nfsserver"
+ " --only=pam --only=process --only=rpm -k rpm.rpmva=off --only=ssh"
+ " --only=startup --only=yum 2>&1;"
+ "rm sosreport*.md5 2>/dev/null;"
+ "mv sosreport*.tar.bz2 sosreport.tar.bz2 2>/dev/null;"
+ "mv sosreport*.tar.xz sosreport.tar.xz 2>/dev/null;"
+ ;
+ static const char command_prefix[] =
+ "cd -- '%s' || exit 1;"
+ "nice sosreport --tmp-dir . --batch %s 2>&1;"
+ "rm sosreport*.md5 2>/dev/null;"
+ "mv sosreport*.tar.bz2 sosreport.tar.bz2 2>/dev/null;"
+ "mv sosreport*.tar.xz sosreport.tar.xz 2>/dev/null;"
+ ;
+ string command;
+
+ vector_string_t args;
+ parse_args(pArgs, args, '"');
+
+ if (args.size() == 0 || args[0] == "")
+ {
+ command = ssprintf(command_default, pActionDir);
+ }
+ else
+ {
+ command = ssprintf(command_prefix, pActionDir, args[0].c_str());
+ }
+
+ update_client(_("Running sosreport: %s"), command.c_str());
+ string output = command;
+ output += '\n';
+ char *command_out = run_in_shell_and_save_output(/*flags:*/ 0, command.c_str(), /*dir:*/ NULL, /*size_p:*/ NULL);
+ output += command_out;
+ update_client(_("Finished running sosreport"));
+ VERB3 log("sosreport output:'%s'", output.c_str());
+
+// Not needed: now we use "sosreport --tmp-dir DUMPDIR"
+#if 0
+ // Parse:
+ // "Your sosreport has been generated and saved in:
+ // /tmp/sosreport-XXXX.tar.bz2"
+ // Note: ParseFilename modifies its parameter and returns pointer
+ // which points somewhere inside it.
+ char *sosreport_filename = xstrdup(ParseFilename(command_out));
+ free(command_out);
+ if (!sosreport_filename)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "Can't find filename in sosreport output");
+ }
+
+ char *sosreport_dd_filename = concat_path_file(pActionDir, "sosreport.tar");
+ char *ext = strrchr(sosreport_filename, '.');
+ if (ext && strcmp(ext, ".tar") != 0)
+ {
+ // Assuming it's .bz2, .gz or some such
+ sosreport_dd_filename = append_to_malloced_string(sosreport_dd_filename, ext);
+ }
+
+ CDebugDump dd;
+ if (!dd.Open(pActionDir))
+ {
+ VERB1 log(_("Unable to open debug dump '%s'"), pDebugDumpDir);
+ free(sosreport_filename);
+ free(sosreport_dd_filename);
+ return;
+ }
+ //Not useful: dd.SaveText("sosreportoutput", output);
+ off_t sz = copy_file(sosreport_filename, sosreport_dd_filename, 0644);
+
+ // don't want to leave sosreport-XXXX.tar.bz2 in /tmp
+ unlink(sosreport_filename);
+ // sosreport-XXXX.tar.bz2.md5 too
+ sosreport_filename = append_to_malloced_string(sosreport_filename, ".md5");
+ unlink(sosreport_filename);
+
+ dd.Close();
+ if (sz < 0)
+ {
+ CABRTException e(EXCEP_PLUGIN,
+ "Can't copy '%s' to '%s'",
+ sosreport_filename, sosreport_dd_filename
+ );
+ free(sosreport_filename);
+ free(sosreport_dd_filename);
+ throw e;
+ }
+ free(sosreport_filename);
+ free(sosreport_dd_filename);
+#endif
+}
+
+PLUGIN_INFO(ACTION,
+ CActionSOSreport,
+ "SOSreport",
+ "0.0.2",
+ _("Runs sosreport, saves the output"),
+ "gavin@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ "");
diff --git a/src/plugins/SOSreport.h b/src/plugins/SOSreport.h
new file mode 100644
index 00000000..4b32940f
--- /dev/null
+++ b/src/plugins/SOSreport.h
@@ -0,0 +1,31 @@
+/*
+ SOSreport.h - Attach an sosreport to a crash dump
+
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SOSREPORT_H_
+#define SOSREPORT_H_
+
+#include "action.h"
+
+class CActionSOSreport : public CAction
+{
+ public:
+ virtual void Run(const char *pActionDir, const char *pArgs, int force);
+};
+
+#endif
diff --git a/src/plugins/SQLite3.conf b/src/plugins/SQLite3.conf
new file mode 100644
index 00000000..a7617a90
--- /dev/null
+++ b/src/plugins/SQLite3.conf
@@ -0,0 +1,4 @@
+# Configuration file for database plugin SQLite3
+
+# DB path
+DBPath = /var/spool/abrt/abrt-db
diff --git a/src/plugins/SQLite3.cpp b/src/plugins/SQLite3.cpp
new file mode 100644
index 00000000..2ed3f9fd
--- /dev/null
+++ b/src/plugins/SQLite3.cpp
@@ -0,0 +1,742 @@
+/*
+ SQLite3.cpp
+
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include <sqlite3.h>
+#include "abrtlib.h"
+#include "SQLite3.h"
+
+using namespace std;
+
+#define ABRT_TABLE_VERSION 4
+#define ABRT_TABLE_VERSION_STR "4"
+#define ABRT_TABLE "abrt_v"ABRT_TABLE_VERSION_STR
+#define ABRT_REPRESULT_TABLE "abrt_v"ABRT_TABLE_VERSION_STR"_reportresult"
+#define SQLITE3_MASTER_TABLE "sqlite_master"
+
+#define COL_UID "UID"
+#define COL_UUID "UUID"
+#define COL_INFORMALL "InformAll"
+#define COL_DEBUG_DUMP_PATH "DebugDumpPath"
+#define COL_COUNT "Count"
+#define COL_REPORTED "Reported"
+#define COL_TIME "Time"
+#define COL_MESSAGE "Message"
+
+#define COL_REPORTER "Reporter"
+
+#define NUM_COL 8
+
+/* Is this string safe wrt SQL injection?
+ * PHP's mysql_real_escape_string() treats \, ', ", \x00, \n, \r, and \x1a as special.
+ * We are a bit more paranoid and disallow any control chars.
+ */
+static bool is_string_safe(const char *str)
+{
+// Apparently SQLite allows unescaped newlines. More surprisingly,
+// it does not unescape escaped ones - I see lines ending with \ when I do it.
+// I wonder whether this is a bug in SQLite, and whether using unescaped
+// newlines is a danger with other SQL servers.
+// For now, I disabled newline escaping, and also allowed double quote.
+ const char *p = str;
+ while (*p)
+ {
+ unsigned char c = *p;
+// if (c == '\\' && p[1] != '\0')
+// {
+// p += 2;
+// continue;
+// }
+ if ((c < ' ' && c != '\n')
+ || strchr("\\\'", c) //was: "\\\"\'"
+ ) {
+ error_msg("Probable SQL injection: '%s'", str);
+ return false;
+ }
+ p++;
+ }
+ return true;
+}
+
+#ifdef UNUSED_FOR_NOW
+/* Escape \n */
+static string sql_escape(const char *str)
+{
+ const char *s = str;
+ unsigned len = 0;
+ do
+ {
+ if (*s == '\n')
+ len++;
+ len++;
+ } while (*s++);
+
+ char buf[len];
+ s = str;
+ char *d = buf;
+ do
+ {
+ if (*s == '\n')
+ *d++ = '\\';
+ *d++ = *s;
+ } while (*s++);
+
+ return buf;
+}
+#endif
+
+/* Note:
+ * expects "SELECT * FROM ...", not "SELECT <only some fields> FROM ..."
+ */
+static GList *vget_table(sqlite3 *db, const char *fmt, va_list p)
+{
+ char *sql = xvasprintf(fmt, p);
+
+ char **table;
+ int ncol, nrow;
+ char *err = NULL;
+ int ret = sqlite3_get_table(db, sql, &table, &nrow, &ncol, &err);
+ if (ret != SQLITE_OK)
+ {
+ error_msg("Error in SQL:'%s' error: %s", sql, err);
+ free(sql);
+ sqlite3_free(err);
+ return (GList*)ERR_PTR;
+ }
+ VERB2 log("%s: %d rows returned by SQL:%s", __func__, nrow, sql);
+ free(sql);
+
+ if (nrow > 0 && ncol < NUM_COL)
+ error_msg_and_die("Unexpected number of columns: %d", ncol);
+
+ GList *rows = NULL;
+ int ii;
+ for (ii = 0; ii < nrow; ii++)
+ {
+ int jj;
+ struct db_row *row = (struct db_row*)xzalloc(sizeof(struct db_row));
+ for (jj = 0; jj < ncol; jj++)
+ {
+ char *val = table[jj + (ncol*ii) + ncol];
+ switch (jj)
+ {
+ case 0: row->db_uuid = xstrdup(val); break;
+ case 1: row->db_uid = xstrdup(val); break;
+ case 2: row->db_inform_all = xstrdup(val); break;
+ case 3: row->db_dump_dir = xstrdup(val); break;
+ case 4: row->db_count = xstrdup(val); break;
+ case 5: row->db_reported = xstrdup(val); break;
+ case 6: row->db_time = xstrdup(val); break;
+ case 7: row->db_message = xstrdup(val); break;
+ }
+ }
+
+ VERB3 log("%s: row->db_uuid = '%s'", __func__, row->db_uuid);
+ VERB3 log("%s: row->db_uid = '%s'", __func__, row->db_uid);
+ VERB3 log("%s: row->db_inform_all = '%s'", __func__, row->db_inform_all);
+ VERB3 log("%s: row->db_dump_dir = '%s'", __func__, row->db_dump_dir);
+ VERB3 log("%s: row->db_count = '%s'", __func__, row->db_count);
+ VERB3 log("%s: row->db_reported = '%s'", __func__, row->db_reported);
+ VERB3 log("%s: row->db_time = '%s'", __func__, row->db_time);
+ VERB3 log("%s: row->db_message = '%s'", __func__, row->db_message);
+ rows = g_list_append(rows, row);
+
+ }
+ sqlite3_free_table(table);
+
+ return rows;
+}
+
+static GList *get_table_or_die(sqlite3 *db, const char *fmt, ...)
+{
+ va_list p;
+ va_start(p, fmt);
+ GList *table = vget_table(db, fmt, p);
+ va_end(p);
+
+ if (table == (GList*)ERR_PTR)
+ xfunc_die();
+
+ return table;
+}
+
+static int vexecute_sql(sqlite3 *db, const char *fmt, va_list p)
+{
+ char *sql = xvasprintf(fmt, p);
+
+ char *err = NULL;
+ int ret = sqlite3_exec(db, sql, /*callback:*/ NULL, /*callback param:*/ NULL, &err);
+ if (ret != SQLITE_OK)
+ {
+ error_msg("Error in SQL:'%s' error: %s", sql, err);
+ free(sql);
+ sqlite3_free(err);
+ return -1;
+ }
+ int affected = sqlite3_changes(db);
+ VERB2 log("%d rows affected by SQL:%s", affected, sql);
+ free(sql);
+
+ return affected;
+}
+
+static int execute_sql_or_die(sqlite3 *db, const char *fmt, ...)
+{
+ va_list p;
+ va_start(p, fmt);
+ int ret = vexecute_sql(db, fmt, p);
+ va_end(p);
+
+ if (ret < 0)
+ xfunc_die();
+
+ return ret;
+}
+
+static bool exists_uuid_uid(sqlite3 *db, const char *UUID, const char *UID)
+{
+ GList *table = get_table_or_die(db, "SELECT * FROM "ABRT_TABLE
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ UUID, UID
+ );
+
+ if (!table)
+ return false;
+
+ db_list_free(table);
+
+ return true;
+}
+
+static void update_from_old_ver(sqlite3 *db, int old_version)
+{
+ static const char *const update_sql_commands[] = {
+ // v0 -> v1
+ NULL,
+ // v1 -> v2
+ "BEGIN TRANSACTION;"
+ "CREATE TABLE abrt_v2 ("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_DEBUG_DUMP_PATH" VARCHAR NOT NULL,"
+ COL_COUNT" INT NOT NULL DEFAULT 1,"
+ COL_REPORTED" INT NOT NULL DEFAULT 0,"
+ COL_TIME" VARCHAR NOT NULL DEFAULT 0,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID"));"
+ "INSERT INTO abrt_v2 "
+ "SELECT "COL_UUID","
+ COL_UID","
+ COL_DEBUG_DUMP_PATH","
+ COL_COUNT","
+ COL_REPORTED","
+ COL_TIME","
+ COL_MESSAGE
+ " FROM abrt;"
+ "DROP TABLE abrt;"
+ "COMMIT;",
+ // v2 -> v3
+ "BEGIN TRANSACTION;"
+ "CREATE TABLE abrt_v3 ("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_DEBUG_DUMP_PATH" VARCHAR NOT NULL,"
+ COL_COUNT" INT NOT NULL DEFAULT 1,"
+ COL_REPORTED" INT NOT NULL DEFAULT 0,"
+ COL_TIME" VARCHAR NOT NULL DEFAULT 0,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID"));"
+ "INSERT INTO abrt_v3 "
+ "SELECT "COL_UUID","
+ COL_UID","
+ COL_DEBUG_DUMP_PATH","
+ COL_COUNT","
+ COL_REPORTED","
+ COL_TIME","
+ COL_MESSAGE
+ " FROM abrt_v2;"
+ "DROP TABLE abrt_v2;"
+ "CREATE TABLE abrt_v3_reportresult ("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_REPORTER" VARCHAR NOT NULL,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID","COL_REPORTER"));"
+ "COMMIT;",
+ // v3-> v4
+ "BEGIN TRANSACTION;"
+ "CREATE TABLE abrt_v4("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_INFORMALL" INT NOT NULL DEFAULT 0,"
+ COL_DEBUG_DUMP_PATH" VARCHAR NOT NULL,"
+ COL_COUNT" INT NOT NULL DEFAULT 1,"
+ COL_REPORTED" INT NOT NULL DEFAULT 0,"
+ COL_TIME" VARCHAR NOT NULL DEFAULT 0,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID"));"
+ "INSERT INTO abrt_v4 "
+ "SELECT "COL_UUID","
+ COL_UID","
+ "0," /* COL_INFORMALL */
+ COL_DEBUG_DUMP_PATH","
+ COL_COUNT","
+ COL_REPORTED","
+ COL_TIME","
+ COL_MESSAGE
+ " FROM abrt_v3;"
+ "DROP TABLE abrt_v3;"
+ "UPDATE abrt_v4"
+ " SET "COL_UID"='0', "COL_INFORMALL"=1"
+ " WHERE "COL_UID"='-1';"
+ "CREATE TABLE abrt_v4_reportresult ("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_REPORTER" VARCHAR NOT NULL,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID","COL_REPORTER"));"
+ "INSERT INTO abrt_v4_reportresult "
+ "SELECT * FROM abrt_v3_reportresult;"
+ "DROP TABLE abrt_v3_reportresult;"
+ "COMMIT;",
+ };
+
+ while (old_version < ABRT_TABLE_VERSION)
+ {
+ execute_sql_or_die(db, update_sql_commands[old_version]);
+ old_version++;
+ }
+}
+
+static bool check_table(sqlite3 *db)
+{
+ const char *command = "SELECT NAME FROM "SQLITE3_MASTER_TABLE" "
+ "WHERE TYPE='table' AND NAME like 'abrt_v%';";
+ char **table;
+ int ncol, nrow;
+ char *err;
+ int ret = sqlite3_get_table(db, command, &table, &nrow, &ncol, &err);
+ if (ret != SQLITE_OK)
+ {
+ /* Should never happen */
+ error_msg_and_die("SQLite3 database is corrupted");
+ }
+ if (!nrow)
+ {
+ sqlite3_free_table(table);
+ return false;
+ }
+
+ // table format:
+ // table[0]:"NAME" // table[1]:"SQL" <== field names from SELECT
+ // table[2]:"abrt_vNN" // table[3]:"sql"
+ char *tableName = table[0 + ncol];
+ char *underscore = strchr(tableName, '_');
+ if (underscore)
+ {
+ // It can be "abrt_vNN_something", thus using atoi(), not xatoi()
+ int tableVersion = atoi(underscore + 2);
+ sqlite3_free_table(table);
+ if (tableVersion < ABRT_TABLE_VERSION)
+ {
+ update_from_old_ver(db, tableVersion);
+ }
+ return true;
+ }
+ sqlite3_free_table(table);
+ update_from_old_ver(db, 1);
+ return true;
+}
+
+
+CSQLite3::CSQLite3() :
+ m_sDBPath(LOCALSTATEDIR "/spool/abrt/abrt-db"),
+ m_pDB(NULL)
+{}
+
+CSQLite3::~CSQLite3()
+{
+ /* Paranoia. In C++, destructor will abort() if it was called while unwinding
+ * the stack and it throws an exception.
+ */
+ try
+ {
+ DisConnect();
+ m_sDBPath.clear();
+ }
+ catch (...)
+ {
+ error_msg_and_die("Internal error");
+ }
+}
+
+void CSQLite3::DisConnect()
+{
+ if (m_pDB)
+ {
+ sqlite3_close(m_pDB);
+ m_pDB = NULL;
+ }
+}
+
+void CSQLite3::Connect()
+{
+ int ret = sqlite3_open_v2(m_sDBPath.c_str(),
+ &m_pDB,
+ SQLITE_OPEN_READWRITE,
+ NULL
+ );
+
+ if (ret != SQLITE_OK)
+ {
+ if (ret != SQLITE_CANTOPEN)
+ {
+ error_msg_and_die("Can't open database '%s': %s", m_sDBPath.c_str(), sqlite3_errmsg(m_pDB));
+ }
+
+ ret = sqlite3_open_v2(m_sDBPath.c_str(),
+ &m_pDB,
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
+ NULL
+ );
+ if (ret != SQLITE_OK)
+ {
+ error_msg_and_die("Can't create database '%s': %s", m_sDBPath.c_str(), sqlite3_errmsg(m_pDB));
+ }
+ }
+
+ if (!check_table(m_pDB))
+ {
+ execute_sql_or_die(m_pDB,
+ "CREATE TABLE "ABRT_TABLE" ("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_INFORMALL" INT NOT NULL DEFAULT 0,"
+ COL_DEBUG_DUMP_PATH" VARCHAR NOT NULL,"
+ COL_COUNT" INT NOT NULL DEFAULT 1,"
+ COL_REPORTED" INT NOT NULL DEFAULT 0,"
+ COL_TIME" VARCHAR NOT NULL DEFAULT 0,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID"));"
+ );
+ execute_sql_or_die(m_pDB,
+ "CREATE TABLE "ABRT_REPRESULT_TABLE" ("
+ COL_UUID" VARCHAR NOT NULL,"
+ COL_UID" VARCHAR NOT NULL,"
+ COL_REPORTER" VARCHAR NOT NULL,"
+ COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
+ "PRIMARY KEY ("COL_UUID","COL_UID","COL_REPORTER"));"
+ );
+ }
+}
+
+void CSQLite3::Insert_or_Update(const char *crash_id,
+ bool inform_all_users,
+ const char *pDebugDumpPath,
+ const char *pTime)
+{
+ const char *UUID = strchr(crash_id, ':');
+ if (!UUID
+ || !is_string_safe(crash_id)
+ || !is_string_safe(pDebugDumpPath)
+ || !is_string_safe(pTime)
+ ) {
+ return;
+ }
+
+ /* Split crash_id into UID:UUID */
+ unsigned uid_len = UUID - crash_id;
+ UUID++;
+ char UID[uid_len + 1];
+ strncpy(UID, crash_id, uid_len);
+ UID[uid_len] = '\0';
+
+ if (!exists_uuid_uid(m_pDB, UUID, UID))
+ {
+ execute_sql_or_die(m_pDB,
+ "INSERT INTO "ABRT_TABLE" ("
+ COL_UUID","
+ COL_UID","
+ COL_INFORMALL","
+ COL_DEBUG_DUMP_PATH","
+ COL_TIME
+ ")"
+ " VALUES ('%s','%s',%u,'%s','%s');",
+ UUID, UID, (unsigned)inform_all_users, pDebugDumpPath, pTime
+ );
+ }
+ else
+ {
+ execute_sql_or_die(m_pDB,
+ "UPDATE "ABRT_TABLE
+ " SET "COL_COUNT"="COL_COUNT"+1,"COL_TIME"='%s'"
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ pTime,
+ UUID, UID
+ );
+ }
+}
+
+void CSQLite3::DeleteRow(const char *crash_id)
+{
+ const char *UUID = strchr(crash_id, ':');
+ if (!UUID
+ || !is_string_safe(crash_id)
+ ) {
+ return;
+ }
+
+ /* Split crash_id into UID:UUID */
+ unsigned uid_len = UUID - crash_id;
+ UUID++;
+ char UID[uid_len + 1];
+ strncpy(UID, crash_id, uid_len);
+ UID[uid_len] = '\0';
+
+ if (exists_uuid_uid(m_pDB, UUID, UID))
+ {
+ execute_sql_or_die(m_pDB, "DELETE FROM "ABRT_TABLE
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ UUID, UID
+ );
+ execute_sql_or_die(m_pDB, "DELETE FROM "ABRT_REPRESULT_TABLE
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ UUID, UID
+ );
+ }
+ else
+ {
+ error_msg("crash_id %s is not found in DB", crash_id);
+ }
+}
+
+void CSQLite3::DeleteRows_by_dir(const char *dump_dir)
+{
+ if (!is_string_safe(dump_dir))
+ {
+ return;
+ }
+
+ /* Get UID:UUID pair(s) to delete */
+ GList *table = get_table_or_die(m_pDB, "SELECT * FROM "ABRT_TABLE
+ " WHERE "COL_DEBUG_DUMP_PATH"='%s';",
+ dump_dir
+ );
+
+ if (!table)
+ {
+ return;
+ }
+
+ struct db_row *row = NULL;
+ /* Delete from both tables */
+ for (GList *li = table; li != NULL; li = g_list_next(li))
+ {
+ row = (struct db_row*)li->data;
+ execute_sql_or_die(m_pDB,
+ "DELETE FROM "ABRT_REPRESULT_TABLE
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ row->db_uuid, row->db_uid
+ );
+ }
+ execute_sql_or_die(m_pDB,
+ "DELETE FROM "ABRT_TABLE
+ " WHERE "COL_DEBUG_DUMP_PATH"='%s'",
+ dump_dir
+ );
+}
+
+void CSQLite3::SetReported(const char *crash_id, const char *pMessage)
+{
+ const char *UUID = strchr(crash_id, ':');
+ if (!UUID
+ || !is_string_safe(crash_id)
+ || !is_string_safe(pMessage)
+ ) {
+ return;
+ }
+
+ /* Split crash_id into UID:UUID */
+ unsigned uid_len = UUID - crash_id;
+ UUID++;
+ char UID[uid_len + 1];
+ strncpy(UID, crash_id, uid_len);
+ UID[uid_len] = '\0';
+
+ if (exists_uuid_uid(m_pDB, UUID, UID))
+ {
+ execute_sql_or_die(m_pDB,
+ "UPDATE "ABRT_TABLE
+ " SET "COL_REPORTED"=1"
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ UUID, UID
+ );
+ execute_sql_or_die(m_pDB,
+ "UPDATE "ABRT_TABLE
+ " SET "COL_MESSAGE"='%s'"
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ pMessage, UUID, UID
+ );
+ }
+ else
+ {
+ error_msg("crash_id %s is not found in DB", crash_id);
+ }
+}
+
+void CSQLite3::SetReportedPerReporter(const char *crash_id,
+ const char *reporter,
+ const char *pMessage)
+{
+ const char *UUID = strchr(crash_id, ':');
+ if (!UUID
+ || !is_string_safe(crash_id)
+ || !is_string_safe(reporter)
+ || !is_string_safe(pMessage)
+ ) {
+ return;
+ }
+
+ /* Split crash_id into UID:UUID */
+ unsigned uid_len = UUID - crash_id;
+ UUID++;
+ char UID[uid_len + 1];
+ strncpy(UID, crash_id, uid_len);
+ UID[uid_len] = '\0';
+
+ int affected_rows = execute_sql_or_die(m_pDB,
+ "UPDATE "ABRT_REPRESULT_TABLE
+ " SET "COL_MESSAGE"='%s'"
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s' AND "COL_REPORTER"='%s'",
+ pMessage,
+ UUID, UID, reporter
+ );
+ if (!affected_rows)
+ {
+ execute_sql_or_die(m_pDB,
+ "INSERT INTO "ABRT_REPRESULT_TABLE
+ " ("COL_UUID","COL_UID","COL_REPORTER","COL_MESSAGE")"
+ " VALUES ('%s','%s','%s','%s');",
+ UUID, UID, reporter, pMessage
+ );
+ }
+}
+
+GList *CSQLite3::GetUIDData(long caller_uid)
+{
+ GList *table = NULL;
+
+ if (caller_uid == 0)
+ {
+ table = get_table_or_die(m_pDB, "SELECT * FROM "ABRT_TABLE";");
+ }
+ else
+ {
+ table = get_table_or_die(m_pDB, "SELECT * FROM "ABRT_TABLE
+ " WHERE "COL_UID"='%ld' OR "COL_INFORMALL"=1;",
+ caller_uid
+ );
+ }
+ return table;
+}
+
+struct db_row *CSQLite3::GetRow(const char *crash_id)
+{
+ const char *UUID = strchr(crash_id, ':');
+ if (!UUID
+ || !is_string_safe(crash_id)
+ ) {
+ return NULL;
+ }
+
+ /* Split crash_id into UID:UUID */
+ unsigned uid_len = UUID - crash_id;
+ UUID++;
+ char UID[uid_len + 1];
+ strncpy(UID, crash_id, uid_len);
+ UID[uid_len] = '\0';
+
+ GList *table = get_table_or_die(m_pDB, "SELECT * FROM "ABRT_TABLE
+ " WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
+ UUID, UID
+ );
+
+ if (!table)
+ {
+ return NULL;
+ }
+
+ GList *first = g_list_first(table);
+ struct db_row *row = db_rowcpy_from_list(first);
+
+ db_list_free(table);
+
+ return row;
+}
+
+struct db_row *CSQLite3::GetRow_by_dir(const char *dir)
+{
+ if (!is_string_safe(dir))
+ return NULL;
+
+ GList *table = get_table_or_die(m_pDB, "SELECT * FROM "ABRT_TABLE
+ " WHERE "COL_DEBUG_DUMP_PATH"='%s';",
+ dir
+ );
+
+ if (!table)
+ return NULL;
+
+ GList *first = g_list_first(table);
+ struct db_row *row = db_rowcpy_from_list(first);
+
+ db_list_free(table);
+
+ return row;
+}
+
+void CSQLite3::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("DBPath");
+ if (it != end)
+ {
+ m_sDBPath = it->second;
+ }
+}
+
+//ok to delete?
+//const map_plugin_settings_t& CSQLite3::GetSettings()
+//{
+// m_pSettings["DBPath"] = m_sDBPath;
+//
+// return m_pSettings;
+//}
+
+PLUGIN_INFO(DATABASE,
+ CSQLite3,
+ "SQLite3",
+ "0.0.2",
+ _("Keeps SQLite3 database about all crashes"),
+ "zprikryl@redhat.com,jmoskovc@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ "");
diff --git a/src/plugins/SQLite3.h b/src/plugins/SQLite3.h
new file mode 100644
index 00000000..5750d92e
--- /dev/null
+++ b/src/plugins/SQLite3.h
@@ -0,0 +1,58 @@
+/*
+ SQLite3.h
+
+ Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
+ Copyright (C) 2009 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#ifndef SQLITE3_H_
+#define SQLITE3_H_
+
+#include "plugin.h"
+#include "database.h"
+
+class CSQLite3 : public CDatabase
+{
+ private:
+ std::string m_sDBPath;
+ sqlite3* m_pDB;
+
+ public:
+ CSQLite3();
+ ~CSQLite3();
+
+ virtual void Connect();
+ virtual void DisConnect();
+
+ virtual void Insert_or_Update(const char *crash_id,
+ bool inform_all_users,
+ const char *pDebugDumpPath,
+ const char *pTime);
+ virtual void DeleteRow(const char *crash_id);
+ virtual void DeleteRows_by_dir(const char *dump_dir);
+ virtual void SetReported(const char *crash_id, const char *pMessage);
+ virtual void SetReportedPerReporter(const char *crash_id,
+ const char *reporter,
+ const char *pMessage);
+ virtual GList *GetUIDData(long caller_uid);
+ virtual struct db_row *GetRow(const char *crash_id);
+ virtual struct db_row *GetRow_by_dir(const char *dir);
+
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+};
+
+
+#endif
diff --git a/src/plugins/abrt-Bugzilla.7 b/src/plugins/abrt-Bugzilla.7
new file mode 100644
index 00000000..99bb60d1
--- /dev/null
+++ b/src/plugins/abrt-Bugzilla.7
@@ -0,0 +1,43 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+Bugzilla plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fIBugzilla\fP plugin
+for \fIabrt\fP.
+.P
+This plugin is used to report the crash to a Bugzilla instance. The
+plugin will determine the package name and distribution version. The
+crash data is attached to the bug report.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file.
+No parameters are necessary.
+.SH CONFIGURATION
+The \fIBugzilla.conf\fP configuration file contains several
+entries in the format "Option = Value". The options are:
+.SS BugzillaURL
+The URL of the Bugzilla instance that you want to use, including the
+path to the xmlrpc. The default is https://bugzilla.redhat.com/xmlrpc.cgi
+.SS Login
+Your Bugzilla login. If you have no Bugzilla account, you cannot
+use the plugin.
+.SS Password
+Your Bugzilla password.
+.SH EXAMPLES
+.P
+This is a snippet from the \fIabrt.conf\fP configuration file.
+When something crashes, use the Bugzilla plugin:
+.P
+[common]
+.br
+ActionsAndReporters = Bugzilla
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Zdenek Prikryl <zprikryl@redhat.com>.
+Manual page written by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/plugins/abrt-FileTransfer.7 b/src/plugins/abrt-FileTransfer.7
new file mode 100644
index 00000000..a721dd81
--- /dev/null
+++ b/src/plugins/abrt-FileTransfer.7
@@ -0,0 +1,72 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+FileTransfer plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fIFileTransfer\fP plugin
+for \fIabrt\fP.
+.P
+This plugin is used to transfer the crash report to another
+machine using a file transfer protocol. The protocols supported
+are FTP, FTPS, HTTP, HTTPS, SCP, SFTP, and TFTP.
+.SH INVOCATION
+.P
+The plugin is invoked in the \fIabrt.conf\fP file, usually in the
+\fIActionsAndReporters\fP option and/or the \fI[cron]\fP section.
+There are two modes of invocation:
+.P
+* Specify \fIFileTransfer(one)\fP in ActionsAndReporters directive.
+Immediately after crash is detected, the plugin transfers crash data
+to the server specified in the \fIFileTransfer.conf\fP configuration file.
+.P
+* Specify \fIFileTransfer(store)\fP in ActionsAndReporters directive
+and add \fIHH:MM = FileTransfer\fP line in [cron] section.
+At the time of the crash,
+the plugin stores a record of it in its internal list.
+When specified time is reached, the plugin iterates through
+its internal list and sends every recorded crash to the specified URL.
+After that, the internal list is cleared.
+.SH CONFIGURATION
+The \fIFileTransfer.conf\fP configuration file contains
+several entries in the format "Option = Value". The options are:
+.SS URL
+The URL of the server, where the crash should
+be transfered, specifying the protocol, the path,
+the user name and the password, for example:
+.br
+URL = ftp://user:passwd@server.com/path
+.SS ArchiveType
+The type of the archive in which to pack the crash data.
+Currently, \fI.tar\fP, \fI.tar.gz\fP, \fI.tar.bz2\fP and \fI.zip\fP
+are supported. The default is \fI.tar.gz\fP
+.SS RetryCount
+This specifies how many times the plugin will try to resend
+the file if the transfer was not succesful. The plugin
+waits a while before it retries the transfer: see \fIRetryDelay\fP.
+The default is 3
+.SS RetryDelay
+If the transfer was not succesful, the plugin will
+wait some time before sending the file again. This configuration
+option specifies the time in seconds. The default is 20.
+.SH EXAMPLES
+.P
+Typical configuration in \fIabrt.conf\fP. The crash is stored
+each time it happens and at midnight, all the crash data
+is transferred to a central server.
+.P
+[common]
+.br
+ActionsAndReporters = FileTransfer(store)
+.br
+[cron]
+.br
+00:00 = FileTransfer
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/plugins/abrt-KerneloopsReporter.7 b/src/plugins/abrt-KerneloopsReporter.7
new file mode 100644
index 00000000..98bd3874
--- /dev/null
+++ b/src/plugins/abrt-KerneloopsReporter.7
@@ -0,0 +1,40 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+KerneloopsReporter plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fIKerneloopsReporter\fP
+plugin for \fIabrt\fP.
+.P
+This plugin is used to report the crash to the Kerneloops tracker.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file.
+No parameters are necessary.
+.SH CONFIGURATION
+The \fIKerneloopsReporter.conf\fP configuration file contains one entry:
+.SS SubmitURL
+The URL of the kerneloops tracker, the default is
+.br
+SubmitURL = http://submit.kerneloops.org/submitoops.php
+.SH EXAMPLES
+.P
+This is a snippet from the \fIabrt.conf\fP configuration file.
+Each time a kernel oops is detected, run KerneloopsReporter:
+.P
+[common]
+.br
+ActionsAndReporters = Kerneloops, KerneloopsReporter
+.br
+[AnalyzerActionsAndReporters]
+.br
+Kerneloops = KerneloopsReporter
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Anton Arapov <anton@redhat.com>. Manual
+page by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/plugins/abrt-KerneloopsScanner.7 b/src/plugins/abrt-KerneloopsScanner.7
new file mode 100644
index 00000000..ff094847
--- /dev/null
+++ b/src/plugins/abrt-KerneloopsScanner.7
@@ -0,0 +1,46 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+KerneloopsScanner plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fIKerneloopsScanner\fP
+plugin for \fIabrt\fP.
+.P
+This plugin reads the system log file (default /var/log/messages)
+and stores the kernel oops crashes, which were not already
+reported, to abrt's debug dump directory.
+.P
+To distinguish between new crashes and crashes
+that were already reported, the plugin makes its own entry
+in the log file, which acts as a separator.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file.
+No parameters are necessary.
+.SH CONFIGURATION
+The \fIKerneloopsScanner.conf\fP configuration file contains one entry:
+.SS SysLogFile
+The file to scan. The default is
+.br
+SysLogFile = /var/log/messages
+.SH EXAMPLES
+.P
+This is a snippet from the \fIabrt.conf\fP configuration file.
+Every 10 seconds look if there were any kernel crashes:
+.P
+[common]
+.br
+ActionsAndReporters = Kerneloops, KerneloopsScanner
+.br
+[cron]
+.br
+10 = KerneloopsScanner
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Anton Arapov <anton@redhat.com>. Manual
+page by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/plugins/abrt-Logger.7 b/src/plugins/abrt-Logger.7
new file mode 100644
index 00000000..8ae679f8
--- /dev/null
+++ b/src/plugins/abrt-Logger.7
@@ -0,0 +1,44 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+Logger plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fILogger\fP plugin
+for \fIabrt\fP.
+.P
+This plugin is used to log the crash to a file.
+.P
+The log will contain all the file names as well as their
+content. It also contains "duplicity check": the ID
+of the crash, which is used to tell whether the same
+crash has happened previously.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file.
+No parameters are necessary.
+.SH CONFIGURATION
+The \fILogger.conf\fP configuration file contains
+several entries in a format "Option = Value". The options are:
+.SS LogPath
+The path to the log file.
+.SS AppendLogs
+If set to "yes" (the default) \fILogger\fP will append
+the report to the file, otherwise it will overwrite the file (so
+only the last crash will be stored).
+.SH EXAMPLES
+.P
+This is a snippet from the \fIabrt.conf\fP configuration file.
+Log all the C/C++ application crashes:
+.P
+[AnalyzerActionsAndReporters]
+.br
+CCpp = Logger
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Zdenek Prikryl <zprikryl@redhat.com>. Manual
+page by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/plugins/abrt-Mailx.7 b/src/plugins/abrt-Mailx.7
new file mode 100644
index 00000000..90a8bbce
--- /dev/null
+++ b/src/plugins/abrt-Mailx.7
@@ -0,0 +1,57 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+Mailx plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fIMailx\fP plugin
+for \fIabrt\fP.
+.P
+This plugin is used to mail the data about the crash
+to a specified mail address.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file. It can take
+one parameter, a subject of the mail (if it differs from the
+one specified in the \fIMailx.conf\fP configuration file).
+.SH CONFIGURATION
+The \fIMailx.conf\fP configuration file contains
+several entries in a format "Option = Value". The options are:
+.SS Subject
+The subject of the mail.
+.SS Parameters
+The \fIMailx\fP plugin executes the external "mailx" command to
+send the mail. This option defines some additional command line
+parameters, which should be added to the program invocation, if any.
+.SS EmailFrom
+The address from which the email is sent.
+.SS EmailTo
+The address to which the email is sent.
+.SS SendBinaryData
+Can be "yes" or "no". If set to "yes", the email will also
+contain the binary files associated with the crash. Warning:
+this can cause the emails to be large! (several MB)
+.SH EXAMPLES
+.P
+These are snippets from the \fIabrt.conf\fP configuration file.
+.P
+1) Each time a crash happens, a mail is sent
+.PP
+[common]
+.br
+ActionsAndReporters = Mailx("[abrt] a crash occurs")
+.P
+2) When a program in a specific package (in this case "httpd") crashes,
+send a mail about it.
+.PP
+[AnalyzerActionsAndReporters]
+.br
+CCpp:httpd = Mailx("[abrt] Apache crash")
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Zdenek Prikryl <zprikryl@redhat.com>. Manual
+page by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/plugins/abrt-ReportUploader.7 b/src/plugins/abrt-ReportUploader.7
new file mode 100644
index 00000000..bd91f266
--- /dev/null
+++ b/src/plugins/abrt-ReportUploader.7
@@ -0,0 +1,55 @@
+.TH abrt "7" "9 July 2009" ""
+.SH NAME
+ReportUploader plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon which watches for application crashes. When a crash occurs,
+it collects the crash data and performs some actions according to
+the configuration. This manual page describes the \fIReportUploader\fP plugin
+for \fIabrt\fP.
+.P
+This plugin will send a report to an anonymous FTP site. It's intended
+for use in cases where a ticketing system is associated with the FTP site,
+but the ticketing system has no way to automatically create new tickets,
+or add to existing tickets. Customer Name is put in config file.
+Ticket name (or number) is also put in config file. If no ticket
+name is configured, assume ticketing system should create a new ticket.
+This information is added to the report, the report is copied into a
+compressed, optionally encrypted, tarball. Then the tarball is FTP'd
+to the upload site. Then a status string is displayed to the user
+showing the name of the file on the FTP site, it's MD5SUM, and
+it's encryption key. This information can be pasted into a ticket
+in the ticketing system.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file.
+No parameters are necessary.
+.SH CONFIGURATION
+The \fIReportUploader.conf\fP configuration file contains
+entries in a format "Option = Value". The options are:
+.SS Customer
+This is the customer's name or other customer identifier.
+.SS Ticket
+This is the ticket name or number.
+.SS Encrypt
+"yes" for encrypt upload, anything else for not.
+.SS Upload
+"yes" for for upload to FTP site, anything else for copy to local /tmp.
+.SS URL
+URL of upload site (ie. ftp://support.com/upload).
+.SH EXAMPLES
+.P
+This is a snippet from the \fIabrt.conf\fP configuration file.
+Log all the C/C++ application crashes:
+.P
+[AnalyzerActionsAndReporters]
+.br
+CCpp = RHUpload
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Plugin and man page by Gavin Romig-Koch <gavin@redhat.com>.
+
+
diff --git a/src/plugins/abrt-SQLite3.7 b/src/plugins/abrt-SQLite3.7
new file mode 100644
index 00000000..c2b39d86
--- /dev/null
+++ b/src/plugins/abrt-SQLite3.7
@@ -0,0 +1,36 @@
+.TH abrt "7" "1 Jun 2009" ""
+.SH NAME
+SQLite3 database plugin for abrt(8)
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data and takes action according to
+its configuration. This manual page describes the \fISQLite3\fP database plugin
+for \fIabrt\fP.
+.P
+This is a database plugin: \fIabrt\fP needs a database in which to store
+its metadata. You can choose one by specifying "Database" in
+the \fIabrt.conf\fP configuration file. Currently SQLite3 is
+the only choice supported.
+.SH INVOCATION
+The plugin is invoked in the \fIabrt.conf\fP configuration file, like
+this:
+.br
+[common]
+.br
+Database = SQLite3
+.SH CONFIGURATION
+The \fISQLite3.conf\fP configuration file contains one entry:
+.SS DBPath
+The path to the database.
+.SH EXAMPLES
+see \fBINVOCATION\fP
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-plugins (7)
+.SH AUTHOR
+Written by Zdenek Prikryl <zprikryl@redhat.com> and Jiri
+Moskovcak <jmoskovc@redhat.com>. Manual
+page by Daniel Novotny <dnovotny@redhat.com>.
diff --git a/src/daemon/abrt-action-analyze-c.c b/src/plugins/abrt-action-analyze-c.c
index 60e08372..60e08372 100644
--- a/src/daemon/abrt-action-analyze-c.c
+++ b/src/plugins/abrt-action-analyze-c.c
diff --git a/src/daemon/abrt-action-analyze-oops.c b/src/plugins/abrt-action-analyze-oops.c
index 354ec6fd..354ec6fd 100644
--- a/src/daemon/abrt-action-analyze-oops.c
+++ b/src/plugins/abrt-action-analyze-oops.c
diff --git a/src/daemon/abrt-action-analyze-python.c b/src/plugins/abrt-action-analyze-python.c
index bb5722ec..bb5722ec 100644
--- a/src/daemon/abrt-action-analyze-python.c
+++ b/src/plugins/abrt-action-analyze-python.c
diff --git a/src/daemon/abrt-action-bugzilla.cpp b/src/plugins/abrt-action-bugzilla.cpp
index a3c2f0b0..a3c2f0b0 100644
--- a/src/daemon/abrt-action-bugzilla.cpp
+++ b/src/plugins/abrt-action-bugzilla.cpp
diff --git a/src/daemon/abrt-action-generate-backtrace.c b/src/plugins/abrt-action-generate-backtrace.c
index 8f1642d7..8f1642d7 100644
--- a/src/daemon/abrt-action-generate-backtrace.c
+++ b/src/plugins/abrt-action-generate-backtrace.c
diff --git a/src/daemon/abrt-action-install-debuginfo b/src/plugins/abrt-action-install-debuginfo
index c1b8fdb9..c1b8fdb9 100755
--- a/src/daemon/abrt-action-install-debuginfo
+++ b/src/plugins/abrt-action-install-debuginfo
diff --git a/src/daemon/abrt-action-kerneloops.cpp b/src/plugins/abrt-action-kerneloops.cpp
index 4c820081..4c820081 100644
--- a/src/daemon/abrt-action-kerneloops.cpp
+++ b/src/plugins/abrt-action-kerneloops.cpp
diff --git a/src/daemon/abrt-action-print.cpp b/src/plugins/abrt-action-print.cpp
index a4db373a..a4db373a 100644
--- a/src/daemon/abrt-action-print.cpp
+++ b/src/plugins/abrt-action-print.cpp
diff --git a/src/daemon/abrt-action-rhtsupport.cpp b/src/plugins/abrt-action-rhtsupport.cpp
index d1854541..d1854541 100644
--- a/src/daemon/abrt-action-rhtsupport.cpp
+++ b/src/plugins/abrt-action-rhtsupport.cpp
diff --git a/src/plugins/abrt-plugins.7 b/src/plugins/abrt-plugins.7
new file mode 100644
index 00000000..6c07e65a
--- /dev/null
+++ b/src/plugins/abrt-plugins.7
@@ -0,0 +1,43 @@
+.TH abrt "8" "28 May 2009" ""
+.SH NAME
+abrt-plugins \- plugins for the abrt crash reporter program
+.SH DESCRIPTION
+.P
+.I abrt
+is a daemon that watches for application crashes. When a crash occurs,
+it collects the crash data (core file, application's command line etc.)
+and takes action according to the type of application that
+crashed and according to the configuration specified in the
+.I abrt.conf
+configuration file.
+.P
+Plugins allow abrt to perform various actions: for example,
+to report the crash to Bugzilla, to mail the report, to transfer
+the report via FTP or SCP, or to run a program that you specify.
+.P
+This manual page provides a list of all the manual pages for
+these plugins.
+.P
+If you want to create your own plugin, refer to the PLUGINS-HOWTO
+file in the documentation directory.
+.SH INVOCATION
+Each plugin is invoked in the \fIabrt.conf\fP configuration
+file, in the section that is appropriate to what you
+want abrt to do.
+.SH CONFIGURATION
+Almost every plugin has its configuration file,
+stored in the \fI/etc/abrt/plugins\fP directory.
+.SH "SEE ALSO"
+.IR abrt (8),
+.IR abrt.conf (5),
+.IR abrt-Bugzilla (7),
+.IR abrt-FileTransfer (7),
+.IR abrt-KerneloopsReporter (7),
+.IR abrt-KerneloopsScanner (7),
+.IR abrt-Logger (7),
+.IR abrt-Mailx (7),
+.IR abrt-SQLite3 (7)
+.SH AUTHOR
+\fIabrt\fP written by Zdeněk Přikryl <zprikryl@redhat.com> and
+Jiří Moskovčák <jmoskovc@redhat.com>. Manual page written by Daniel
+Novotný <dnovotny@redhat.com>.
diff --git a/src/daemon/abrt_rh_support.c b/src/plugins/abrt_rh_support.c
index 04e2c8ef..04e2c8ef 100644
--- a/src/daemon/abrt_rh_support.c
+++ b/src/plugins/abrt_rh_support.c
diff --git a/src/daemon/abrt_rh_support.h b/src/plugins/abrt_rh_support.h
index db6e9cd7..db6e9cd7 100644
--- a/src/daemon/abrt_rh_support.h
+++ b/src/plugins/abrt_rh_support.h