summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2011-05-13 18:32:06 +0200
committerKarel Klic <kklic@redhat.com>2011-05-13 18:32:06 +0200
commite16a562d8616d2ac55f58b091f95acd5b3174229 (patch)
treebf5c97a4ab4d4f792c436d4ed93a1c36cd381c3b /src/plugins
parent15473d2a5ecfd20bd8cc3982e703fcedd51289f8 (diff)
parente123c5f3b4bdd10f3b495a4a948f6c452ed6205f (diff)
downloadabrt-e16a562d8616d2ac55f58b091f95acd5b3174229.tar.gz
abrt-e16a562d8616d2ac55f58b091f95acd5b3174229.tar.xz
abrt-e16a562d8616d2ac55f58b091f95acd5b3174229.zip
merge
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/Makefile.am42
-rw-r--r--src/plugins/abrt-Bugzilla.743
-rw-r--r--src/plugins/abrt-Logger.744
-rw-r--r--src/plugins/abrt-Mailx.757
-rw-r--r--src/plugins/abrt-action-analyze-backtrace.c14
-rw-r--r--src/plugins/abrt-action-analyze-backtrace.txt53
-rw-r--r--src/plugins/abrt-action-analyze-c.c14
-rwxr-xr-xsrc/plugins/abrt-action-analyze-core.py6
-rw-r--r--src/plugins/abrt-action-analyze-oops.c14
-rw-r--r--src/plugins/abrt-action-analyze-python.c14
-rw-r--r--src/plugins/abrt-action-bugzilla.c340
-rw-r--r--src/plugins/abrt-action-bugzilla.cpp966
-rw-r--r--src/plugins/abrt-action-bugzilla.txt96
-rw-r--r--src/plugins/abrt-action-generate-backtrace.c18
-rw-r--r--src/plugins/abrt-action-generate-backtrace.txt47
-rw-r--r--src/plugins/abrt-action-install-debuginfo.c42
-rwxr-xr-xsrc/plugins/abrt-action-install-debuginfo.py135
-rw-r--r--src/plugins/abrt-action-kerneloops.c14
-rwxr-xr-xsrc/plugins/abrt-action-list-dsos.py29
-rw-r--r--src/plugins/abrt-action-list-dsos.txt44
-rw-r--r--src/plugins/abrt-action-mailx.c16
-rw-r--r--src/plugins/abrt-action-mailx.txt91
-rw-r--r--src/plugins/abrt-action-print.c14
-rw-r--r--src/plugins/abrt-action-print.txt63
-rw-r--r--src/plugins/abrt-action-rhtsupport.c14
-rw-r--r--src/plugins/abrt-action-trim-files.c15
-rw-r--r--src/plugins/abrt-action-trim-files.txt30
-rw-r--r--src/plugins/abrt-action-upload.c14
-rw-r--r--src/plugins/abrt-dump-oops.c18
-rw-r--r--src/plugins/abrt-retrace-client.c159
-rw-r--r--src/plugins/abrt_rh_support.c2
-rw-r--r--src/plugins/analyze_LocalGDB.xml.in1
-rw-r--r--src/plugins/analyze_RetraceServer.xml.in3
-rw-r--r--src/plugins/analyze_xsession_errors.xml.in10
-rw-r--r--src/plugins/ccpp_events.conf56
-rw-r--r--src/plugins/rhbz.c482
-rw-r--r--src/plugins/rhbz.h100
37 files changed, 1704 insertions, 1416 deletions
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 52006b5e..df0ad944 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -1,3 +1,5 @@
+-include ../../config.mak
+
pluginslibdir = $(PLUGINS_LIB_DIR)
bin_SCRIPTS = \
@@ -38,6 +40,7 @@ dist_events_DATA = \
report_Logger.conf \
analyze_LocalGDB.xml \
analyze_RetraceServer.xml \
+ analyze_xsession_errors.xml \
report_Mailx.xml \
report_RHTSupport.xml \
report_Kerneloops.xml
@@ -53,13 +56,31 @@ dist_eventsconf_DATA = \
rhtsupport_events.conf
man_MANS = \
- abrt-Bugzilla.7 \
abrt-KerneloopsReporter.7 \
- abrt-Logger.7 \
- abrt-Mailx.7 \
abrt-Upload.7 \
abrt-plugins.7
+MAN_TXT = \
+ abrt-action-print.txt \
+ abrt-action-trim-files.txt \
+ abrt-action-generate-backtrace.txt \
+ abrt-action-analyze-backtrace.txt \
+ abrt-action-mailx.txt \
+ abrt-action-bugzilla.txt \
+ abrt-action-list-dsos.txt
+
+# Manual pages are generated from .txt via Docbook
+man1_MANS = ${MAN_TXT:%.txt=%.1}
+
+%.1 %.5 %.7: %.xml
+ $(XMLTO_SILENT) xmlto man $< 2>&1 | sed '/Note/d'
+
+%.xml: %.txt ../../asciidoc.conf
+ $(ASCIIDOC_SILENT) asciidoc --backend=docbook --doctype=manpage --conf-file ../../asciidoc.conf -aabrt_version=$(PACKAGE_VERSION) -o $@ $<
+
+
+CLEANFILES = $(man1_MANS)
+
PYTHON_FILES = \
abrt-action-install-debuginfo.py \
abrt-action-list-dsos.py \
@@ -67,12 +88,15 @@ PYTHON_FILES = \
EXTRA_DIST = \
$(man_MANS) \
+ $(MAN_TXT) \
$(PYTHON_FILES) \
+ $(man1_MANS) \
+ analyze_xsession_errors.xml.in \
+ analyze_LocalGDB.xml.in \
+ analyze_RetraceServer.xml.in \
report_Bugzilla.xml.in \
report_Bugzilla.conf \
report_Logger.conf \
- analyze_LocalGDB.xml.in \
- analyze_RetraceServer.xml.in \
report_Mailx.xml.in \
report_RHTSupport.xml.in \
report_Kerneloops.xml.in
@@ -80,10 +104,6 @@ EXTRA_DIST = \
$(DESTDIR)/$(DEBUG_INFO_DIR):
$(mkdir_p) '$@'
-install-data-hook: $(DESTDIR)/$(DEBUG_INFO_DIR)
- $(LN_S) -f analyze_RetraceServer.xml $(DESTDIR)$(eventsdir)/reanalyze_RetraceServer.xml
- $(LN_S) -f analyze_LocalGDB.xml $(DESTDIR)$(eventsdir)/reanalyze_LocalGDB.xml
-
abrt_dump_oops_SOURCES = \
abrt-dump-oops.c
abrt_dump_oops_CPPFLAGS = \
@@ -219,7 +239,7 @@ abrt_action_analyze_backtrace_LDADD = \
../btparser/libbtparser.la
abrt_action_bugzilla_SOURCES = \
- abrt-action-bugzilla.cpp
+ abrt-action-bugzilla.c rhbz.c rhbz.h
abrt_action_bugzilla_CPPFLAGS = \
-I$(srcdir)/../include/report -I$(srcdir)/../include \
-I$(srcdir)/../lib \
@@ -233,7 +253,7 @@ abrt_action_bugzilla_CPPFLAGS = \
-DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(GLIB_CFLAGS) \
-D_GNU_SOURCE \
- -Wall -Wwrite-strings -Werror
+ -Wall -Wwrite-strings
abrt_action_bugzilla_LDADD = \
$(GLIB_LIBS) \
../lib/libabrt_web.la \
diff --git a/src/plugins/abrt-Bugzilla.7 b/src/plugins/abrt-Bugzilla.7
deleted file mode 100644
index 708695c7..00000000
--- a/src/plugins/abrt-Bugzilla.7
+++ /dev/null
@@ -1,43 +0,0 @@
-.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 problem 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
-problem 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-Logger.7 b/src/plugins/abrt-Logger.7
deleted file mode 100644
index a9fbae09..00000000
--- a/src/plugins/abrt-Logger.7
+++ /dev/null
@@ -1,44 +0,0 @@
-.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 problem 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
deleted file mode 100644
index 1f2f08fc..00000000
--- a/src/plugins/abrt-Mailx.7
+++ /dev/null
@@ -1,57 +0,0 @@
-.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 problem 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-action-analyze-backtrace.c b/src/plugins/abrt-action-analyze-backtrace.c
index f25f379c..5d8c77f6 100644
--- a/src/plugins/abrt-action-analyze-backtrace.c
+++ b/src/plugins/abrt-action-analyze-backtrace.c
@@ -21,8 +21,6 @@
#include "../btparser/location.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-generate-backtrace"
-
static const char *dump_dir_name = ".";
@@ -50,13 +48,11 @@ static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [options] -d DIR\n"
+ "\b [options] -d DIR\n"
"\n"
"Analyzes C/C++ backtrace, generates duplication hash, backtrace rating, and identifies crash function in dump directory DIR"
);
@@ -72,11 +68,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
diff --git a/src/plugins/abrt-action-analyze-backtrace.txt b/src/plugins/abrt-action-analyze-backtrace.txt
new file mode 100644
index 00000000..7a3f096c
--- /dev/null
+++ b/src/plugins/abrt-action-analyze-backtrace.txt
@@ -0,0 +1,53 @@
+abrt-action-analyze-backtrace(1)
+================================
+
+NAME
+----
+abrt-action-analyze-backtrace - Analyzes C/C++ backtrace, generates
+duplication hash, backtrace rating, and identifies crash function
+in dump directory DIR.
+
+
+SYNOPSIS
+--------
+'abrt-action-analyze-backtrace' [-v] [-d DIR]
+
+DESCRIPTION
+-----------
+The tool reads a file named 'backtrace' from problem dump directory,
+generates duplication hash, backtrace rating, and identifies
+crash function. Then it saves this data as new elements 'global_uuid',
+'rating', 'crash_function' in this dump directory.
+
+Integration with ABRT events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+'abrt-action-analyze-backtrace' can be used as a secondary analyzer,
+after backtrace has been generated. The data generated by
+'abrt-action-analyze-backtrace' is useful for reporting the crash
+to bug databases: rating makes it possible to prevent reporting of bugs
+with low quality (non-informative) backtraces, duplication hash
+is used to find already filed bugs about similar crashes.
+
+Example usage in abrt_event.conf:
+
+------------
+EVENT=analyze analyzer=CCpp
+ abrt-action-generate-backtrace || exit $?
+ abrt-action-analyze-backtrace
+------------
+
+OPTIONS
+-------
+-d DIR::
+ Path to dump directory.
+
+-v::
+ Be more verbose. Can be given multiple times.
+
+AUTHORS
+-------
+* ABRT team
+
+SEE ALSO
+--------
+abrt-action-generate-backtrace
diff --git a/src/plugins/abrt-action-analyze-c.c b/src/plugins/abrt-action-analyze-c.c
index e3fe71d3..487fb8f7 100644
--- a/src/plugins/abrt-action-analyze-c.c
+++ b/src/plugins/abrt-action-analyze-c.c
@@ -19,8 +19,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-analyze-c"
-
static void create_hash(char hash_str[SHA1_RESULT_LEN*2 + 1], const char *pInput)
{
unsigned char hash_bytes[SHA1_RESULT_LEN];
@@ -155,15 +153,13 @@ static void trim_unstrip_output(char *result, const char *unstrip_n_output)
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
const char *dump_dir_name = ".";
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] -d DIR\n"
+ "\b [-v] -d DIR\n"
"\n"
"Calculates and saves UUID of coredump in dump directory DIR"
);
@@ -179,11 +175,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
/* Run unstrip -n and trim its output, leaving only sizes and build ids */
diff --git a/src/plugins/abrt-action-analyze-core.py b/src/plugins/abrt-action-analyze-core.py
index 949519cc..06473c40 100755
--- a/src/plugins/abrt-action-analyze-core.py
+++ b/src/plugins/abrt-action-analyze-core.py
@@ -33,13 +33,13 @@ def error_msg(s):
def error_msg_and_die(s):
sys.stderr.write("%s\n" % s)
- os.exit(1)
+ sys.exit(1)
def xopen(name, mode):
try:
r = open(name, mode)
- except IOError, e:
- error_msg_and_die("Can't open '%s': %s" % (name, e));
+ except IOError, ex:
+ error_msg_and_die("Can't open '%s': %s" % (name, ex))
return r
diff --git a/src/plugins/abrt-action-analyze-oops.c b/src/plugins/abrt-action-analyze-oops.c
index 8fca109d..9485d3c8 100644
--- a/src/plugins/abrt-action-analyze-oops.c
+++ b/src/plugins/abrt-action-analyze-oops.c
@@ -19,8 +19,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-analyze-oops"
-
static void hash_oops_str(char hash_str[SHA1_RESULT_LEN*2 + 1], char *oops_buf, const char *oops_ptr)
{
unsigned char old_c;
@@ -137,15 +135,13 @@ static void hash_oops_str(char hash_str[SHA1_RESULT_LEN*2 + 1], char *oops_buf,
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
const char *dump_dir_name = ".";
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-vs] -d DIR\n"
+ "\b [-vs] -d DIR\n"
"\n"
"Calculates and saves UUID and DUPHASH for oops dump directory DIR"
);
@@ -161,11 +157,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
diff --git a/src/plugins/abrt-action-analyze-python.c b/src/plugins/abrt-action-analyze-python.c
index 07f14a32..5a33fb8d 100644
--- a/src/plugins/abrt-action-analyze-python.c
+++ b/src/plugins/abrt-action-analyze-python.c
@@ -19,19 +19,15 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-analyze-python"
-
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
const char *dump_dir_name = ".";
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] -d DIR\n"
+ "\b [-v] -d DIR\n"
"\n"
"Calculates and saves UUID and DUPHASH of python crash dumps"
);
@@ -47,11 +43,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
diff --git a/src/plugins/abrt-action-bugzilla.c b/src/plugins/abrt-action-bugzilla.c
new file mode 100644
index 00000000..91bc26f8
--- /dev/null
+++ b/src/plugins/abrt-action-bugzilla.c
@@ -0,0 +1,340 @@
+/*
+ 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 "abrt_problem_data.h"
+#include "parse_options.h"
+#include "abrt_xmlrpc.h"
+#include "rhbz.h"
+
+#define XML_RPC_SUFFIX "/xmlrpc.cgi"
+
+/* From RHEL6 kernel/panic.c:
+ * { TAINT_PROPRIETARY_MODULE, 'P', 'G' },
+ * { TAINT_FORCED_MODULE, 'F', ' ' },
+ * { TAINT_UNSAFE_SMP, 'S', ' ' },
+ * { TAINT_FORCED_RMMOD, 'R', ' ' },
+ * { TAINT_MACHINE_CHECK, 'M', ' ' },
+ * { TAINT_BAD_PAGE, 'B', ' ' },
+ * { TAINT_USER, 'U', ' ' },
+ * { TAINT_DIE, 'D', ' ' },
+ * { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
+ * { TAINT_WARN, 'W', ' ' },
+ * { TAINT_CRAP, 'C', ' ' },
+ * { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' },
+ * entries 12 - 27 are unused
+ * { TAINT_HARDWARE_UNSUPPORTED, 'H', ' ' },
+ * entries 29 - 31 are unused
+ */
+
+static const char * const taint_warnings[] = {
+ "Proprietary Module",
+ "Forced Module",
+ "Unsafe SMP",
+ "Forced rmmod",
+ "Machine Check",
+ "Bad Page",
+ "User",
+ "Die",
+ "Overriden ACPI Table",
+ "Warning Issued",
+ "Experimental Module Loaded",
+ "Firmware Workaround",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Hardware Unsupported",
+ NULL,
+ NULL,
+};
+
+/* TODO: npajkovs: fix tainted string */
+static const char *tainted_string(unsigned tainted)
+{
+ unsigned idx = 0;
+ while ((tainted >>= 1) != 0)
+ idx++;
+
+ return taint_warnings[idx];
+}
+
+static void report_to_bugzilla(const char *dump_dir_name, map_string_h *settings)
+{
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
+ xfunc_die(); /* dd_opendir already emitted error msg */
+ problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
+ dd_close(dd);
+
+ const char *env;
+ const char *login;
+ const char *password;
+ const char *bugzilla_xmlrpc;
+ const char *bugzilla_url;
+ bool ssl_verify;
+
+ env = getenv("Bugzilla_Login");
+ login = env ? env : get_map_string_item_or_empty(settings, "Login");
+ env = getenv("Bugzilla_Password");
+ password = env ? env : get_map_string_item_or_empty(settings, "Password");
+ if (!login[0] || !password[0])
+ error_msg_and_die(_("Empty login or password, please check your configuration"));
+
+ env = getenv("Bugzilla_BugzillaURL");
+ bugzilla_url = env ? env : get_map_string_item_or_empty(settings, "BugzillaURL");
+ if (!bugzilla_url[0])
+ bugzilla_url = "https://bugzilla.redhat.com";
+ bugzilla_xmlrpc = xasprintf("%s"XML_RPC_SUFFIX, bugzilla_url);
+
+ env = getenv("Bugzilla_SSLVerify");
+ ssl_verify = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SSLVerify"));
+
+ const char *component = get_problem_item_content_or_NULL(problem_data, FILENAME_COMPONENT);
+ const char *duphash = get_problem_item_content_or_NULL(problem_data, FILENAME_DUPHASH);
+ if (!duphash)
+ error_msg_and_die(_("Essential file '%s' is missing, can't continue.."),
+ FILENAME_DUPHASH);
+
+ if (!*duphash)
+ error_msg_and_die(_("Essential file '%s' is empty, can't continue.."),
+ FILENAME_DUPHASH);
+
+ const char *release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE);
+ if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */
+ release = get_problem_item_content_or_NULL(problem_data, "release");
+
+ struct abrt_xmlrpc *client = abrt_xmlrpc_new_client(bugzilla_xmlrpc, ssl_verify);
+
+ log(_("Logging into Bugzilla at %s"), bugzilla_url);
+ rhbz_login(client, login, password);
+
+ log(_("Checking for duplicates"));
+ char *product = NULL;
+ char *version = NULL;
+ parse_release_for_bz(release, &product, &version);
+ free(version);
+
+ xmlrpc_value *result;
+ if (strcmp(product, "Fedora") == 0)
+ result = rhbz_search_duphash(client, component, product, duphash);
+ else
+ result = rhbz_search_duphash(client, component, NULL, duphash);
+
+ xmlrpc_value *all_bugs = rhbz_get_member("bugs", result);
+ xmlrpc_DECREF(result);
+
+ if (!all_bugs)
+ error_msg_and_die(_("Missing mandatory member 'bugs'"));
+
+ int all_bugs_size = rhbz_array_size(all_bugs);
+ // When someone clones bug it has same duphash, so we can find more than 1.
+ // Need to be checked if component is same.
+ VERB3 log("Bugzilla has %i reports with same duphash '%s'",
+ all_bugs_size, duphash);
+
+ int bug_id = -1, dependent_bug = -1;
+ struct bug_info *bz = NULL;
+ if (all_bugs_size > 0)
+ {
+ bug_id = rhbz_bug_id(all_bugs);
+ xmlrpc_DECREF(all_bugs);
+ bz = rhbz_bug_info(client, bug_id);
+
+ if (strcmp(bz->bi_product, product) != 0)
+ {
+ dependent_bug = bug_id;
+ /* found something, but its a different product */
+ free_bug_info(bz);
+
+ xmlrpc_value *result = rhbz_search_duphash(client, component,
+ product, duphash);
+ xmlrpc_value *all_bugs = rhbz_get_member("bugs", result);
+ xmlrpc_DECREF(result);
+
+ all_bugs_size = rhbz_array_size(all_bugs);
+ if (all_bugs_size > 0)
+ {
+ bug_id = rhbz_bug_id(all_bugs);
+ bz = rhbz_bug_info(client, bug_id);
+ }
+ xmlrpc_DECREF(all_bugs);
+ }
+
+ }
+ free(product);
+
+ if (all_bugs_size == 0) // Create new bug
+ {
+ log(_("Creating a new bug"));
+ bug_id = rhbz_new_bug(client, problem_data, bug_id);
+
+ log("Adding attachments to bug %i", bug_id);
+ char bug_id_str[sizeof(int)*3 + 2];
+ sprintf(bug_id_str, "%i", bug_id);
+
+ rhbz_attachments(client, bug_id_str, problem_data);
+
+ log(_("Logging out"));
+ rhbz_logout(client);
+
+ log("Status: NEW %s/show_bug.cgi?id=%u", bugzilla_url, bug_id);
+ abrt_xmlrpc_free_client(client);
+ return;
+ }
+
+ // decision based on state
+ log(_("Bug is already reported: %i"), bz->bi_id);
+ if ((strcmp(bz->bi_status, "CLOSED") == 0)
+ && (strcmp(bz->bi_resolution, "DUPLICATE") == 0))
+ {
+ struct bug_info *origin;
+ origin = rhbz_find_origin_bug_closed_duplicate(client, bz);
+ if (origin)
+ {
+ free_bug_info(bz);
+ bz = origin;
+ }
+ }
+
+ if (strcmp(bz->bi_status, "CLOSED") != 0)
+ {
+ if ((strcmp(bz->bi_reporter, login) != 0)
+ && (!g_list_find_custom(bz->bi_cc_list, login, (GCompareFunc)g_strcmp0)))
+ {
+ log(_("Add %s to CC list"), login);
+ rhbz_mail_to_cc(client, bz->bi_id, login);
+ }
+
+ char *dsc = make_description_comment(problem_data);
+ if (dsc)
+ {
+ const char *package = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_PACKAGE);
+ const char *release = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_OS_RELEASE);
+ if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */
+ release = get_problem_item_content_or_NULL(problem_data, "release");
+ const char *arch = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_ARCHITECTURE);
+ const char *is_private = get_problem_item_content_or_NULL(problem_data,
+ "is_private");
+
+ char *full_dsc = xasprintf("Package: %s\n"
+ "Architecture: %s\n"
+ "OS Release: %s\n"
+ "%s", package, arch, release, dsc);
+
+ log(_("Adding new comment to bug %d"), bz->bi_id);
+ free(dsc);
+
+ int is_priv = is_private && string_to_bool(is_private);
+ rhbz_add_comment(client, bz->bi_id, full_dsc, is_priv);
+ free(full_dsc);
+ }
+ }
+
+ log(_("Logging out"));
+ rhbz_logout(client);
+
+ log("Status: %s%s%s %s/show_bug.cgi?id=%u",
+ bz->bi_status,
+ bz->bi_resolution ? " " : "",
+ bz->bi_resolution ? bz->bi_resolution : "",
+ bugzilla_url,
+ bz->bi_id);
+
+ dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (dd)
+ {
+ char *msg = xasprintf("Bugzilla: URL=%s/show_bug.cgi?id=%u", bugzilla_url, bz->bi_id);
+ add_reported_to(dd, msg);
+ free(msg);
+ dd_close(dd);
+ }
+
+ free_problem_data(problem_data);
+ free_bug_info(bz);
+ abrt_xmlrpc_free_client(client);
+}
+
+int main(int argc, char **argv)
+{
+ abrt_init(argv);
+
+ map_string_h *settings = new_map_string();
+ const char *dump_dir_name = ".";
+ GList *conf_file = NULL;
+
+ /* Can't keep these strings/structs static: _() doesn't support that */
+ const char *program_usage_string = _(
+ "\b [-v] -c CONFFILE -d DIR\n"
+ "\n"
+ "Reports problem to Bugzilla"
+ );
+ enum {
+ OPT_v = 1 << 0,
+ OPT_d = 1 << 1,
+ OPT_c = 1 << 2,
+ };
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Dump directory")),
+ OPT_LIST( 'c', NULL, &conf_file , "FILE", _("Configuration file (may be given many times)")),
+ OPT_END()
+ };
+ /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
+
+ export_abrt_envvars(0);
+
+ while (conf_file)
+ {
+ char *fn = (char *)conf_file->data;
+ VERB1 log("Loading settings from '%s'", fn);
+ load_conf_file(fn, settings, /*skip key w/o values:*/ true);
+ VERB3 log("Loaded '%s'", fn);
+ conf_file = g_list_remove(conf_file, fn);
+ }
+
+ VERB1 log("Initializing XML-RPC library");
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+ xmlrpc_client_setup_global_const(&env);
+ if (env.fault_occurred)
+ error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
+ xmlrpc_env_clean(&env);
+
+ report_to_bugzilla(dump_dir_name, settings);
+
+ free_map_string(settings);
+ return 0;
+}
diff --git a/src/plugins/abrt-action-bugzilla.cpp b/src/plugins/abrt-action-bugzilla.cpp
deleted file mode 100644
index 6f551e2c..00000000
--- a/src/plugins/abrt-action-bugzilla.cpp
+++ /dev/null
@@ -1,966 +0,0 @@
-/*
- 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 "abrt_xmlrpc.h"
-#include "abrt_problem_data.h"
-#include "parse_options.h"
-
-#define PROGNAME "abrt-action-bugzilla"
-
-#define XML_RPC_SUFFIX "/xmlrpc.cgi"
-#define MAX_HOPS 5
-
-/*
- * TODO: npajkovs: better deallocation of xmlrpc value
- * npajkovs: better gathering function which collects all information from bugzilla
- * npajkovs: figure out how to deal with cloning bugs
- * npajkovs: check if attachment was uploaded successul an if not try it again(max 3 times)
- * and if it still fails. retrun successful, but mention that attaching failed
- * npajkovs: add option to set comment privat
- */
-
-struct bug_info {
- const char* bug_status;
- const char* bug_resolution;
- const char* bug_reporter;
- const char* bug_product;
- xmlrpc_int32 bug_dup_id;
- GList* bug_cc;
-};
-
-/* xzalloc */
-static void bug_info_init(struct bug_info* bz)
-{
- bz->bug_status = NULL;
- bz->bug_resolution = NULL;
- bz->bug_reporter = NULL;
- bz->bug_product = NULL;
- bz->bug_dup_id = -1;
- bz->bug_cc = NULL;
-}
-
-static void bug_info_destroy(struct bug_info* bz)
-{
- free((void*)bz->bug_status);
- free((void*)bz->bug_resolution);
- free((void*)bz->bug_reporter);
- free((void*)bz->bug_product);
-
- list_free_with_free(bz->bug_cc);
-}
-
-/*
- * Static namespace for xmlrpc stuff.
- * Used mainly to ensure we always destroy xmlrpc client and server_info.
- */
-
-namespace {
-
-struct ctx: public abrt_xmlrpc_conn {
- xmlrpc_env env;
-
- ctx(const char* url, bool ssl_verify): abrt_xmlrpc_conn(url, ssl_verify)
- { xmlrpc_env_init(&env); }
- ~ctx() { xmlrpc_env_clean(&env); }
-
- void login(const char* login, const char* passwd);
- void logout();
-
- const char* get_bug_status(xmlrpc_value* result_xml);
- const char* get_bug_resolution(xmlrpc_value* result_xml);
- const char* get_bug_reporter(xmlrpc_value* result_xml);
- const char* get_bug_product(xmlrpc_value* relult_xml);
-
- xmlrpc_value* call_quicksearch_duphash(const char* component, const char* release, const char* duphash);
- xmlrpc_value* get_cc_member(xmlrpc_value* result_xml);
- xmlrpc_value* get_member(const char* member, xmlrpc_value* result_xml);
-
- int get_array_size(xmlrpc_value* result_xml);
- xmlrpc_int32 get_bug_id(xmlrpc_value* result_xml);
- xmlrpc_int32 get_bug_dup_id(xmlrpc_value* result_xml);
- void get_bug_cc(xmlrpc_value* result_xml, struct bug_info* bz);
- int add_plus_one_cc(xmlrpc_int32 bug_id, const char* login);
- xmlrpc_int32 new_bug(problem_data_t *problem_data, int depend_on_bugno);
- int add_attachments(const char* bug_id_str, problem_data_t *problem_data);
- int get_bug_info(struct bug_info* bz, xmlrpc_int32 bug_id);
- int add_comment(xmlrpc_int32 bug_id, const char* comment, bool is_private);
-
- xmlrpc_value* call(const char* method, const char* format, ...);
-};
-
-xmlrpc_value* ctx::call(const char* method, const char* format, ...)
-{
- xmlrpc_value* result = NULL;
-
- if (!env.fault_occurred)
- {
- xmlrpc_value* param = NULL;
- va_list args;
- const char* suffix;
-
- va_start(args, format);
- xmlrpc_build_value_va(&env, format, args, &param, &suffix);
- va_end(args);
-
- if (*suffix != '\0')
- {
- xmlrpc_env_set_fault_formatted(
- &env, XMLRPC_INTERNAL_ERROR, "Junk after the argument "
- "specifier: '%s'. There must be exactly one arument.",
- suffix);
- }
- else
- {
- xmlrpc_client_call2(&env, m_pClient, m_pServer_info, method, param, &result);
- }
- xmlrpc_DECREF(param);
- if (env.fault_occurred)
- return NULL;
- }
-
- return result;
-}
-
-xmlrpc_value* ctx::get_member(const char* member, xmlrpc_value* result_xml)
-{
- xmlrpc_value* cc_member = NULL;
- xmlrpc_struct_find_value(&env, result_xml, member, &cc_member);
- if (env.fault_occurred)
- return NULL;
-
- return cc_member;
-}
-
-int ctx::get_array_size(xmlrpc_value* result_xml)
-{
- int size = xmlrpc_array_size(&env, result_xml);
- if (env.fault_occurred)
- return -1;
-
- return size;
-}
-
-xmlrpc_int32 ctx::get_bug_dup_id(xmlrpc_value* result_xml)
-{
- xmlrpc_value* dup_id = get_member("dup_id", result_xml);
- if (!dup_id)
- return -1;
-
- xmlrpc_int32 dup_id_int = -1;
- xmlrpc_read_int(&env, dup_id, &dup_id_int);
- xmlrpc_DECREF(dup_id);
- if (env.fault_occurred)
- return -1;
-
- VERB3 log("got dup_id: %i", dup_id_int);
- return dup_id_int;
-}
-
-const char* ctx::get_bug_product(xmlrpc_value* result_xml)
-{
- xmlrpc_value* product_member = get_member("product", result_xml);
- if (!product_member) //should never happend. Each bug has to set up product
- return NULL;
-
- const char* product = NULL;
- xmlrpc_read_string(&env, product_member, &product);
- xmlrpc_DECREF(product_member);
- if (env.fault_occurred)
- return NULL;
-
- if (*product != '\0')
- {
- VERB3 log("got bug product: %s", product);
- return product;
- }
-
- free((void*)product);
- return NULL;
-}
-
-const char* ctx::get_bug_reporter(xmlrpc_value* result_xml)
-{
- xmlrpc_value* reporter_member = get_member("reporter", result_xml);
- if (!reporter_member)
- return NULL;
-
- const char* reporter = NULL;
- xmlrpc_read_string(&env, reporter_member, &reporter);
- xmlrpc_DECREF(reporter_member);
- if (env.fault_occurred)
- return NULL;
-
- if (*reporter != '\0')
- {
- VERB3 log("got bug reporter: %s", reporter);
- return reporter;
- }
- free((void*)reporter);
- return NULL;
-}
-
-const char* ctx::get_bug_resolution(xmlrpc_value* result_xml)
-{
- xmlrpc_value* bug_resolution = get_member("resolution", result_xml);
- if (!bug_resolution)
- return NULL;
-
- const char* resolution_str = NULL;
- xmlrpc_read_string(&env, bug_resolution, &resolution_str);
- xmlrpc_DECREF(bug_resolution);
- if (env.fault_occurred)
- return NULL;
-
- if (*resolution_str != '\0')
- {
- VERB3 log("got resolution: %s", resolution_str);
- return resolution_str;
- }
- free((void*)resolution_str);
- return NULL;
-}
-
-const char* ctx::get_bug_status(xmlrpc_value* result_xml)
-{
- xmlrpc_value* bug_status = get_member("bug_status", result_xml);
- if (!bug_status)
- return NULL;
-
- const char* status_str = NULL;
- xmlrpc_read_string(&env, bug_status, &status_str);
- xmlrpc_DECREF(bug_status);
- if (env.fault_occurred)
- return NULL;
-
- if (*status_str != '\0')
- {
- VERB3 log("got bug_status: %s", status_str);
- return status_str;
- }
- free((void*)status_str);
- return NULL;
-}
-
-void ctx::get_bug_cc(xmlrpc_value* result_xml, struct bug_info* bz)
-{
- xmlrpc_value* cc_member = get_member("cc", result_xml);
- if (!cc_member)
- return;
-
- int array_size = xmlrpc_array_size(&env, cc_member);
- if (array_size == -1)
- return;
-
- VERB3 log("count members on cc %i", array_size);
-
- for (int i = 0; i < array_size; i++)
- {
- xmlrpc_value* item = NULL;
- xmlrpc_array_read_item(&env, cc_member, i, &item);
- if (env.fault_occurred)
- return;
-
- if (item)
- {
- const char* cc = NULL;
- xmlrpc_read_string(&env, item, &cc);
- xmlrpc_DECREF(item);
- if (env.fault_occurred)
- {
- xmlrpc_DECREF(cc_member);
- return;
- }
-
- if (*cc != '\0')
- {
- bz->bug_cc = g_list_append(bz->bug_cc, (char*)cc);
- VERB3 log("member on cc is %s", cc);
- continue;
- }
- free((char*)cc);
- }
- }
- xmlrpc_DECREF(cc_member);
- return;
-}
-
-xmlrpc_value* ctx::call_quicksearch_duphash(const char* component,
- const char* release, const char* duphash)
-{
- char *query = NULL;
- if (!release)
- query = xasprintf("ALL component:\"%s\" whiteboard:\"%s\"", component, duphash);
- else
- {
- char *product = NULL;
- char *version = NULL;
- parse_release_for_bz(release, &product, &version);
- query = xasprintf("ALL component:\"%s\" whiteboard:\"%s\" product:\"%s\"",
- component, duphash, product
- );
- free(product);
- free(version);
- }
-
- VERB3 log("quicksearch for `%s'", query);
- xmlrpc_value *ret = call("Bug.search", "({s:s})", "quicksearch", query);
- free(query);
- return ret;
-}
-
-xmlrpc_int32 ctx::get_bug_id(xmlrpc_value* result_xml)
-{
- xmlrpc_value* item = NULL;
- xmlrpc_array_read_item(&env, result_xml, 0, &item);
- if (env.fault_occurred)
- return -1;
-
- xmlrpc_value* bug = get_member("bug_id", item);
- xmlrpc_DECREF(item);
- if (!bug)
- return -1;
-
- xmlrpc_int32 bug_id = -1;
- xmlrpc_read_int(&env, bug, &bug_id);
- xmlrpc_DECREF(bug);
- if (env.fault_occurred)
- return -1;
-
- VERB3 log("got bug_id %d", (int)bug_id);
- return bug_id;
-}
-
-int ctx::add_plus_one_cc(xmlrpc_int32 bug_id, const char* login)
-{
- xmlrpc_value* result = call("Bug.update", "({s:i,s:{s:(s)}})", "ids", (int)bug_id, "updates", "add_cc", login);
- if (result)
- xmlrpc_DECREF(result);
- return result ? 0 : -1;
-}
-
-int ctx::add_comment(xmlrpc_int32 bug_id, const char* comment, bool is_private)
-{
- xmlrpc_value* result = call("Bug.add_comment", "({s:i,s:s,s:b})", "id", (int)bug_id,
- "comment", comment,
- "private", is_private);
- if (result)
- xmlrpc_DECREF(result);
- return result ? 0 : -1;
-}
-
-/* From RHEL6 kernel/panic.c:
- * { TAINT_PROPRIETARY_MODULE, 'P', 'G' },
- * { TAINT_FORCED_MODULE, 'F', ' ' },
- * { TAINT_UNSAFE_SMP, 'S', ' ' },
- * { TAINT_FORCED_RMMOD, 'R', ' ' },
- * { TAINT_MACHINE_CHECK, 'M', ' ' },
- * { TAINT_BAD_PAGE, 'B', ' ' },
- * { TAINT_USER, 'U', ' ' },
- * { TAINT_DIE, 'D', ' ' },
- * { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
- * { TAINT_WARN, 'W', ' ' },
- * { TAINT_CRAP, 'C', ' ' },
- * { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' },
- * entries 12 - 27 are unused
- * { TAINT_HARDWARE_UNSUPPORTED, 'H', ' ' },
- * entries 29 - 31 are unused
- */
-
-static const char * const taint_warnings[] = {
- "Proprietary Module",
- "Forced Module",
- "Unsafe SMP",
- "Forced rmmod",
- "Machine Check",
- "Bad Page",
- "User",
- "Die",
- "Overriden ACPI Table",
- "Warning Issued",
- "Experimental Module Loaded",
- "Firmware Workaround",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "Hardware Unsupported",
- NULL,
- NULL,
-};
-
-static const char *tainted_string(unsigned tainted)
-{
- unsigned idx = 0;
- while ((tainted >>= 1) != 0)
- idx++;
-
- return taint_warnings[idx];
-}
-
-xmlrpc_int32 ctx::new_bug(problem_data_t *problem_data, int depend_on_bugno)
-{
- const char *package = get_problem_item_content_or_NULL(problem_data, FILENAME_PACKAGE);
- const char *component = get_problem_item_content_or_NULL(problem_data, FILENAME_COMPONENT);
- const char *release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE);
- if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */
- release = get_problem_item_content_or_NULL(problem_data, "release");
- const char *arch = get_problem_item_content_or_NULL(problem_data, FILENAME_ARCHITECTURE);
- const char *duphash = get_problem_item_content_or_NULL(problem_data, FILENAME_DUPHASH);
- const char *reason = get_problem_item_content_or_NULL(problem_data, FILENAME_REASON);
- const char *function = get_problem_item_content_or_NULL(problem_data, FILENAME_CRASH_FUNCTION);
- const char *analyzer = get_problem_item_content_or_NULL(problem_data, FILENAME_ANALYZER);
- const char *tainted_str = get_problem_item_content_or_NULL(problem_data, FILENAME_TAINTED);
-
- struct strbuf *buf_summary = strbuf_new();
- strbuf_append_strf(buf_summary, "[abrt] %s", package);
-
- if (function != NULL && strlen(function) < 30)
- strbuf_append_strf(buf_summary, ": %s", function);
-
- if (reason != NULL)
- strbuf_append_strf(buf_summary, ": %s", reason);
-
- if (tainted_str && analyzer
- && (strcmp(analyzer, "Kerneloops") == 0)
- ) {
- unsigned long tainted = xatoi_positive(tainted_str);
- const char *tainted_warning = tainted_string(tainted);
- if (tainted_warning)
- strbuf_append_strf(buf_summary, ": TAINTED %s", tainted_warning);
- }
-
- char *status_whiteboard = xasprintf("abrt_hash:%s", duphash);
-
- char *bz_dsc = make_description_bz(problem_data);
- char *full_dsc = xasprintf("abrt version: "VERSION"\n%s", bz_dsc);
- free(bz_dsc);
-
- char *product = NULL;
- char *version = NULL;
- parse_release_for_bz(release, &product, &version);
-
- xmlrpc_value* result = NULL;
- char *summary = strbuf_free_nobuf(buf_summary);
- if (depend_on_bugno > -1)
- {
- result = call("Bug.create", "({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:i})",
- "product", product,
- "component", component,
- "version", version,
- "summary", summary,
- "description", full_dsc,
- "status_whiteboard", status_whiteboard,
- "platform", arch,
- "dependson", depend_on_bugno
- );
- }
- else
- {
- result = call("Bug.create", "({s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
- "product", product,
- "component", component,
- "version", version,
- "summary", summary,
- "description", full_dsc,
- "status_whiteboard", status_whiteboard,
- "platform", arch
- );
- }
- free(status_whiteboard);
- free(product);
- free(version);
- free(summary);
- free(full_dsc);
-
- if (!result)
- return -1;
-
- xmlrpc_value* id = get_member("id", result);
- xmlrpc_DECREF(result);
- if (!id)
- return -1;
-
- xmlrpc_int32 bug_id = -1;
- xmlrpc_read_int(&env, id, &bug_id);
- xmlrpc_DECREF(id);
- if (env.fault_occurred)
- return -1;
-
- log(_("New bug id: %i"), (int)bug_id);
-
- return bug_id;
-}
-
-int ctx::add_attachments(const char* bug_id_str, problem_data_t *problem_data)
-{
- GHashTableIter iter;
- char *name;
- struct problem_item *value;
- g_hash_table_iter_init(&iter, problem_data);
- while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
- {
- const char *content = value->content;
-
- // We were special-casing FILENAME_BACKTRACE here, but karel says
- // he can retrieve it in inlined form from comments too.
- if ((value->flags & CD_FLAG_TXT)
- && (strlen(content) > CD_TEXT_ATT_SIZE /*|| (strcmp(name, FILENAME_BACKTRACE) == 0)*/)
- ) {
- char *encoded64 = encode_base64(content, strlen(content));
- char *filename = xasprintf("File: %s", name);
- xmlrpc_value* result = call("bugzilla.addAttachment", "(s{s:s,s:s,s:s,s:s})", bug_id_str,
- "description", filename,
- "filename", name,
- "contenttype", "text/plain",
- "data", encoded64
- );
- free(encoded64);
- free(filename);
- if (!result)
- return -1;
-
- xmlrpc_DECREF(result);
- }
- }
- return 0;
-}
-
-int ctx::get_bug_info(struct bug_info* bz, xmlrpc_int32 bug_id)
-{
- char bug_id_str[sizeof(long)*3 + 2];
- sprintf(bug_id_str, "%lu", (long)bug_id);
- xmlrpc_value* result = call("bugzilla.getBug", "(s)", bug_id_str);
- if (!result)
- return -1;
-
- bz->bug_product = get_bug_product(result);
- if (bz->bug_product == NULL)
- return -1;
-
- bz->bug_status = get_bug_status(result);
- if (bz->bug_status == NULL)
- return -1;
-
- bz->bug_reporter = get_bug_reporter(result);
- if (bz->bug_reporter == NULL)
- return -1;
-
- // mandatory when bug status is CLOSED
- if (strcmp(bz->bug_status, "CLOSED") == 0)
- {
- bz->bug_resolution = get_bug_resolution(result);
- if ((env.fault_occurred) && (bz->bug_resolution == NULL))
- return -1;
- }
-
- // mandatory when bug status is CLOSED and resolution is DUPLICATE
- if ((strcmp(bz->bug_status, "CLOSED") == 0)
- && (strcmp(bz->bug_resolution, "DUPLICATE") == 0)
- ) {
- bz->bug_dup_id = get_bug_dup_id(result);
- if (env.fault_occurred)
- return -1;
- }
-
- get_bug_cc(result, bz);
- if (env.fault_occurred)
- return -1;
-
- xmlrpc_DECREF(result);
- return 0;
-}
-
-void ctx::login(const char* login, const char* passwd)
-{
- xmlrpc_value* result = call("User.login", "({s:s,s:s})", "login", login, "password", passwd);
-//TODO: with URL like http://bugzilla.redhat.com (that is, with http: instead of https:)
-//we are getting this error:
-//Logging into Bugzilla at http://bugzilla.redhat.com
-//Can't login. Server said: HTTP response code is 301, not 200
-//But this is a 301 redirect! We _can_ follow it if we configure curl to understand that!
- if (!result)
- error_msg_and_die("Can't login. Server said: %s", env.fault_string);
- xmlrpc_DECREF(result);
-}
-
-void ctx::logout()
-{
- xmlrpc_value* result = call("User.logout", "(s)", "");
- if (result)
- xmlrpc_DECREF(result);
-
- throw_if_xml_fault_occurred(&env);
-}
-
-} /* namespace */
-
-
-static void report_to_bugzilla(
- const char *dump_dir_name,
- map_string_h *settings)
-{
- struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (!dd)
- xfunc_die(); /* dd_opendir already emitted error msg */
- problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
- dd_close(dd);
-
- const char *env;
- const char *login;
- const char *password;
- const char *bugzilla_xmlrpc;
- const char *bugzilla_url;
- bool ssl_verify;
-
- env = getenv("Bugzilla_Login");
- login = env ? env : get_map_string_item_or_empty(settings, "Login");
- env = getenv("Bugzilla_Password");
- password = env ? env : get_map_string_item_or_empty(settings, "Password");
- if (!login[0] || !password[0])
- error_msg_and_die(_("Empty login or password, please check your configuration"));
-
- env = getenv("Bugzilla_BugzillaURL");
- bugzilla_url = env ? env : get_map_string_item_or_empty(settings, "BugzillaURL");
- if (!bugzilla_url[0])
- bugzilla_url = "https://bugzilla.redhat.com";
- bugzilla_xmlrpc = xasprintf("%s"XML_RPC_SUFFIX, bugzilla_url);
-
- env = getenv("Bugzilla_SSLVerify");
- ssl_verify = string_to_bool(env ? env : get_map_string_item_or_empty(settings, "SSLVerify"));
-
- const char *component = get_problem_item_content_or_NULL(problem_data, FILENAME_COMPONENT);
- const char *duphash = get_problem_item_content_or_NULL(problem_data, FILENAME_DUPHASH);
- if (!duphash)
- error_msg_and_die(_("Essential file '%s' is missing, can't continue.."),
- FILENAME_DUPHASH);
-
- if (!*duphash)
- error_msg_and_die(_("Essential file '%s' is empty, can't continue.."),
- FILENAME_DUPHASH);
-
- const char *release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE);
- if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */
- release = get_problem_item_content_or_NULL(problem_data, "release");
-
- ctx bz_server(bugzilla_xmlrpc, ssl_verify);
-
- log(_("Logging into Bugzilla at %s"), bugzilla_url);
- bz_server.login(login, password);
-
- log(_("Checking for duplicates"));
-
- char *product = NULL;
- char *version = NULL;
- parse_release_for_bz(release, &product, &version);
- free(version);
-
- xmlrpc_value *result;
- if (strcmp(product, "Fedora") == 0)
- result = bz_server.call_quicksearch_duphash(component, product, duphash);
- else
- result = bz_server.call_quicksearch_duphash(component, NULL, duphash);
-
- if (!result)
- throw_if_xml_fault_occurred(&bz_server.env);
-
- xmlrpc_value *all_bugs = bz_server.get_member("bugs", result);
- xmlrpc_DECREF(result);
-
- if (!all_bugs)
- {
- throw_if_xml_fault_occurred(&bz_server.env);
- error_msg_and_die(_("Missing mandatory member 'bugs'"));
- }
-
- xmlrpc_int32 bug_id = -1;
- int all_bugs_size = bz_server.get_array_size(all_bugs);
- struct bug_info bz;
- int depend_on_bugno = -1;
- if (all_bugs_size > 0)
- {
- bug_id = bz_server.get_bug_id(all_bugs);
- xmlrpc_DECREF(all_bugs);
- if (bug_id == -1)
- throw_if_xml_fault_occurred(&bz_server.env);
-
- bug_info_init(&bz);
- if (bz_server.get_bug_info(&bz, bug_id) == -1)
- {
- bug_info_destroy(&bz);
- throw_if_xml_fault_occurred(&bz_server.env);
- error_msg_and_die(_("get_bug_info() failed. Could not collect all mandatory information"));
- }
-
- if (strcmp(bz.bug_product, product) != 0)
- {
- depend_on_bugno = bug_id;
- bug_info_destroy(&bz);
- result = bz_server.call_quicksearch_duphash(component, release, duphash);
- if (!result)
- throw_if_xml_fault_occurred(&bz_server.env);
-
- all_bugs = bz_server.get_member("bugs", result);
- xmlrpc_DECREF(result);
-
- if (!all_bugs)
- {
- throw_if_xml_fault_occurred(&bz_server.env);
- error_msg_and_die(_("Missing mandatory member 'bugs'"));
- }
-
- all_bugs_size = bz_server.get_array_size(all_bugs);
- if (all_bugs_size > 0)
- {
- bug_id = bz_server.get_bug_id(all_bugs);
- xmlrpc_DECREF(all_bugs);
- if (bug_id == -1)
- throw_if_xml_fault_occurred(&bz_server.env);
-
- bug_info_init(&bz);
- if (bz_server.get_bug_info(&bz, bug_id) == -1)
- {
- bug_info_destroy(&bz);
- throw_if_xml_fault_occurred(&bz_server.env);
- error_msg_and_die(_("get_bug_info() failed. Could not collect all mandatory information"));
- }
- }
- else
- xmlrpc_DECREF(all_bugs);
- }
- }
- free(product);
-
- if (all_bugs_size < 0)
- {
- throw_if_xml_fault_occurred(&bz_server.env);
- }
- else if (all_bugs_size == 0) // Create new bug
- {
- log(_("Creating a new bug"));
- bug_id = bz_server.new_bug(problem_data, depend_on_bugno);
- if (bug_id < 0)
- {
- throw_if_xml_fault_occurred(&bz_server.env);
- error_msg_and_die(_("Bugzilla entry creation failed"));
- }
-
- log("Adding attachments to bug %ld", (long)bug_id);
- char bug_id_str[sizeof(long)*3 + 2];
- sprintf(bug_id_str, "%ld", (long) bug_id);
- int ret = bz_server.add_attachments(bug_id_str, problem_data);
- if (ret == -1)
- {
- throw_if_xml_fault_occurred(&bz_server.env);
- }
-
- log(_("Logging out"));
- bz_server.logout();
-
- log("Status: NEW %s/show_bug.cgi?id=%u",
- bugzilla_url,
- (int)bug_id
- );
- return;
- }
-
- if (all_bugs_size > 1)
- {
- // When someone clones bug it has same duphash, so we can find more than 1.
- // Need to be checked if component is same.
- VERB3 log("Bugzilla has %u reports with same duphash '%s'", all_bugs_size, duphash);
- }
-
- // decision based on state
- log(_("Bug is already reported: %i"), bug_id);
-
- xmlrpc_int32 original_bug_id = bug_id;
- if ((strcmp(bz.bug_status, "CLOSED") == 0) && (strcmp(bz.bug_resolution, "DUPLICATE") == 0))
- {
- for (int ii = 0; ii <= MAX_HOPS; ii++)
- {
- if (ii == MAX_HOPS)
- {
- VERB3 log("Bugzilla could not find a parent of bug %d", (int)original_bug_id);
- bug_info_destroy(&bz);
- error_msg_and_die(_("Bugzilla couldn't find parent of bug %d"), (int)original_bug_id);
- }
-
- log("Bug %d is a duplicate, using parent bug %d", bug_id, (int)bz.bug_dup_id);
- bug_id = bz.bug_dup_id;
- bug_info_destroy(&bz);
- bug_info_init(&bz);
-
- if (bz_server.get_bug_info(&bz, bug_id) == -1)
- {
- bug_info_destroy(&bz);
- if (bz_server.env.fault_occurred)
- {
- throw_if_xml_fault_occurred(&bz_server.env);
- }
- error_msg_and_die(_("get_bug_info() failed. Could not collect all mandatory information"));
- }
-
- // found a bug which is not CLOSED as DUPLICATE
- if (bz.bug_dup_id == -1)
- break;
- }
- }
-
- if (strcmp(bz.bug_status, "CLOSED") != 0)
- {
- int status = 0;
- if ((strcmp(bz.bug_reporter, login) != 0)
- && (g_list_find(bz.bug_cc, login)))
- {
- log(_("Add %s to CC list"), login);
- status = bz_server.add_plus_one_cc(bug_id, login);
- }
-
- if (status == -1)
- {
- bug_info_destroy(&bz);
- throw_if_xml_fault_occurred(&bz_server.env);
- }
-
- char *dsc = make_description_comment(problem_data);
- if (dsc)
- {
- const char* package = get_problem_item_content_or_NULL(problem_data, FILENAME_PACKAGE);
- const char* release = get_problem_item_content_or_NULL(problem_data, FILENAME_OS_RELEASE);
- if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */
- release = get_problem_item_content_or_NULL(problem_data, "release");
- const char* arch = get_problem_item_content_or_NULL(problem_data, FILENAME_ARCHITECTURE);
- const char* is_private = get_problem_item_content_or_NULL(problem_data, "is_private");
-
- char *full_dsc = xasprintf("Package: %s\n"
- "Architecture: %s\n"
- "OS Release: %s\n"
- "%s", package, arch, release, dsc
- );
-
- log(_("Adding new comment to bug %d"), (int)bug_id);
-
- free(dsc);
-
- bool is_priv = is_private && string_to_bool(is_private);
- if (bz_server.add_comment(bug_id, full_dsc, is_priv) == -1)
- {
- free(full_dsc);
- bug_info_destroy(&bz);
- throw_xml_fault(&bz_server.env);
- }
- free(full_dsc);
- }
- }
-
- log(_("Logging out"));
- bz_server.logout();
-
- log("Status: %s%s%s %s/show_bug.cgi?id=%u",
- bz.bug_status,
- bz.bug_resolution ? " " : "",
- bz.bug_resolution ? bz.bug_resolution : "",
- bugzilla_url,
- (int)bug_id
- );
-
- dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (dd)
- {
- char *msg = xasprintf("Bugzilla: URL=%s/show_bug.cgi?id=%u", bugzilla_url, (int)bug_id);
- add_reported_to(dd, msg);
- free(msg);
- dd_close(dd);
- }
-
- free_problem_data(problem_data);
- bug_info_destroy(&bz);
-}
-
-int main(int argc, char **argv)
-{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
-
- map_string_h *settings = new_map_string();
- const char *dump_dir_name = ".";
- GList *conf_file = NULL;
-
- /* Can't keep these strings/structs static: _() doesn't support that */
- const char *program_usage_string = _(
- PROGNAME" [-v] -c CONFFILE -d DIR\n"
- "\n"
- "Reports problem to Bugzilla"
- );
- enum {
- OPT_v = 1 << 0,
- OPT_d = 1 << 1,
- OPT_c = 1 << 2,
- };
- /* Keep enum above and order of options below in sync! */
- struct options program_options[] = {
- OPT__VERBOSE(&g_verbose),
- OPT_STRING('d', NULL, &dump_dir_name, "DIR" , _("Dump directory")),
- OPT_LIST( 'c', NULL, &conf_file , "FILE", _("Configuration file (may be given many times)")),
- OPT_END()
- };
- /*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
-
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
-
- while (conf_file)
- {
- char *fn = (char *)conf_file->data;
- VERB1 log("Loading settings from '%s'", fn);
- load_conf_file(fn, settings, /*skip key w/o values:*/ true);
- VERB3 log("Loaded '%s'", fn);
- conf_file = g_list_remove(conf_file, fn);
- }
-
- VERB1 log("Initializing XML-RPC library");
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- xmlrpc_client_setup_global_const(&env);
- if (env.fault_occurred)
- error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
- xmlrpc_env_clean(&env);
-
- report_to_bugzilla(dump_dir_name, settings);
-
- free_map_string(settings);
- return 0;
-}
diff --git a/src/plugins/abrt-action-bugzilla.txt b/src/plugins/abrt-action-bugzilla.txt
new file mode 100644
index 00000000..313e5b19
--- /dev/null
+++ b/src/plugins/abrt-action-bugzilla.txt
@@ -0,0 +1,96 @@
+abrt-action-buzilla(1)
+====================
+
+NAME
+----
+abrt-action-bugzilla - Sends problem information to bugzilla.
+
+SYNOPSIS
+--------
+'abrt-action-bugzilla' [-v] [-c CONFFILE] -d DIR
+
+DESCRIPTION
+-----------
+The tool reads a problem dump direcotry. Firstly, the tool is trying to find
+duplication of bug. If duplication is 'not' found, then a new bug is created.
+Otherwise if duplication 'is' found and bug is closed as duplication of the
+other bug, than, so called, 'hoping' begin. It means, that tool is going to try
+track the origin bug.
+
+Example of bug stages are:
+------------
+CLOSED DUPLICATE -> CLOSED DUPLICATE -> NEW
+------------
+Third one is the origin of the same problem. The tool adds a new comment to bug,
+logouts from bugzilla and return link to bug.
+
+Properties of bugzilla can be specified in a configuration file,
+and via environment variables.
+
+Configuration file
+~~~~~~~~~~~~~~~~~~
+Configuration file contains entries in a format "Option = Value".
+
+The options are:
+
+'Login'::
+ Login to Bugzilla account.
+
+'Password'::
+ Password to Bugzilla account.
+
+'BugzillaURL'::
+ Bugzilla http address. (default: https://bugzilla.redht.com)
+
+'SSLVerify'::
+ Use yes/true/on/1 to verify Bugzilla ssl certificate. (default: yes)
+
+Integration with ABRT events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+'abrt-action-bugzilla' can be used as a reporter, to allow users report
+problems to bugzilla when they decide to do it. This usage is
+pre-configured in /etc/abrt/events.d/ccpp_events.conf and
+/etc/abrt/abrt_events.conf.
+
+For python problems (/etc/abrt/abrt_events.conf)
+------------
+EVENT=report_Bugzilla analyzer=Python
+ abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf
+------------
+
+For C/C++ problems (/etc/abrt/events.d/ccpp_events.conf)
+------------
+EVENT=report_Bugzilla analyzer=CCpp
+ abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf
+------------
+
+OPTIONS
+-------
+-d DIR::
+ Path to dump directory.
+
+-c CONFFILE::
+ Path to configration file. When used in ABRT event system, the file
+ contains site-wide configuration. Users can change the values via
+ environment variables.
+
+ENVIRONMENT VARIABLES
+---------------------
+Environment variables take precedence over values provided in
+the configuration file.
+
+'Bugzilla_Login'::
+ Login to Bugzilla account.
+
+'Bugzilla_Password'::
+ Password to Bugzilla account.
+
+'Bugzilla_BugzillaURL'::
+ Bugzilla http address. (default: https://bugzilla.redht.com)
+
+'Bugzilla_SSLVerify'::
+ Use yes/true/on/1 to verify Bugzilla ssl certificate. (default: yes)
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/plugins/abrt-action-generate-backtrace.c b/src/plugins/abrt-action-generate-backtrace.c
index 561b2165..1d06871a 100644
--- a/src/plugins/abrt-action-generate-backtrace.c
+++ b/src/plugins/abrt-action-generate-backtrace.c
@@ -23,8 +23,6 @@
#include "parse_options.h"
-#define PROGNAME "abrt-action-generate-backtrace"
-
#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di"
static const char *dump_dir_name = ".";
@@ -232,17 +230,15 @@ static char *get_backtrace(struct dump_dir *dd)
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
char *i_opt = NULL;
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [options] -d DIR\n"
+ "\b [options] -d DIR\n"
"\n"
- "Generates and saves backtrace for coredump in dump directory DIR"
+ "Analyzes coredump in dump directory DIR, generates and saves backtrace"
);
enum {
OPT_v = 1 << 0,
@@ -255,16 +251,12 @@ int main(int argc, char **argv)
OPT__VERBOSE(&g_verbose),
OPT_STRING( 'd', NULL, &dump_dir_name , "DIR" , _("Dump directory")),
OPT_STRING( 'i', NULL, &i_opt , "DIR1[:DIR2]...", _("Additional debuginfo directories")),
- OPT_INTEGER('t', NULL, &exec_timeout_sec, _("Kill gdb if it runs for more than N seconds")),
+ OPT_INTEGER('t', NULL, &exec_timeout_sec, _("Kill gdb if it runs for more than NUM seconds")),
OPT_END()
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
if (i_opt)
{
diff --git a/src/plugins/abrt-action-generate-backtrace.txt b/src/plugins/abrt-action-generate-backtrace.txt
new file mode 100644
index 00000000..fb90f158
--- /dev/null
+++ b/src/plugins/abrt-action-generate-backtrace.txt
@@ -0,0 +1,47 @@
+abrt-action-generate-backtrace(1)
+=================================
+
+NAME
+----
+abrt-action-generate-backtrace - Analyzes coredump, generates and saves backtrace.
+
+SYNOPSIS
+--------
+'abrt-action-generate-backtrace' [-v] [-d DIR] [-i DIR1[:DIR2]...] [-t NUM]
+
+DESCRIPTION
+-----------
+This tool runs gdb(1) on a file named 'coredump' in dump directory DIR.
+gdb(1) generates backtrace and other diagnostic information about the state
+of the application at the moment when coredump was generated.
+Then the tool saves it as new element 'backtrace' in this dump directory.
+
+Integration with ABRT events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+'abrt-action-generate-backtrace' can be used as an analyzer for
+application crashes which dump core.
+
+Example usage in abrt_event.conf:
+
+------------
+EVENT=analyze analyzer=CCpp
+ abrt-action-generate-backtrace
+------------
+
+OPTIONS
+-------
+-d DIR::
+ Path to dump directory.
+
+-v::
+ Be more verbose. Can be given multiple times.
+
+-i DIR1[:DIR2]::
+ Additional debuginfo directories
+
+-t NUM::
+ Kill gdb if it runs for more than NUM seconds
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/plugins/abrt-action-install-debuginfo.c b/src/plugins/abrt-action-install-debuginfo.c
index 357762ee..112620b4 100644
--- a/src/plugins/abrt-action-install-debuginfo.c
+++ b/src/plugins/abrt-action-install-debuginfo.c
@@ -21,8 +21,7 @@
#include <stdlib.h>
#include <string.h>
-// TODO: honor configure --prefix here:
-#define EXECUTABLE "/usr/bin/abrt-action-install-debuginfo.py"
+#define EXECUTABLE "abrt-action-install-debuginfo.py"
static void error_msg_and_die(const char *msg, const char *arg)
{
@@ -30,7 +29,7 @@ static void error_msg_and_die(const char *msg, const char *arg)
if (arg)
{
write(2, " '", 2);
- write(2, msg, strlen(msg));
+ write(2, arg, strlen(arg));
write(2, "'", 1);
}
write(2, "\n", 1);
@@ -47,7 +46,7 @@ int main(int argc, char **argv)
{
/*
* We disallow passing of arguments which point to writable dirs.
- * This way, the script will always use default arguments.
+ * This way, the script will always use default values for these arguments.
*/
char **pp = argv;
char *arg;
@@ -57,7 +56,7 @@ int main(int argc, char **argv)
error_msg_and_die("bad option", arg);
if (strncmp(arg, "--tmpdir", 8) == 0)
error_msg_and_die("bad option", arg);
- if (strncmp(arg, "-i", 2) == 0)
+ if (strncmp(arg, "--ids", 5) == 0)
error_msg_and_die("bad option", arg);
}
@@ -70,12 +69,35 @@ int main(int argc, char **argv)
setregid(g, g);
uid_t u = geteuid();
if (u != getuid())
+ {
setreuid(u, u);
+ /* We are suid'ed! */
+ /* Prevent malicious user from messing up with suid'ed process: */
+ /* Set safe PATH */
+// TODO: honor configure --prefix here by adding it to PATH
+// (otherwise abrt-action-install-debuginfo.py would fail to spawn abrt-action-trim-files):
+ if (u == 0)
+ putenv((char*) "PATH=/usr/sbin:/sbin:/usr/bin:/bin");
+ else
+ putenv((char*) "PATH=/usr/bin:/bin");
+ /* Clear dangerous stuff from env */
+ static const char forbid[] =
+ "LD_LIBRARY_PATH" "\0"
+ "LD_PRELOAD" "\0"
+ "LD_TRACE_LOADED_OBJECTS" "\0"
+ "LD_BIND_NOW" "\0"
+ "LD_AOUT_LIBRARY_PATH" "\0"
+ "LD_AOUT_PRELOAD" "\0"
+ "LD_NOWARN" "\0"
+ "LD_KEEPDIR" "\0"
+ ;
+ const char *p = forbid;
+ do {
+ unsetenv(p);
+ p += strlen(p) + 1;
+ } while (*p);
+ }
- /* We use full path, and execv instead of execvp in order to
- * disallow user to execute his own abrt-action-install-debuginfo.py
- * in his dir by setting up corresponding malicious $PATH.
- */
- execv(EXECUTABLE, argv);
+ execvp(EXECUTABLE, argv);
error_msg_and_die("Can't execute", EXECUTABLE);
}
diff --git a/src/plugins/abrt-action-install-debuginfo.py b/src/plugins/abrt-action-install-debuginfo.py
index ab131f7c..e15fc12b 100755
--- a/src/plugins/abrt-action-install-debuginfo.py
+++ b/src/plugins/abrt-action-install-debuginfo.py
@@ -1,8 +1,10 @@
#! /usr/bin/python -u
# -*- coding: utf-8 -*-
-
# WARNING: python -u means unbuffered I/O without it the messages are
-# passed to the parent asynchronously which looks bad in clients..
+# passed to the parent asynchronously which looks bad in clients.
+
+PROGNAME = "abrt-action-install-debuginfo.py"
+
from subprocess import Popen, PIPE
import sys
import os
@@ -35,9 +37,26 @@ def init_gettext():
gettext.textdomain(GETTEXT_PROGNAME)
-def error_msg_and_die(s):
- sys.stderr.write("%s\n" % s)
- os.exit(1)
+verbose = 0
+def log(fmt, *args):
+ sys.stderr.write("%s\n" % (fmt % args))
+
+def log1(fmt, *args):
+ """ prints log message if verbosity >= 1 """
+ if verbose >= 1:
+ sys.stderr.write("%s\n" % (fmt % args))
+
+def log2(fmt, *args):
+ """ prints log message if verbosity >= 2 """
+ if verbose >= 2:
+ sys.stderr.write("%s\n" % (fmt % args))
+
+def error_msg(fmt, *args):
+ sys.stderr.write("%s\n" % (fmt % args))
+
+def error_msg_and_die(fmt, *args):
+ sys.stderr.write("%s\n" % (fmt % args))
+ sys.exit(1)
old_stdout = -1
@@ -60,10 +79,10 @@ def ask_yes_no(prompt, retries=4):
response = raw_input(prompt)
except EOFError:
log1("got eof, probably executed from helper, assuming - yes")
- response = 'y'
- if response in ('y', 'Y'):
return True
- if response in ('n', 'N', ''):
+ if response in (_("y")): # for translators -> y/Y as yes
+ return True
+ if response in ("", _("n")): # for translators -> N/n as no
return False
retries = retries - 1
if retries < 0:
@@ -76,8 +95,8 @@ def ask_yes_no(prompt, retries=4):
def unpack_rpm(package_nevra, files, tmp_dir, destdir, keeprpm):
package_name = package_nevra + ".rpm"
package_full_path = tmp_dir + "/" + package_name
- log1("Extracting %s to %s" % (package_full_path, destdir))
- log2(files)
+ log1("Extracting %s to %s", package_full_path, destdir)
+ log2("%s", files)
print _("Extracting cpio from %s") % (package_full_path)
unpacked_cpio_path = tmp_dir + "/unpacked.cpio"
try:
@@ -92,7 +111,7 @@ def unpack_rpm(package_nevra, files, tmp_dir, destdir, keeprpm):
if retcode == 0:
log1("cpio written OK")
if not keeprpm:
- log1("keeprpms = False, removing %s" % package_full_path)
+ log1("keeprpms = False, removing %s", package_full_path)
#print _("Removing temporary rpm file")
os.unlink(package_full_path)
else:
@@ -106,7 +125,7 @@ def unpack_rpm(package_nevra, files, tmp_dir, destdir, keeprpm):
unpacked_cpio = open(unpacked_cpio_path, 'rb')
print _("Caching files from %s made from %s") % ("unpacked.cpio", package_name)
- cpio = Popen(["cpio","-i", "-d", "--quiet"],
+ cpio = Popen(["cpio", "-idu", "--quiet"],
stdin=unpacked_cpio, cwd=destdir, bufsize=-1)
retcode = cpio.wait()
@@ -208,7 +227,7 @@ class DebugInfoDownload(YumBase):
#print repo
repo.enable()
rid = self.repos.enableRepo(repo.id)
- log1("enabled repo %s" % rid)
+ log1("enabled repo %s", rid)
setattr(repo, "skip_if_unavailable", True)
self.repos.doSetup()
@@ -241,7 +260,7 @@ class DebugInfoDownload(YumBase):
not_found = []
package_files_dict = {}
for debuginfo_path in files:
- log2("yum whatprovides %s" % debuginfo_path)
+ log2("yum whatprovides %s", debuginfo_path)
pkg = self.pkgSack.searchFiles(debuginfo_path)
# sometimes one file is provided by more rpms, we can use either of
# them, so let's use the first match
@@ -254,9 +273,9 @@ class DebugInfoDownload(YumBase):
installed_size += float(pkg[0].installedsize)
total_pkgs += 1
- log2("found pkg for %s: %s" % (debuginfo_path, pkg[0]))
+ log2("found pkg for %s: %s", debuginfo_path, pkg[0])
else:
- log2("not found pkg for %s" % debuginfo_path)
+ log2("not found pkg for %s", debuginfo_path)
not_found.append(debuginfo_path)
# connect our progress update callback
@@ -317,17 +336,6 @@ class DebugInfoDownload(YumBase):
except OSError:
print _("Can't remove %s, probably contains an error log") % self.tmpdir
-verbose = 0
-def log1(message):
- """ prints log message if verbosity > 0 """
- if verbose > 0:
- print "LOG1:", message
-
-def log2(message):
- """ prints log message if verbosity > 1 """
- if verbose > 1:
- print "LOG2:", message
-
def build_ids_to_path(build_ids):
"""
build_id1=${build_id:0:2}
@@ -344,14 +352,14 @@ def filter_installed_debuginfos(build_ids, cache_dir):
files = build_ids_to_path(build_ids)
for debuginfo_path in files:
cache_debuginfo_path = cache_dir + debuginfo_path
- log2("checking path: %s" % debuginfo_path)
+ log2("checking path: %s", debuginfo_path)
if os.path.exists(debuginfo_path):
- log2("found: %s" % debuginfo_path)
+ log2("found: %s", debuginfo_path)
continue
if os.path.exists(cache_debuginfo_path):
- log2("found: %s" % cache_debuginfo_path)
+ log2("found: %s", cache_debuginfo_path)
continue
- log2("not found: %s" % (cache_debuginfo_path))
+ log2("not found: %s", cache_debuginfo_path)
missing_di.append(debuginfo_path)
return missing_di
@@ -380,6 +388,7 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, sigint_handler)
fbuild_ids = "build_ids"
cachedir = None
+ size_mb = 4096
tmpdir = None
keeprpms = False
noninteractive = False
@@ -395,12 +404,29 @@ if __name__ == "__main__":
except:
pass
- progname = os.path.basename(sys.argv[0])
- help_text = _("Usage: %s [-i <build_ids_file>] [--tmpdir=TMPDIR] "
- "[--cache=CACHEDIR] [--keeprpms]") % progname
+ PROGNAME = os.path.basename(sys.argv[0])
+ # ____________________________________________________________________________________ 7
+ # ______01234567890123456789012345678901234567890123456789012345678901234567890123456789
+ help_text = _(
+ "Usage: %s [-vy] [--ids=BUILD_IDS_FILE]\n"
+ " [--tmpdir=TMPDIR] [--cache=CACHEDIR] [--size_mb=SIZE]\n"
+ "\n"
+ "Installs debuginfos for all build-ids listed in BUILD_IDS_FILE\n"
+ "to CACHEDIR, using TMPDIR as temporary staging area.\n"
+ "Old files in CACHEDIR are deleted until it is smaller than SIZE.\n"
+ "\n"
+ " -v Be verbose\n"
+ " -y Noninteractive, assume 'Yes' to all questions\n"
+ " --ids Default: build_ids\n"
+ " --tmpdir Default: /tmp/abrt-tmp-debuginfo-RANDOM_SUFFIX\n"
+ " --cache Default: /var/cache/abrt-di\n"
+ " --size_mb Default: 4096\n"
+ # --keeprpms is not documented yet because it's a NOP so far
+ ) % PROGNAME
+
try:
- opts, args = getopt.getopt(sys.argv[1:], "vyhi:", ["help", "cache=",
- "tmpdir=","keeprpms"])
+ opts, args = getopt.getopt(sys.argv[1:], "vyh",
+ ["help", "ids=", "cache=", "size_mb=", "tmpdir=", "keeprpms"])
except getopt.GetoptError, err:
print str(err) # prints something like "option -a not recognized"
exit(RETURN_FAILURE)
@@ -413,13 +439,18 @@ if __name__ == "__main__":
verbose += 1
elif opt == "-y":
noninteractive = True
- elif opt == "-i":
+ elif opt == "--ids":
fbuild_ids = arg
- elif opt in ("--cache"):
+ elif opt == "--cache":
cachedir = arg
- elif opt in ("--tmpdir"):
+ elif opt == "--size_mb":
+ try:
+ size_mb = int(arg)
+ except:
+ pass
+ elif opt == "--tmpdir":
tmpdir = arg
- elif opt in ("--keeprpms"):
+ elif opt == "--keeprpms":
keeprpms = True
if not cachedir:
@@ -440,15 +471,37 @@ if __name__ == "__main__":
if not b_ids:
exit(RETURN_FAILURE)
+ # Delete oldest/biggest files from cachedir.
+ # (Note that we need to do it before we check for missing debuginfos)
+ #
+ # We can do it as a separate step in abrt_event.conf, but this
+ # would require setuid'ing abrt-action-trim-files to abrt:abrt.
+ # Since we (abrt-action-install-debuginfo) are already running setuid,
+ # it makes sense to NOT setuid abrt-action-trim-files too,
+ # but instead run it as our child:
+ sys.stdout.flush()
+ try:
+ pid = os.fork()
+ if pid == 0:
+ log1("abrt-action-trim-files -f %um:%s", size_mb, cachedir);
+ os.execlp("abrt-action-trim-files", "abrt-action-trim-files", "-f", "%um:%s" % (size_mb, cachedir));
+ if pid > 0:
+ os.waitpid(pid, 0);
+ except Exception, e:
+ error_msg("Can't execute abrt-action-trim-files: %s", e);
+
missing = filter_installed_debuginfos(b_ids, cachedir)
if missing:
- log2(missing)
+ log2("%s", missing)
print _("Coredump references %u debuginfo files, %u of them are not installed") % (len(b_ids), len(missing))
+
+ # TODO: should we pass keep_rpms=keeprpms to DebugInfoDownload here??
downloader = DebugInfoDownload(cache=cachedir, tmp=tmpdir)
try:
result = downloader.download(missing)
except Exception, ex:
error_msg_and_die("Can't download debuginfos: %s", ex)
+
missing = filter_installed_debuginfos(b_ids, cachedir)
for bid in missing:
print _("Missing debuginfo file: %s") % bid
diff --git a/src/plugins/abrt-action-kerneloops.c b/src/plugins/abrt-action-kerneloops.c
index 7b054a2e..99b2fea9 100644
--- a/src/plugins/abrt-action-kerneloops.c
+++ b/src/plugins/abrt-action-kerneloops.c
@@ -21,8 +21,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-kerneloops"
-
/* helpers */
static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream)
{
@@ -129,9 +127,7 @@ static void report_to_kerneloops(
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
map_string_h *settings = new_map_string();
const char *dump_dir_name = ".";
@@ -139,7 +135,7 @@ int main(int argc, char **argv)
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] [-c CONFFILE]... -d DIR\n"
+ "\b [-v] [-c CONFFILE]... -d DIR\n"
"\n"
"Reports kernel oops to kerneloops.org (or similar) site"
);
@@ -157,11 +153,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
while (conf_file)
{
diff --git a/src/plugins/abrt-action-list-dsos.py b/src/plugins/abrt-action-list-dsos.py
index 8b8a06ab..81a99276 100755
--- a/src/plugins/abrt-action-list-dsos.py
+++ b/src/plugins/abrt-action-list-dsos.py
@@ -7,13 +7,6 @@ import os
import getopt
import rpm
-GETTEXT_PROGNAME = "abrt"
-import locale
-import gettext
-
-_ = lambda x: gettext.lgettext(x)
-
-
def log(s):
sys.stderr.write("%s\n" % s)
@@ -22,26 +15,27 @@ def error_msg(s):
def error_msg_and_die(s):
sys.stderr.write("%s\n" % s)
- os.exit(1)
+ sys.exit(1)
def xopen(name, mode):
try:
r = open(name, mode)
except IOError, e:
- error_msg_and_die("Can't open '%s': %s" % (name, e));
+ error_msg_and_die("Can't open '%s': %s" % (name, e))
return r
def parse_maps(maps_path):
try:
f = xopen(maps_path, "r")
- return [x.strip()[x.find('/'):] for x in f.readlines() if x.find('/') > -1]
+ # set() -> uniqifies the list of filenames
+ return set([x.strip()[x.find('/'):] for x in f.readlines() if x.find('/') > -1])
except IOError, e:
- error_msg_and_die("Can't read '%s': %s" % (name, e));
+ error_msg_and_die("Can't read '%s': %s" % (maps_path, e))
if __name__ == "__main__":
progname = os.path.basename(sys.argv[0])
- help_text = _("Usage: %s [-o OUTFILE] -m PROC_PID_MAP_FILE") % progname
+ help_text = ("Usage: %s [-o OUTFILE] -m PROC_PID_MAP_FILE") % progname
try:
opts, args = getopt.getopt(sys.argv[1:], "o:m:h", ["help"])
except getopt.GetoptError, err:
@@ -63,7 +57,7 @@ if __name__ == "__main__":
memfile = arg
if not memfile:
- error_msg(_("MAP_FILE is not specified"))
+ error_msg("MAP_FILE is not specified")
error_msg_and_die(help_text)
try:
@@ -81,10 +75,15 @@ if __name__ == "__main__":
if outname:
outfile = xopen(outname, "w")
outname = None
- outfile.write("%s %s (%s)\n" % (path, h[rpm.RPMTAG_NEVRA], h[rpm.RPMTAG_VENDOR]))
+ outfile.write("%s %s (%s) %s\n" %
+ (path,
+ h[rpm.RPMTAG_NEVRA],
+ h[rpm.RPMTAG_VENDOR],
+ h[rpm.RPMTAG_INSTALLTIME])
+ )
except Exception, ex:
- error_msg_and_die("Can't get the DSO list: %s", ex)
+ error_msg_and_die("Can't get the DSO list: %s" % ex)
outfile.close()
except:
diff --git a/src/plugins/abrt-action-list-dsos.txt b/src/plugins/abrt-action-list-dsos.txt
new file mode 100644
index 00000000..18d10708
--- /dev/null
+++ b/src/plugins/abrt-action-list-dsos.txt
@@ -0,0 +1,44 @@
+abrt-action-list-dsos(1)
+======================
+
+NAME
+----
+abrt-action-list-dsos - Prints out DSO from mapped memory regions.
+
+SYNOPSIS
+--------
+'abrt-action-list-dsos' [-o OUTFILE] -m PROC_PID_MAP_FILE
+
+DESCRIPTION
+-----------
+The tool reads a file containing the mapped memory regions.
+Output is printed to 'stdout' or 'file'.
+
+Output format:
+
+------------
+%p %n %v %i
+------------
+where
+
+'%p'::
+ path to library or binary file, which is mapped in memory region
+'%n'::
+ name, version, release, architecture of package, where '%p' belongs
+'%v'::
+ vendor of package
+'%i'::
+ installation time
+
+OPTIONS
+-------
+-o OUTFILE::
+ Output file, if not specified, it is printed to 'stdout'
+
+-m PROC_PID_MAP_FILE::
+ File containing the mapped memory regions
+
+AUTHORS
+-------
+* ABRT team
+
diff --git a/src/plugins/abrt-action-mailx.c b/src/plugins/abrt-action-mailx.c
index a4ee31cd..21180854 100644
--- a/src/plugins/abrt-action-mailx.c
+++ b/src/plugins/abrt-action-mailx.c
@@ -20,8 +20,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-mailx"
-
static void exec_and_feed_input(const char* text, char **args)
{
int pipein[2];
@@ -131,18 +129,16 @@ static void create_and_send_email(
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
const char *dump_dir_name = ".";
const char *conf_file = NULL;
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] -d DIR [-c CONFFILE]\n"
+ "\b [-v] -d DIR [-c CONFFILE]\n"
"\n"
- "Sends compressed tarball of dump directory DIR via email"
+ "Sends contents of a dump directory DIR via email"
);
enum {
OPT_v = 1 << 0,
@@ -158,11 +154,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
map_string_h *settings = new_map_string();
if (conf_file)
diff --git a/src/plugins/abrt-action-mailx.txt b/src/plugins/abrt-action-mailx.txt
new file mode 100644
index 00000000..a12c2bf1
--- /dev/null
+++ b/src/plugins/abrt-action-mailx.txt
@@ -0,0 +1,91 @@
+abrt-action-mailx(1)
+====================
+
+NAME
+----
+abrt-action-mailx - Sends contents of a dump directory via email.
+
+SYNOPSIS
+--------
+'abrt-action-mailx' [-v] -d DIR [-c CONFFILE]
+
+DESCRIPTION
+-----------
+The tool reads a problem dump directory, composes an email message
+from the directory contents, and uses mailx to send the message to
+specified recipient.
+
+Properties of email messages can be specified in a configuration file,
+and via environment variables.
+
+Configuration file
+~~~~~~~~~~~~~~~~~~
+Configuration file contains entries in a format "Option = Value".
+
+The options are:
+
+'Subject'::
+ The subject of the email message.
+
+'EmailFrom'::
+ The sender of the email message.
+
+'EmailTo'::
+ The recipient of the email message.
+
+'SendBinaryData'::
+ Use yes/true/on/1 to attach all binary files from the dump
+ directory to the email. This can cause the emails to be very
+ large.
+
+Integration with ABRT events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+'abrt-action-mailx' can be used as a reporter, to allow users report
+problems via email when they decide to do it. This usage is
+pre-configured in /etc/abrt/events.d/mailx_events.conf:
+
+------------
+EVENT=report_Mailx abrt-action-mailx
+------------
+
+It can also be used to notify administrator automatically when a
+problem happens. When this is desired, modify the event configuration
+file to run the tool on the 'post-create' event:
+
+------------
+EVENT=post-create abrt-action-mailx
+------------
+
+OPTIONS
+-------
+-d DIR::
+ Path to dump directory.
+
+-c CONFFILE::
+ Path to configration file. When used in ABRT event system, the file
+ contains site-wide configuration. Users can change the values via
+ environment variables.
+
+ENVIRONMENT VARIABLES
+---------------------
+Environment variables take precedence over values provided in
+the configuration file.
+
+'Mailx_Subject'::
+ Subject of the email message.
+
+'Mailx_EmailFrom'::
+ Sender of the email message.
+
+'Mailx_EmailTo'::
+ Recipient of the email message. If nor the environment variable
+ nor the corresponding option is defined, the message is send to
+ "root@localhost".
+
+'Mailx_SendBinaryData'::
+ Use yes/true/on/1 to attach all binary files from the dump
+ directory to the email.
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/plugins/abrt-action-print.c b/src/plugins/abrt-action-print.c
index f76abf86..d433fa52 100644
--- a/src/plugins/abrt-action-print.c
+++ b/src/plugins/abrt-action-print.c
@@ -21,8 +21,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-print"
-
static const char *dump_dir_name = ".";
static const char *output_file = NULL;
static const char *append = "no";
@@ -30,13 +28,11 @@ static const char *open_mode = "w";
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] -d DIR [-o FILE] [-a yes/no]\n"
+ "\b [-v] -d DIR [-o FILE] [-a yes/no] [-r]\n"
"\n"
"Prints problem information to standard output or FILE"
);
@@ -58,11 +54,7 @@ int main(int argc, char **argv)
};
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
if (output_file)
{
diff --git a/src/plugins/abrt-action-print.txt b/src/plugins/abrt-action-print.txt
new file mode 100644
index 00000000..200ea671
--- /dev/null
+++ b/src/plugins/abrt-action-print.txt
@@ -0,0 +1,63 @@
+abrt-action-print(1)
+====================
+
+NAME
+----
+abrt-action-print - Prints problem information to standard output or FILE.
+
+SYNOPSIS
+--------
+'abrt-action-print' [-v] [-d DIR] [-o FILE] [-a yes/no] [-r]
+
+DESCRIPTION
+-----------
+The tool reads dump directory DIR and prints its text representation
+to stdout or to a specified FILE.
+
+Integration with ABRT events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+'abrt-action-print' can be used as a reporter, to allow users
+to report problems by writinf them to a file. Example:
+
+------------
+EVENT=report abrt-action-print -o "${Log_File:-/tmp/abrt.log}"
+------------
+
+OPTIONS
+-------
+-d DIR::
+ Path to dump directory.
+
+-v::
+ Be more verbose. Can be given multiple times.
+
+-o FILE::
+ Output file
+
+-a yes/no::
+ If -o FILE is specified, controls whether FILE is appended to, or overwritten.
+
+-r::
+ Add a recor to 'reported_to' in DIR which specifies that this problem
+ was reported. Some tools use this to differentiate between problems
+ which were and weren't yet reported.
+
+Output format
+~~~~~~~~~~~~~
+The output is designed to be machine-parseable. The elements which have only
+one line are printed in the form
+
+ NAME:<whitespace>VALUE
+
+Elements which have more than one line are printed in the form
+
+ NAME:
+ :LINE1
+ :LINE2
+ :LINE3
+
+Output may contain empty lines for better readability.
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/plugins/abrt-action-rhtsupport.c b/src/plugins/abrt-action-rhtsupport.c
index fbdc7f7e..4616be3f 100644
--- a/src/plugins/abrt-action-rhtsupport.c
+++ b/src/plugins/abrt-action-rhtsupport.c
@@ -24,8 +24,6 @@
#include "abrt_rh_support.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-rhtsupport"
-
static void report_to_rhtsupport(
const char *dump_dir_name,
map_string_h *settings)
@@ -266,9 +264,7 @@ static void report_to_rhtsupport(
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
map_string_h *settings = new_map_string();
const char *dump_dir_name = ".";
@@ -276,7 +272,7 @@ int main(int argc, char **argv)
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] -c CONFFILE -d DIR\n"
+ "\b [-v] -c CONFFILE -d DIR\n"
"\n"
"Reports a problem to RHTSupport"
);
@@ -294,11 +290,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
while (conf_file)
{
diff --git a/src/plugins/abrt-action-trim-files.c b/src/plugins/abrt-action-trim-files.c
index dd7366ed..9f15038c 100644
--- a/src/plugins/abrt-action-trim-files.c
+++ b/src/plugins/abrt-action-trim-files.c
@@ -19,8 +19,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-trim-files"
-
static double get_dir_size(const char *dirname,
char **worst_file,
double *worst_file_size)
@@ -141,9 +139,7 @@ static void delete_files(gpointer data, gpointer user_data_unused)
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
GList *dir_list = NULL;
GList *file_list = NULL;
@@ -151,7 +147,7 @@ int main(int argc, char **argv)
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] [-d SIZE:DIR]... [-f SIZE:DIR]... [-p DIR]\n"
+ "\b [-v] [-d SIZE:DIR]... [-f SIZE:DIR]... [-p DIR]\n"
"\n"
"Deletes dump dirs (-d) or files (-f) in DIRs until they are smaller than SIZE"
);
@@ -169,17 +165,12 @@ int main(int argc, char **argv)
OPT_STRING('p', NULL, &preserve , "DIR" , _("Preserve this dump dir")),
OPT_END()
};
-
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
argv += optind;
if (argv[0] || !(dir_list || file_list))
show_usage_and_die(program_usage_string, program_options);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
g_list_foreach(dir_list, delete_dirs, preserve);
g_list_foreach(file_list, delete_files, NULL);
diff --git a/src/plugins/abrt-action-trim-files.txt b/src/plugins/abrt-action-trim-files.txt
new file mode 100644
index 00000000..a8d8a50e
--- /dev/null
+++ b/src/plugins/abrt-action-trim-files.txt
@@ -0,0 +1,30 @@
+abrt-action-trim-files(1)
+=========================
+
+NAME
+----
+abrt-action-trim-files - Deletes old dump directories or files
+in specified directories until they are smaller than specified size.
+
+SYNOPSIS
+--------
+'abrt-action-trim-files' [-v] [-d SIZE:DIR]... [-f SIZE:DIR]... [-p DIR]
+
+OPTIONS
+-------
+-v::
+ Be more verbose. Can be given multiple times.
+
+-d SIZE:DIR::
+ Delete dump directories in DIR
+ SIZE can be suffixed by k,m,g,t to specify kilo,mega,giga,terabytes.
+
+-f SIZE:DIR::
+ Delete files in DIR
+
+-p DIR::
+ Preserve this dump directory (never consider it for deletion)
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/plugins/abrt-action-upload.c b/src/plugins/abrt-action-upload.c
index 79347a18..06ae8b20 100644
--- a/src/plugins/abrt-action-upload.c
+++ b/src/plugins/abrt-action-upload.c
@@ -22,8 +22,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-action-upload"
-
//TODO: use this for better logging
#if 0
/* "read local data from a file" callback */
@@ -232,9 +230,7 @@ static int create_and_upload_archive(
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
const char *dump_dir_name = ".";
const char *conf_file = NULL;
@@ -242,7 +238,7 @@ int main(int argc, char **argv)
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-v] -d DIR [-c CONFFILE] [-u URL]\n"
+ "\b [-v] -d DIR [-c CONFFILE] [-u URL]\n"
"\n"
"Uploads compressed tarball of dump directory DIR"
);
@@ -262,11 +258,7 @@ int main(int argc, char **argv)
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
-
- char *pfx = getenv("ABRT_PROG_PREFIX");
- if (pfx && string_to_bool(pfx))
- msg_prefix = PROGNAME;
+ export_abrt_envvars(0);
map_string_h *settings = new_map_string();
if (url)
diff --git a/src/plugins/abrt-dump-oops.c b/src/plugins/abrt-dump-oops.c
index f716c3db..c2879caa 100644
--- a/src/plugins/abrt-dump-oops.c
+++ b/src/plugins/abrt-dump-oops.c
@@ -23,8 +23,6 @@
#include "abrtlib.h"
#include "parse_options.h"
-#define PROGNAME "abrt-dump-oops"
-
static bool world_readable_dump = false;
static const char *debug_dumps_dir = ".";
@@ -560,13 +558,11 @@ static unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
int main(int argc, char **argv)
{
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
+ abrt_init(argv);
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- PROGNAME" [-vsrowx] [-d DIR] FILE\n"
+ "\b [-vsrowx] [-d DIR] FILE\n"
"\n"
"Extract oops from syslog/dmesg file"
);
@@ -595,11 +591,11 @@ int main(int argc, char **argv)
};
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
- putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
- msg_prefix = PROGNAME;
- if ((opts & OPT_s)
- || getenv("ABRT_SYSLOG")
- ) {
+ export_abrt_envvars(0);
+
+ msg_prefix = g_progname;
+ if ((opts & OPT_s) || getenv("ABRT_SYSLOG"))
+ {
openlog(msg_prefix, 0, LOG_DAEMON);
logmode = LOGMODE_SYSLOG;
}
diff --git a/src/plugins/abrt-retrace-client.c b/src/plugins/abrt-retrace-client.c
index d49f9cfa..524fa186 100644
--- a/src/plugins/abrt-retrace-client.c
+++ b/src/plugins/abrt-retrace-client.c
@@ -25,6 +25,7 @@
#include <sslproto.h>
#include <sslerr.h>
#include <secerr.h>
+#include <secmod.h>
struct retrace_settings
{
@@ -38,7 +39,7 @@ struct retrace_settings
static const char *dump_dir_name = NULL;
static const char *coredump = NULL;
-static const char *url = "retrace01.fedoraproject.org";
+static const char *url = "retrace.fedoraproject.org";
static const char *required_files[] = { FILENAME_COREDUMP,
FILENAME_EXECUTABLE,
FILENAME_PACKAGE,
@@ -102,7 +103,7 @@ static int create_archive(bool unlink_temp)
xmove_fd(tar_xz_pipe[0], STDIN_FILENO);
xdup2(tempfd, STDOUT_FILENO);
execvp(xz_args[0], (char * const*)xz_args);
- perror_msg("Can't execute '%s'", xz_args[0]);
+ perror_msg("Can't execute '%s'", xz_args[0]);
}
close(tar_xz_pipe[0]);
@@ -129,7 +130,7 @@ static int create_archive(bool unlink_temp)
xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
xmove_fd(tar_xz_pipe[1], STDOUT_FILENO);
execvp(tar_args[0], (char * const*)tar_args);
- perror_msg("Can't execute '%s'", tar_args[0]);
+ perror_msg("Can't execute '%s'", tar_args[0]);
}
close(tar_xz_pipe[1]);
@@ -208,6 +209,28 @@ static const char *ssl_get_configdir()
return NULL;
}
+static PK11GenericObject *nss_load_cacert(const char *filename)
+{
+ PK11SlotInfo *slot = PK11_FindSlotByName("PEM Token #0");
+ if (!slot)
+ error_msg_and_die("Failed to get slot 'PEM Token #0': %d.", PORT_GetError());
+
+ CK_ATTRIBUTE template[4];
+ CK_OBJECT_CLASS class = CKO_CERTIFICATE;
+
+#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \
+ (x)->pValue=(v); (x)->ulValueLen = (l)
+
+ PK11_SETATTRS(&template[0], CKA_CLASS, &class, sizeof(class));
+ CK_BBOOL cktrue = CK_TRUE;
+ PK11_SETATTRS(&template[1], CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
+ PK11_SETATTRS(&template[2], CKA_LABEL, (unsigned char*)filename, strlen(filename)+1);
+ PK11_SETATTRS(&template[3], CKA_TRUST, &cktrue, sizeof(CK_BBOOL));
+ PK11GenericObject *cert = PK11_CreateGenericObject(slot, template, 4, PR_FALSE);
+ PK11_FreeSlot(slot);
+ return cert;
+}
+
static char *ssl_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
{
return NULL;
@@ -216,13 +239,6 @@ static char *ssl_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
static void ssl_connect(PRFileDesc **tcp_sock,
PRFileDesc **ssl_sock)
{
- const char *configdir = ssl_get_configdir();
- if (configdir)
- NSS_Initialize(configdir, "", "", "", NSS_INIT_READONLY);
- else
- NSS_NoDB_Init(NULL);
- PK11_SetPasswordFunc(ssl_get_password);
- NSS_SetDomesticPolicy();
*tcp_sock = PR_NewTCPSocket();
if (!*tcp_sock)
error_msg_and_die("Failed to create a TCP socket");
@@ -253,6 +269,7 @@ static void ssl_connect(PRFileDesc **tcp_sock,
error_msg_and_die("Failed to enable client handshake to SSL socket.");
if (SECSuccess != SSL_OptionSet(*ssl_sock, SSL_ENABLE_TLS, PR_TRUE))
error_msg_and_die("Failed to enable client handshake to SSL socket.");
+
sec_status = SSL_SetURL(*ssl_sock, url);
if (SECSuccess != sec_status)
{
@@ -322,14 +339,6 @@ static void ssl_disconnect(PRFileDesc *ssl_sock)
PRStatus pr_status = PR_Close(ssl_sock);
if (PR_SUCCESS != pr_status)
error_msg("Failed to close SSL socket.");
-
- SSL_ClearSessionCache();
-
- SECStatus sec_status = NSS_Shutdown();
- if (SECSuccess != sec_status)
- error_msg("Failed to shutdown NSS.");
-
- PR_Cleanup();
}
/**
@@ -366,10 +375,12 @@ static char *http_get_header_value(const char *message,
*/
static char *http_get_body(const char *message)
{
- char *body = strstr(message, "\r\n\r\n") + strlen("\r\n\r\n");
+ char *body = strstr(message, "\r\n\r\n");
if (!body)
return NULL;
+ body += strlen("\r\n\r\n");
+
while (*body == ' ')
++body;
@@ -642,11 +653,17 @@ static int create(bool delete_temp_archive,
close(tempfd);
/* Read the HTTP header of the response from server. */
char *http_response = tcp_read_response(tcp_sock);
+ char *http_body = http_get_body(http_response);
+ if (!http_body)
+ error_msg_and_die("Invalid response from server: missing HTTP message body.");
if (http_show_headers)
http_print_headers(stderr, http_response);
int response_code = http_get_response_code(http_response);
- if (response_code != 201)
- error_msg_and_die("Unexpected HTTP response from server: %d\n%s", response_code, http_response);
+ if (response_code == 500 || response_code == 507)
+ error_msg_and_die("There is a problem on the server side: %s", http_body);
+ else if (response_code != 201)
+ error_msg_and_die("Unexpected HTTP response from server: %d\n%s", response_code, http_body);
+ free(http_body);
*task_id = http_get_header_value(http_response, "X-Task-Id");
if (!*task_id)
error_msg_and_die("Invalid response from server: missing X-Task-Id");
@@ -670,6 +687,7 @@ static int run_create(bool delete_temp_archive)
return 0;
}
+/* Caller must free task_status and status_message */
static void status(const char *task_id,
const char *task_password,
char **task_status,
@@ -695,23 +713,21 @@ static void status(const char *task_id,
}
strbuf_free(http_request);
char *http_response = tcp_read_response(tcp_sock);
+ char *http_body = http_get_body(http_response);
+ if (!*http_body)
+ error_msg_and_die("Invalid response from server: missing body");
if (http_show_headers)
http_print_headers(stderr, http_response);
int response_code = http_get_response_code(http_response);
if (response_code != 200)
{
error_msg_and_die("Unexpected HTTP response from server: %d\n%s",
- response_code, http_response);
+ response_code, http_body);
}
*task_status = http_get_header_value(http_response, "X-Task-Status");
if (!*task_status)
error_msg_and_die("Invalid response from server: missing X-Task-Status");
- *status_message = http_get_body(http_response);
- if (!*status_message)
- {
- free(*task_status);
- error_msg_and_die("Invalid response from server: missing body");
- }
+ *status_message = http_body;
free(http_response);
ssl_disconnect(ssl_sock);
}
@@ -726,6 +742,7 @@ static void run_status(const char *task_id, const char *task_password)
free(status_message);
}
+/* Caller must free backtrace */
static void backtrace(const char *task_id, const char *task_password,
char **backtrace)
{
@@ -749,30 +766,18 @@ static void backtrace(const char *task_id, const char *task_password,
}
strbuf_free(http_request);
char *http_response = tcp_read_response(tcp_sock);
+ char *http_body = http_get_body(http_response);
+ if (!http_body)
+ error_msg_and_die("Invalid response from server: missing HTTP message body.");
if (http_show_headers)
http_print_headers(stderr, http_response);
int response_code = http_get_response_code(http_response);
if (response_code != 200)
{
error_msg_and_die("Unexpected HTTP response from server: %d\n%s",
- response_code, http_response);
- }
- char *headers_end = strstr(http_response, "\r\n\r\n");
- if (!headers_end)
- error_msg_and_die("Invalid response from server: missing HTTP message body.");
- int length = strlen(http_response) + (headers_end - http_response) + strlen("\r\n\r\n");
- /* Slightly more space than needed might be allocated, because
- * '\r' characters are not copied to the backtrace. */
- *backtrace = xmalloc(length);
- char *b = *backtrace;
- char *c;
- for (c = headers_end + strlen("\r\n\r\n"); *c; ++c)
- {
- if (*c == '\r')
- continue;
- *b = *c;
- ++b;
+ response_code, http_body);
}
+ *backtrace = http_body;
free(http_response);
ssl_disconnect(ssl_sock);
}
@@ -807,24 +812,19 @@ static void run_log(const char *task_id, const char *task_password)
}
strbuf_free(http_request);
char *http_response = tcp_read_response(tcp_sock);
+ char *http_body = http_get_body(http_response);
+ if (!http_body)
+ error_msg_and_die("Invalid response from server: missing HTTP message body.");
if (http_show_headers)
http_print_headers(stderr, http_response);
int response_code = http_get_response_code(http_response);
if (response_code != 200)
{
error_msg_and_die("Unexpected HTTP response from server: %d\n%s",
- response_code, http_response);
- }
- char *headers_end = strstr(http_response, "\r\n\r\n");
- char *c;
- if (!headers_end)
- error_msg_and_die("Invalid response from server: missing HTTP message body.");
- for (c = headers_end + 4; *c; ++c)
- {
- if (*c == '\r')
- continue;
- putc(*c, stdout);
+ response_code, http_body);
}
+ puts(http_body);
+ free(http_body);
free(http_response);
ssl_disconnect(ssl_sock);
}
@@ -844,6 +844,7 @@ static int run_batch(bool delete_temp_archive)
sleep(10);
status(task_id, task_password, &task_status, &status_message);
puts(status_message);
+ fflush(stdout);
}
if (0 == strcmp(task_status, "FINISHED_SUCCESS"))
{
@@ -875,6 +876,8 @@ static int run_batch(bool delete_temp_archive)
int main(int argc, char **argv)
{
+ abrt_init(argv);
+
const char *task_id = NULL;
const char *task_password = NULL;
@@ -922,9 +925,6 @@ int main(int argc, char **argv)
const char usage[] = "abrt-retrace-client <operation> [options]\n"
"Operations: create/status/backtrace/log/batch";
- char *env_verbose = getenv("ABRT_VERBOSE");
- if (env_verbose)
- g_verbose = atoi(env_verbose);
char *env_url = getenv("RETRACE_SERVER_URL");
if (env_url)
url = env_url;
@@ -942,17 +942,40 @@ int main(int argc, char **argv)
show_usage_and_die(usage, options);
ssl_allow_insecure = opts & OPT_insecure;
http_show_headers = opts & OPT_headers;
+
+ /* Initialize NSS */
+ SECStatus sec_status;
+ const char *configdir = ssl_get_configdir();
+ if (configdir)
+ sec_status = NSS_Initialize(configdir, "", "", "", NSS_INIT_READONLY);
+ else
+ sec_status = NSS_NoDB_Init(NULL);
+ if (SECSuccess != sec_status)
+ error_msg_and_die("Failed to initialize NSS.");
+
+ char *user_module = xstrdup("library=libnsspem.so name=PEM");
+ SECMODModule* mod = SECMOD_LoadUserModule(user_module, NULL, PR_FALSE);
+ free(user_module);
+ if (!mod || !mod->loaded)
+ error_msg_and_die("Failed to initialize security module.");
+
+ PK11GenericObject *cert = nss_load_cacert("/etc/pki/tls/certs/ca-bundle.crt");
+ PK11_SetPasswordFunc(ssl_get_password);
+ NSS_SetDomesticPolicy();
+
+ /* Run the desired operation. */
+ int result = 0;
if (0 == strcasecmp(operation, "create"))
{
if (!dump_dir_name && !coredump)
error_msg_and_die("Either dump directory or coredump is needed.");
- return run_create(0 == (opts & OPT_no_unlink));
+ result = run_create(0 == (opts & OPT_no_unlink));
}
else if (0 == strcasecmp(operation, "batch"))
{
if (!dump_dir_name && !coredump)
error_msg_and_die("Either dump directory or coredump is needed.");
- return run_batch(0 == (opts & OPT_no_unlink));
+ result = run_batch(0 == (opts & OPT_no_unlink));
}
else if (0 == strcasecmp(operation, "status"))
{
@@ -980,5 +1003,17 @@ int main(int argc, char **argv)
}
else
error_msg_and_die("Unknown operation: %s", operation);
- return 0;
+
+ /* Shutdown NSS. */
+ SSL_ClearSessionCache();
+ PK11_DestroyGenericObject(cert);
+ SECMOD_UnloadUserModule(mod);
+ SECMOD_DestroyModule(mod);
+ sec_status = NSS_Shutdown();
+ if (SECSuccess != sec_status)
+ error_msg("Failed to shutdown NSS.");
+
+ PR_Cleanup();
+
+ return result;
}
diff --git a/src/plugins/abrt_rh_support.c b/src/plugins/abrt_rh_support.c
index 9a48485b..b83f041e 100644
--- a/src/plugins/abrt_rh_support.c
+++ b/src/plugins/abrt_rh_support.c
@@ -421,7 +421,7 @@ send_report_to_new_case(const char* baseURL,
atch_state->http_resp_code,
errmsg ? ": " : "",
errmsg ? errmsg : ""
- );
+ );
break;
case 200:
diff --git a/src/plugins/analyze_LocalGDB.xml.in b/src/plugins/analyze_LocalGDB.xml.in
index 925f2c41..4f7ccce1 100644
--- a/src/plugins/analyze_LocalGDB.xml.in
+++ b/src/plugins/analyze_LocalGDB.xml.in
@@ -5,4 +5,5 @@
<_long-description>Needs to downloads debuginfo packages, which might take significant time, and take up disk space.
However, unlike RetraceServer, doesn't send coredump to remote machines.
</_long-description>
+ <creates-elements>backtrace</creates-elements>
</event>
diff --git a/src/plugins/analyze_RetraceServer.xml.in b/src/plugins/analyze_RetraceServer.xml.in
index f91bf763..d2072db5 100644
--- a/src/plugins/analyze_RetraceServer.xml.in
+++ b/src/plugins/analyze_RetraceServer.xml.in
@@ -6,10 +6,11 @@
Pros: no need for debuginfo downloads. Retrace server's database of debuginfos is more complete. Retrace server may generate better backtraces.
Cons: coredump you upload contains all the data from the crashed program, including your private data, if any.
</_long-description>
+ <creates-elements>backtrace</creates-elements>
<options>
<option type="text" name="RETRACE_SERVER_URL">
<_label>Retrace server URL</_label>
- <default-value>retrace01.fedoraproject.org</default-value>
+ <default-value>retrace.fedoraproject.org</default-value>
<allow-empty>no</allow-empty>
<_description>Address of the retrace server</_description>
</option>
diff --git a/src/plugins/analyze_xsession_errors.xml.in b/src/plugins/analyze_xsession_errors.xml.in
new file mode 100644
index 00000000..9f7a46bf
--- /dev/null
+++ b/src/plugins/analyze_xsession_errors.xml.in
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<event>
+ <name>Collect .xsession-errors</name>
+ <_description>Save relevant lines from ~/.xsession-errors file</_description>
+ <_long-description>
+ Scans through ~/.xsession-errors file and saves those lines which contain executable's name.
+ The result is saved as 'xsession_errors' element.
+ </_long-description>
+ <creates-elements>xsession_errors</creates-elements>
+</event>
diff --git a/src/plugins/ccpp_events.conf b/src/plugins/ccpp_events.conf
index 1e111f04..b56601e9 100644
--- a/src/plugins/ccpp_events.conf
+++ b/src/plugins/ccpp_events.conf
@@ -1,33 +1,37 @@
EVENT=post-create analyzer=CCpp
- abrt-action-analyze-c &&
- abrt-action-list-dsos.py -m maps -o dsos
+ abrt-action-analyze-c &&
+ abrt-action-list-dsos.py -m maps -o dsos &&
+ (
+ # Try to save relevant log lines.
+ # Can't do it as analyzer step, non-root can't read log.
+ # It's not an error if /var/log/messages isn't readable:
+ test -f /var/log/messages || exit 0
+ test -r /var/log/messages || exit 0
+ executable=`cat executable` &&
+ base_executable=${executable##*/} &&
+ grep -F -e "$base_executable" /var/log/messages | tail -999 >var_log_messages &&
+ echo "Element 'var_log_messages' saved"
+ )
+
+EVENT=analyze_xsession_errors analyzer=CCpp
+ test -f ~/.xsession-errors || { echo "No ~/.xsession-errors"; exit 1; }
+ test -r ~/.xsession-errors || { echo "Can't read ~/.xsession-errors"; exit 1; }
+ executable=`cat executable` &&
+ base_executable=${executable##*/} &&
+ grep -F -e "$base_executable" ~/.xsession-errors | tail -999 >xsession_errors &&
+ echo "Element 'xsession_errors' saved"
-# We run analyze_foo steps only if backtrace is empty (not yet generated):
# TODO: can we still specify additional directories to search for debuginfos,
# or was this ability lost with move to python installer?
-EVENT=analyze_LocalGDB analyzer=CCpp backtrace=
- abrt-action-trim-files -f 4096m:/var/cache/abrt-di &&
- abrt-action-analyze-core.py --core=coredump -o build_ids &&
- abrt-action-install-debuginfo &&
- abrt-action-generate-backtrace &&
- abrt-action-analyze-backtrace
-
-EVENT=analyze_RetraceServer analyzer=CCpp backtrace=
- abrt-retrace-client batch -k --dir "$DUMP_DIR" &&
- abrt-action-analyze-backtrace
-
-# Same as "analyze", but executed when user requests "refresh" in GUI
-# It doesn't check that backtrace is empty:
-EVENT=reanalyze_LocalGDB analyzer=CCpp
- abrt-action-trim-files -f 4096m:/var/cache/abrt-di &&
- abrt-action-analyze-core.py --core=coredump -o build_ids &&
- abrt-action-install-debuginfo &&
- abrt-action-generate-backtrace &&
- abrt-action-analyze-backtrace
+EVENT=analyze_LocalGDB analyzer=CCpp
+ abrt-action-analyze-core.py --core=coredump -o build_ids &&
+ abrt-action-install-debuginfo --size_mb=4096 &&
+ abrt-action-generate-backtrace &&
+ abrt-action-analyze-backtrace
-EVENT=reanalyze_RetraceServer analyzer=CCpp
- abrt-retrace-client batch -k --dir "$DUMP_DIR" &&
- abrt-action-analyze-backtrace
+EVENT=analyze_RetraceServer analyzer=CCpp
+ abrt-retrace-client batch --dir "$DUMP_DIR" &&
+ abrt-action-analyze-backtrace
EVENT=report_Bugzilla analyzer=CCpp
- abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf
+ abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf
diff --git a/src/plugins/rhbz.c b/src/plugins/rhbz.c
new file mode 100644
index 00000000..90587e5e
--- /dev/null
+++ b/src/plugins/rhbz.c
@@ -0,0 +1,482 @@
+/*
+ Copyright (C) 2011 ABRT team
+ Copyright (C) 2011 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 "rhbz.h"
+
+#define MAX_HOPS 5
+
+struct bug_info *new_bug_info()
+{
+ struct bug_info *bi = xzalloc(sizeof(struct bug_info));
+ bi->bi_dup_id = -1;
+
+ return bi;
+}
+
+void free_bug_info(struct bug_info *bi)
+{
+ if (!bi)
+ return;
+
+ free((void*)bi->bi_status);
+ free((void*)bi->bi_resolution);
+ free((void*)bi->bi_reporter);
+ free((void*)bi->bi_product);
+
+ list_free_with_free(bi->bi_cc_list);
+
+ bi->bi_status = NULL;
+ bi->bi_resolution = NULL;
+ bi->bi_reporter = NULL;
+ bi->bi_product = NULL;
+
+ bi->bi_cc_list = NULL;
+
+ free(bi);
+}
+
+void rhbz_login(struct abrt_xmlrpc *ax, const char* login, const char* passwd)
+{
+ xmlrpc_value* result = abrt_xmlrpc_call(ax, "User.login", "({s:s,s:s})",
+ "login", login, "password", passwd);
+
+//TODO: with URL like http://bugzilla.redhat.com (that is, with http: instead of https:)
+//we are getting this error:
+//Logging into Bugzilla at http://bugzilla.redhat.com
+//Can't login. Server said: HTTP response code is 301, not 200
+//But this is a 301 redirect! We _can_ follow it if we configure curl to understand that!
+ xmlrpc_DECREF(result);
+}
+
+xmlrpc_value *rhbz_search_duphash(struct abrt_xmlrpc *ax, const char *component,
+ const char *product, const char *duphash)
+{
+ char *query = NULL;
+ if (!product)
+ query = xasprintf("ALL component:\"%s\" whiteboard:\"%s\"", component, duphash);
+ else
+ query = xasprintf("ALL component:\"%s\" whiteboard:\"%s\" product:\"%s\"",
+ component, duphash, product);
+
+ VERB3 log("search for '%s'", query);
+ xmlrpc_value *ret = abrt_xmlrpc_call(ax, "Bug.search", "({s:s})",
+ "quicksearch", query);
+ free(query);
+ return ret;
+}
+
+xmlrpc_value *rhbz_get_member(const char *member, xmlrpc_value *xml)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value *value = NULL;
+ /* The xmlrpc_struct_find_value functions consider "not found" to be
+ * a normal result. If a member of the structure with the specified key
+ * exists, it returns it as a handle to an xmlrpc_value. If not, it returns
+ * NULL in place of that handle.
+ */
+ xmlrpc_struct_find_value(&env, xml, member, &value);
+ if (env.fault_occurred)
+ abrt_xmlrpc_error(&env);
+
+ return value;
+}
+
+/* The only way this can fail is if arrayP is not actually an array XML-RPC
+ * value. So it is usually not worth checking *envP.
+ * die or return size of array
+ */
+int rhbz_array_size(xmlrpc_value *xml)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ int size = xmlrpc_array_size(&env, xml);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ return size;
+}
+
+/* die or return bug id; each bug must have bug id otherwise xml is corrupted */
+int rhbz_bug_id(xmlrpc_value* xml)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value *item = NULL;
+ xmlrpc_value *bug = NULL;
+ int bug_id = -1;;
+
+ xmlrpc_array_read_item(&env, xml, 0, &item);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ bug = rhbz_get_member("bug_id", item);
+ xmlrpc_DECREF(item);
+ if (!bug)
+ abrt_xmlrpc_die(&env);
+
+ xmlrpc_read_int(&env, bug, &bug_id);
+ xmlrpc_DECREF(bug);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ VERB3 log("found bug_id %i", bug_id);
+ return bug_id;
+}
+
+/* die when mandatory value is missing (set flag RHBZ_MANDATORY_MEMB)
+ * or return appropriate string or NULL when fail;
+ */
+// TODO: npajkovs: add flag to read xmlrpc_read_array_item first
+void *rhbz_bug_read_item(const char *memb, xmlrpc_value *xml, int flags)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value *member = rhbz_get_member(memb, xml);
+
+ const char *string = NULL;
+
+ if (!member)
+ goto die;
+
+ if (IS_READ_STR(flags))
+ {
+ xmlrpc_read_string(&env, member, &string);
+ xmlrpc_DECREF(member);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ if (!*string)
+ goto die;
+
+ VERB3 log("found %s: '%s'", memb, string);
+ return (void*)string;
+ }
+
+ {
+ if (IS_READ_INT(flags))
+ {
+ int *integer = xmalloc(sizeof(int));
+ xmlrpc_read_int(&env, member, integer);
+ xmlrpc_DECREF(member);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ VERB3 log("found %s: '%i'", memb, *integer);
+ return (void*)integer;
+ }
+ }
+die:
+ free((void*)string);
+ if (IS_MANDATORY(flags))
+ error_msg_and_die(_("Looks like corrupted xml response, because '%s'"
+ " member is missing."), memb);
+
+ return NULL;
+}
+
+GList *rhbz_bug_cc(xmlrpc_value* result_xml)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value* cc_member = rhbz_get_member("cc", result_xml);
+ if (!cc_member)
+ return NULL;
+
+ int array_size = rhbz_array_size(cc_member);
+
+ VERB3 log("count members on cc %i", array_size);
+ GList *cc_list = NULL;
+
+ for (int i = 0; i < array_size; ++i)
+ {
+ xmlrpc_value* item = NULL;
+ xmlrpc_array_read_item(&env, cc_member, i, &item);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ if (!item)
+ continue;
+
+ const char* cc = NULL;
+ xmlrpc_read_string(&env, item, &cc);
+ xmlrpc_DECREF(item);
+ if (env.fault_occurred)
+ abrt_xmlrpc_die(&env);
+
+ if (*cc != '\0')
+ {
+ cc_list = g_list_append(cc_list, (char*)cc);
+ VERB3 log("member on cc is %s", cc);
+ continue;
+ }
+ free((char*)cc);
+ }
+ xmlrpc_DECREF(cc_member);
+ return cc_list;
+}
+
+struct bug_info *rhbz_bug_info(struct abrt_xmlrpc *ax, int bug_id)
+{
+ struct bug_info *bz = new_bug_info();
+ xmlrpc_value *xml_bug_response = abrt_xmlrpc_call(ax, "bugzilla.getBug",
+ "(i)", bug_id);
+
+ int *ret = (int*)rhbz_bug_read_item("bug_id", xml_bug_response,
+ RHBZ_MANDATORY_MEMB | RHBZ_READ_INT);
+ bz->bi_id = *ret;
+ free(ret);
+ bz->bi_product = rhbz_bug_read_item("product", xml_bug_response,
+ RHBZ_MANDATORY_MEMB | RHBZ_READ_STR);
+ bz->bi_reporter = rhbz_bug_read_item("reporter", xml_bug_response,
+ RHBZ_MANDATORY_MEMB | RHBZ_READ_STR);
+ bz->bi_status = rhbz_bug_read_item("bug_status", xml_bug_response,
+ RHBZ_MANDATORY_MEMB | RHBZ_READ_STR);
+ bz->bi_resolution = rhbz_bug_read_item("resolution", xml_bug_response,
+ RHBZ_READ_STR);
+
+ if (strcmp(bz->bi_status, "CLOSED") == 0 && !bz->bi_resolution)
+ error_msg_and_die(_("Bug %i is CLOSED, but it has no RESOLUTION"), bz->bi_id);
+
+ ret = (int*)rhbz_bug_read_item("dup_id", xml_bug_response,
+ RHBZ_READ_INT);
+ if (strcmp(bz->bi_status, "CLOSED") == 0
+ && strcmp(bz->bi_resolution, "DUPLICATE") == 0
+ && !ret)
+ {
+ error_msg_and_die(_("Bug %i is CLOSED as DUPLICATE, but it has no DUP_ID"),
+ bz->bi_id);
+ }
+
+ bz->bi_dup_id = (ret) ? *ret: -1;
+ free(ret);
+
+ bz->bi_cc_list = rhbz_bug_cc(xml_bug_response);
+
+ xmlrpc_DECREF(xml_bug_response);
+
+ return bz;
+}
+
+/* suppress mail notify by {s:i} (nomail:1) (driven by flag) */
+int rhbz_new_bug(struct abrt_xmlrpc *ax, problem_data_t *problem_data,
+ int depend_on_bug)
+{
+ const char *package = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_PACKAGE);
+ const char *component = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_COMPONENT);
+ const char *release = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_OS_RELEASE);
+ if (!release) /* Old dump dir format compat. Remove in abrt-2.1 */
+ release = get_problem_item_content_or_NULL(problem_data, "release");
+ const char *arch = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_ARCHITECTURE);
+ const char *duphash = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_DUPHASH);
+ const char *reason = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_REASON);
+ const char *function = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_CRASH_FUNCTION);
+ const char *analyzer = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_ANALYZER);
+ const char *tainted_str = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_TAINTED);
+
+ struct strbuf *buf_summary = strbuf_new();
+ strbuf_append_strf(buf_summary, "[abrt] %s", package);
+
+ if (function != NULL && strlen(function) < 30)
+ strbuf_append_strf(buf_summary, ": %s", function);
+
+ if (reason != NULL)
+ strbuf_append_strf(buf_summary, ": %s", reason);
+
+ if (tainted_str && analyzer
+ && (strcmp(analyzer, "Kerneloops") == 0)
+ ) {
+ //TODO: fix me; basically it doesn't work as it suppose to work
+ // I will fix it immediately when this patch land into abrt git
+ /*
+ unsigned long tainted = xatoi_positive(tainted_str);
+ const char *tainted_warning = tainted_string(tainted);
+ if (tainted_warning)
+ strbuf_append_strf(buf_summary, ": TAINTED %s", tainted_warning);
+ */
+ }
+
+ char *status_whiteboard = xasprintf("abrt_hash:%s", duphash);
+
+ char *bz_dsc = make_description_bz(problem_data);
+ char *full_dsc = xasprintf("abrt version: "VERSION"\n%s", bz_dsc);
+ free(bz_dsc);
+
+ char *product = NULL;
+ char *version = NULL;
+ parse_release_for_bz(release, &product, &version);
+
+ xmlrpc_value* result = NULL;
+ char *summary = strbuf_free_nobuf(buf_summary);
+ if (depend_on_bug > -1)
+ {
+ result = abrt_xmlrpc_call(ax, "Bug.create", "({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:i})",
+ "product", product,
+ "component", component,
+ "version", version,
+ "summary", summary,
+ "description", full_dsc,
+ "status_whiteboard", status_whiteboard,
+ "platform", arch,
+ "dependson", depend_on_bug);
+ }
+ else
+ {
+ result = abrt_xmlrpc_call(ax, "Bug.create", "({s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
+ "product", product,
+ "component", component,
+ "version", version,
+ "summary", summary,
+ "description", full_dsc,
+ "status_whiteboard", status_whiteboard,
+ "platform", arch);
+ }
+ free(status_whiteboard);
+ free(product);
+ free(version);
+ free(summary);
+ free(full_dsc);
+
+ if (!result)
+ return -1;
+
+ int *r = rhbz_bug_read_item("id", result, RHBZ_MANDATORY_MEMB | RHBZ_READ_INT);
+ xmlrpc_DECREF(result);
+ int new_bug_id = *r;
+ free(r);
+
+ log(_("New bug id: %i"), new_bug_id);
+ return new_bug_id;
+}
+
+/* suppress mail notify by {s:i} (nomail:1) (driven by flag) */
+int rhbz_attachment(struct abrt_xmlrpc *ax, const char *filename,
+ const char *bug_id, const char *data)
+{
+ char *encoded64 = encode_base64(data, strlen(data));
+ char *fn = xasprintf("File: %s", filename);
+ xmlrpc_value* result;
+ result= abrt_xmlrpc_call(ax, "bugzilla.addAttachment", "(s{s:s,s:s,s:s,s:s})",
+ bug_id,
+ "description", fn,
+ "filename", filename,
+ "contenttype", "text/plain",
+ "data", encoded64);
+ free(encoded64);
+ free(fn);
+ if (!result)
+ return -1;
+
+ xmlrpc_DECREF(result);
+
+ return 0;
+}
+
+/* suppress mail notify by {s:i} (nomail:1) (driven by flag) */
+int rhbz_attachments(struct abrt_xmlrpc *ax, const char *bug_id,
+ problem_data_t *problem_data)
+{
+ GHashTableIter iter;
+ char *name;
+ struct problem_item *value;
+ g_hash_table_iter_init(&iter, problem_data);
+ while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
+ {
+ const char *content = value->content;
+
+ // We were special-casing FILENAME_BACKTRACE here, but karel says
+ // he can retrieve it in inlined form from comments too.
+ if ((value->flags & CD_FLAG_TXT)
+ && (strlen(content) > CD_TEXT_ATT_SIZE /*|| (strcmp(name, FILENAME_BACKTRACE) == 0)*/)
+ ) {
+ /* check if the attachment failed and try it once more */
+ rhbz_attachment(ax, name, bug_id, content);
+ }
+ }
+
+ return 0;
+}
+
+void rhbz_logout(struct abrt_xmlrpc *ax)
+{
+ xmlrpc_value* result = abrt_xmlrpc_call(ax, "User.logout", "(s)", "");
+ if (result)
+ xmlrpc_DECREF(result);
+}
+
+struct bug_info *rhbz_find_origin_bug_closed_duplicate(struct abrt_xmlrpc *ax,
+ struct bug_info *bi)
+{
+ struct bug_info *bi_tmp = new_bug_info();
+ bi_tmp->bi_id = bi->bi_id;
+ bi_tmp->bi_dup_id = bi->bi_dup_id;
+
+ for (int ii = 0; ii <= MAX_HOPS; ii++)
+ {
+ if (ii == MAX_HOPS)
+ error_msg_and_die(_("Bugzilla couldn't find parent of bug %d"), bi->bi_id);
+
+ log("Bug %d is a duplicate, using parent bug %d", bi_tmp->bi_id, bi_tmp->bi_dup_id);
+ int bug_id = bi_tmp->bi_dup_id;
+
+ free_bug_info(bi_tmp);
+ bi_tmp = rhbz_bug_info(ax, bug_id);
+
+ // found a bug which is not CLOSED as DUPLICATE
+ if (bi_tmp->bi_dup_id == -1)
+ break;
+ }
+
+ return bi_tmp;
+}
+
+/* suppress mail notify by {s:i} (nomail:1) */
+void rhbz_mail_to_cc(struct abrt_xmlrpc *ax, int bug_id, const char *mail)
+{
+ xmlrpc_value *result = abrt_xmlrpc_call(ax, "Bug.update", "({s:i,s:{s:(s)}})",
+ "ids", bug_id, "updates", "add_cc", mail);
+ if (result)
+ xmlrpc_DECREF(result);
+}
+
+void rhbz_add_comment(struct abrt_xmlrpc *ax, int bug_id, const char *comment,
+ int is_private)
+{
+ xmlrpc_value *result = abrt_xmlrpc_call(ax, "Bug.add_comment", "({s:i,s:s,s:b})",
+ "id", bug_id,
+ "comment", comment,
+ "private", is_private);
+ if (result)
+ xmlrpc_DECREF(result);
+}
diff --git a/src/plugins/rhbz.h b/src/plugins/rhbz.h
new file mode 100644
index 00000000..73d76f0a
--- /dev/null
+++ b/src/plugins/rhbz.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2011 ABRT team
+ Copyright (C) 2011 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 RHBZ_H
+#define RHBZ_H
+
+/* include/stdint.h: typedef int int32_t;
+ * include/xmlrpc-c/base.h: typedef int32_t xmlrpc_int32;
+ */
+
+#include "abrt_xmlrpc.h"
+#include "abrt_problem_data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ RHBZ_MANDATORY_MEMB = (1 << 0),
+ RHBZ_READ_STR = (1 << 1),
+ RHBZ_READ_INT = (1 << 2),
+};
+
+#define IS_MANDATORY(flags) ((flags) & RHBZ_MANDATORY_MEMB)
+#define IS_READ_STR(flags) ((flags) & RHBZ_READ_STR)
+#define IS_READ_INT(flags) ((flags) & RHBZ_READ_INT)
+
+struct bug_info {
+ int bi_id;
+ int bi_dup_id;
+
+ const char *bi_status;
+ const char *bi_resolution;
+ const char *bi_reporter;
+ const char *bi_product;
+
+ GList *bi_cc_list;
+};
+
+struct bug_info *new_bug_info();
+void free_bug_info(struct bug_info *bz);
+
+void rhbz_login(struct abrt_xmlrpc *ax, const char *login, const char *passwd);
+
+void rhbz_mail_to_cc(struct abrt_xmlrpc *ax, int bug_id, const char *mail);
+
+void rhbz_add_comment(struct abrt_xmlrpc *ax, int bug_id, const char *comment,
+ int is_private);
+
+void *rhbz_bug_read_item(const char *memb, xmlrpc_value *xml, int flags);
+
+void rhbz_logout(struct abrt_xmlrpc *ax);
+
+xmlrpc_value *rhbz_search_duphash(struct abrt_xmlrpc *ax, const char *component,
+ const char *release, const char *duphash);
+
+xmlrpc_value *rhbz_get_member(const char *member, xmlrpc_value *xml);
+
+int rhbz_array_size(xmlrpc_value *xml);
+
+int rhbz_bug_id(xmlrpc_value *xml);
+
+int rhbz_new_bug(struct abrt_xmlrpc *ax, problem_data_t *problem_data,
+ int depend_on_bug);
+
+int rhbz_attachments(struct abrt_xmlrpc *ax, const char *bug_id,
+ problem_data_t *problem_data);
+
+int rhbz_attachment(struct abrt_xmlrpc *ax, const char *filename,
+ const char *bug_id, const char *data);
+
+GList *rhbz_bug_cc(xmlrpc_value *result_xml);
+
+struct bug_info *rhbz_bug_info(struct abrt_xmlrpc *ax, int bug_id);
+
+
+struct bug_info *rhbz_find_origin_bug_closed_duplicate(struct abrt_xmlrpc *ax,
+ struct bug_info *bi);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif