Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/include/internal_libreport.h | 11 ++++
src/lib/Makefile.am | 1 +
src/lib/is_in_string_list.c | 51 ++++++++++++++++
src/lib/problem_data.c | 42 +-------------
src/lib/string_list.c | 109 +++++++++++++++++++++++++++++++++
src/plugins/bugzilla.conf | 5 ++
src/plugins/reporter-bugzilla.c | 25 +++++++-
src/plugins/rhbz.c | 124 +++++++++++++++++++++++++++++++++-----
src/plugins/rhbz.h | 23 ++++++-
9 files changed, 329 insertions(+), 62 deletions(-)
create mode 100644 src/lib/string_list.c
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h
index 42c94f7..b4497a7 100644
--- a/src/include/internal_libreport.h
+++ b/src/include/internal_libreport.h
@@ -250,8 +250,19 @@ char *run_in_shell_and_save_output(int flags,
/* Random utility functions */
+#define build_string_list_from_csv libreport_build_string_list_from_csv
+char **build_string_list_from_csv(const char *comma_separated_list);
+#define join_string_lists libreport_join_string_lists
+char **join_string_lists(char **op1, char **op2);
+#define string_list_len libreport_string_list_len
+size_t string_list_len(char **v);
+
#define is_in_string_list libreport_is_in_string_list
bool is_in_string_list(const char *name, char **v);
+#define is_in_sorted_string_list libreport_is_in_sorted_string_list
+bool is_in_sorted_string_list(const char *name, char **sorted_v, size_t len);
+#define sort_string_list libreport_sort_string_list
+size_t sort_string_list(char **v);
#define is_in_comma_separated_list libreport_is_in_comma_separated_list
bool is_in_comma_separated_list(const char *value, const char *list);
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index cffabb2..dec7941 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -10,6 +10,7 @@ lib_LTLIBRARIES = \
libreport_la_SOURCES = \
xfuncs.c \
+ string_list.c \
is_in_string_list.c \
is_in_comma_separated_list.c \
encbase64.c \
diff --git a/src/lib/is_in_string_list.c b/src/lib/is_in_string_list.c
index 663edff..5d085ec 100644
--- a/src/lib/is_in_string_list.c
+++ b/src/lib/is_in_string_list.c
@@ -28,3 +28,54 @@ bool is_in_string_list(const char *name, char **v)
}
return false;
}
+
+/* Computes length of list terminated by NULL value
+ *
+ * @param v a list
+ * @return number of items in list
+ */
+size_t string_list_len(char **v)
+{
+ if (!v)
+ return 0;
+
+ char **cursor = v;
+ while (*cursor)
+ ++cursor;
+
+ return cursor - v;
+}
+
+/* A wrapper for strcmp() function used as param in qsort() and bsearch()
+ */
+static int cmpstringp(const void *p1, const void *p2)
+{
+ return strcmp(*(char * const *)p1, *(char * const *)p2);
+}
+
+/* Inplace sorting of list terminated by NULL.
+ *
+ * @param v a list
+ * @return number of sorted items
+ */
+size_t sort_string_list(char **v)
+{
+ const size_t len = string_list_len(v);
+
+ if (len>0)
+ qsort(v, len, sizeof(char*), cmpstringp);
+
+ return len;
+}
+
+/* Looks up for a value in sorted list.
+ *
+ * @param name a searched value
+ * @param sorted_v a sorted list terminated by NULL
+ * @param len number of items in list
+ * @return nonzero value if the name is found int the sorted_v; otherwise 0
+ */
+bool is_in_sorted_string_list(const char *name, char **sorted_v, size_t len)
+{
+ return len>0 && bsearch(&name, sorted_v, len, sizeof(char*),
cmpstringp);
+}
diff --git a/src/lib/problem_data.c b/src/lib/problem_data.c
index 536f7a1..917e62f 100644
--- a/src/lib/problem_data.c
+++ b/src/lib/problem_data.c
@@ -399,52 +399,12 @@ problem_data_t *create_problem_data_from_dump_dir(struct dump_dir
*dd)
return problem_data;
}
-/*
- * Returns NULL-terminated char *vector[]. Result itself must be freed,
- * but do no free list elements. IOW: do free(result), but never free(result[i])!
- * If comma_separated_list is NULL or "", returns NULL.
- */
-static char **build_exclude_vector(const char *comma_separated_list)
-{
- char **exclude_items = NULL;
- if (comma_separated_list && comma_separated_list[0])
- {
- /* even w/o commas, we'll need two elements:
- * exclude_items[0] = "name"
- * exclude_items[1] = NULL
- */
- unsigned cnt = 2;
-
- const char *cp = comma_separated_list;
- while (*cp)
- if (*cp++ == ',')
- cnt++;
-
- /* We place the string directly after the char *vector[cnt]: */
- exclude_items = xzalloc(cnt * sizeof(exclude_items[0]) + (cp -
comma_separated_list) + 1);
- char *p = strcpy((char*)&exclude_items[cnt], comma_separated_list);
-
- char **pp = exclude_items;
- *pp++ = p;
- while (*p)
- {
- if (*p++ == ',')
- {
- p[-1] = '\0';
- *pp++ = p;
- }
- }
- }
-
- return exclude_items;
-}
-
problem_data_t *create_problem_data_for_reporting(const char *dump_dir_name)
{
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
return NULL; /* dd_opendir already emitted error msg */
- char **exclude_items =
build_exclude_vector(getenv("EXCLUDE_FROM_REPORT"));
+ char **exclude_items =
build_string_list_from_csv(getenv("EXCLUDE_FROM_REPORT"));
problem_data_t *problem_data = new_problem_data();
load_problem_data_from_dump_dir(problem_data, dd, exclude_items);
dd_close(dd);
diff --git a/src/lib/string_list.c b/src/lib/string_list.c
new file mode 100644
index 0000000..b7d8526
--- /dev/null
+++ b/src/lib/string_list.c
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2012 ABRT team
+ Copyright (C) 2012 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 "internal_libreport.h"
+
+/*
+ * Returns NULL-terminated char *vector[]. Result itself must be freed,
+ * but do no free list elements. IOW: do free(result), but never free(result[i])!
+ * If comma_separated_list is NULL or "", returns NULL.
+ */
+char **build_string_list_from_csv(const char *comma_separated_list)
+{
+ char **result_list = NULL;
+ if (comma_separated_list && comma_separated_list[0])
+ {
+ /* even w/o commas, we'll need two elements:
+ * result_list[0] = "name"
+ * result_list[1] = NULL
+ */
+ unsigned cnt = 2;
+
+ const char *cp = comma_separated_list;
+ while (*cp)
+ if (*cp++ == ',')
+ cnt++;
+
+ /* We place the string directly after the char *vector[cnt]: */
+ result_list = xzalloc(cnt * sizeof(result_list[0]) + (cp - comma_separated_list)
+ 1);
+ char *p = strcpy((char*)&result_list[cnt], comma_separated_list);
+
+ char **pp = result_list;
+ *pp++ = p;
+ while (*p)
+ {
+ if (*p++ == ',')
+ {
+ p[-1] = '\0';
+ *pp++ = p;
+ }
+ }
+ }
+
+ return result_list;
+}
+
+/*
+ * Returns NULL-terminated char *vector[]. Result itself must be freed,
+ * but do no free list elements. IOW: do free(result), but never free(result[i])!
+ * If comma_separated_list is NULL or "", returns NULL.
+ */
+char **join_string_lists(char **op1, char** op2)
+{
+ char **result_list = NULL;
+ size_t nmemb = 0;
+ size_t bytes = 0;
+
+ char **lists[] = {op1, op2, NULL};
+ /* At first, work out a number of required bytes and a number of strings */
+ for (char*** list_beginig = lists; *list_beginig; ++list_beginig)
+ {
+ char **list_member = *list_beginig;
+ if (!list_member)
+ continue;
+
+ while (*list_member)
+ bytes += strlen(*list_member++) + 1;
+
+ nmemb += list_member - *list_beginig;
+ }
+
+ // add 1 item for terminating NULL
+ if (nmemb++)
+ {
+ result_list = xzalloc(nmemb * sizeof(result_list[0]) + bytes);
+
+ size_t written = 0;
+ char **result_member = result_list;
+ for (char ***list_beginig = lists; *list_beginig; ++list_beginig)
+ {
+ char **list_member = *list_beginig;
+ if (!list_member)
+ continue;
+
+ while (*list_member)
+ {
+ *result_member++ = strcpy(((char*)&result_list[nmemb]) + written,
*list_member);
+
+ written += strlen(*list_member++) + 1;
+ }
+ }
+ }
+
+ return result_list;
+}
diff --git a/src/plugins/bugzilla.conf b/src/plugins/bugzilla.conf
index 18eba5a..f8f6cb6 100644
--- a/src/plugins/bugzilla.conf
+++ b/src/plugins/bugzilla.conf
@@ -6,3 +6,8 @@ SSLVerify = yes
Login =
# your password
Password =
+# Names of files from problem directory which are excluded from BZ report at all
+ExcludeList = remote_result,time
+# Names of files from problem directory which are always attached and never
+# printed to full description of a bug report.
+AllwaysAttached = dso_list,maps,open_fds,smap,smolt_data
diff --git a/src/plugins/reporter-bugzilla.c b/src/plugins/reporter-bugzilla.c
index 6584f0f..d72c188 100644
--- a/src/plugins/reporter-bugzilla.c
+++ b/src/plugins/reporter-bugzilla.c
@@ -42,6 +42,12 @@ static void set_settings(struct bugzilla_struct *b, map_string_h
*settings)
environ = getenv("Bugzilla_OSRelease");
b->b_release = environ ? environ : get_map_string_item_or_NULL(settings,
"OSRelease");
+
+ environ = getenv("Bugzilla_ExcludeList:");
+ b->b_excluded_files = environ ? environ : get_map_string_item_or_NULL(settings,
"ExcludeList");
+
+ environ = getenv("Bugzilla_AlwaysAttached");
+ b->b_always_attached_files = environ ? environ :
get_map_string_item_or_NULL(settings, "AlwaysAttached");
}
int main(int argc, char **argv)
@@ -337,9 +343,18 @@ int main(int argc, char **argv)
if (all_bugs_size == 0)
{
+ char **always_attached_list =
build_string_list_from_csv(rhbz.b_always_attached_files);
+ sort_string_list(always_attached_list);
+
+ char **excluded_from_report =
build_string_list_from_csv(rhbz.b_excluded_files);
+ sort_string_list(excluded_from_report);
+
+ char **excluded_from_full_desc_items =
join_string_lists(always_attached_list,
+
excluded_from_report);
+
/* Create new bug */
log(_("Creating a new bug"));
- int bug_id = rhbz_new_bug(client, problem_data, rhbz.b_release);
+ int bug_id = rhbz_new_bug(client, problem_data, rhbz.b_release,
excluded_from_full_desc_items);
log(_("Adding attachments to bug %i"), bug_id);
char bug_id_str[sizeof(int)*3 + 2];
@@ -348,11 +363,17 @@ int main(int argc, char **argv)
int flags = RHBZ_NOMAIL_NOTIFY;
if (opts & OPT_b)
flags |= RHBZ_ATTACH_BINARY_FILES;
- rhbz_attach_big_files(client, bug_id_str, problem_data, flags);
+ rhbz_attach_big_and_ugly_files(client, bug_id_str, problem_data, flags,
+ excluded_from_report, always_attached_list);
bz = new_bug_info();
bz->bi_status = xstrdup("NEW");
bz->bi_id = bug_id;
+
+ free(excluded_from_full_desc_items);
+ free(excluded_from_report);
+ free(always_attached_list);
+
goto log_out;
}
else
diff --git a/src/plugins/rhbz.c b/src/plugins/rhbz.c
index a3aa2ef..9ae102b 100644
--- a/src/plugins/rhbz.c
+++ b/src/plugins/rhbz.c
@@ -381,9 +381,98 @@ struct bug_info *rhbz_bug_info(struct abrt_xmlrpc *ax, int bug_id)
return bz;
}
+/* Format problem data according to Red Had Bugzilla default template.
+ *
+ * @param problem_data a problem data
+ * @param excluded_items a sorted NULL terminated list containing excluded items
+ * @return mallocated string with full description. Never returns NULL
+ */
+char* rhbz_make_bug_full_description(problem_data_t *problem_data, char**
excluded_items)
+{
+ /* Items we don't want to include to bz */
+ static const char *const additional_info_blacklisted_items[] = {
+ CD_DUMPDIR ,
+ FILENAME_ANALYZER ,
+ FILENAME_COREDUMP ,
+ FILENAME_HOSTNAME ,
+ FILENAME_DUPHASH ,
+ FILENAME_UUID ,
+ FILENAME_COUNT ,
+ FILENAME_TAINTED_SHORT,
+ FILENAME_ARCHITECTURE,
+ FILENAME_PACKAGE,
+ FILENAME_OS_RELEASE,
+ FILENAME_COMPONENT,
+ FILENAME_REASON,
+ FILENAME_COMMENT,
+ /* Plugin specific files */
+ RHBZ_FILENAME_HOW_REPRODUCIBLE,
+ RHBZ_FILENAME_STEPS_TO_REPRODUCE,
+ RHBZ_FILENAME_ACTUAL_RESULTS,
+ RHBZ_FILENAME_EXPECTED_RESULTS,
+ NULL
+ };
+
+ char** real_black_list = excluded_items
+ ?
join_string_lists((char**)additional_info_blacklisted_items, excluded_items)
+ : (char**)additional_info_blacklisted_items;
+
+ const char *analyzer = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_ANALYZER);
+ char *additional_info;
+ if (analyzer && !strcmp(analyzer, "Kerneloops"))
+ additional_info = make_description_koops(problem_data, CD_TEXT_ATT_SIZE_BZ);
+ else
+ additional_info = make_description(
+ problem_data,
+ real_black_list,
+ CD_TEXT_ATT_SIZE_BZ,
+ /* full description no longer contains senseless file
names */
+ MAKEDESC_SHOW_MULTILINE // | MAKEDESC_SHOW_FILES
+ );
+
+ const char *comment = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_COMMENT);
+ const char *how_reproducible = get_problem_item_content_or_NULL(problem_data,
+
RHBZ_FILENAME_HOW_REPRODUCIBLE);
+ const char *steps_to_reproduce = get_problem_item_content_or_NULL(problem_data,
+
RHBZ_FILENAME_STEPS_TO_REPRODUCE);
+ const char *actual_results = get_problem_item_content_or_NULL(problem_data,
+
RHBZ_FILENAME_ACTUAL_RESULTS);
+ const char *expected_results = get_problem_item_content_or_NULL(problem_data,
+
RHBZ_FILENAME_EXPECTED_RESULTS);
+ const char *package = get_problem_item_content_or_NULL(problem_data,
+ FILENAME_PACKAGE);
+ /* full bug description according to default template */
+ char *full_dsc = xasprintf(
+ "Description of problem:\n%s\n\n"
+ "Version-Release number of selected component (if
applicable):\n%s\n\n"
+ "How reproducible:\n%s\n\n"
+ "Steps to Reproduce:\n%s\n\n"
+ "Actual results:\n%s\n\n"
+ "Expected results:\n%s\n\n"
+ "Additional info:\nlibreport version: "VERSION"\n%s\n"
+ /* Description of problem */ , comment ? :
RHBZ_ITEM_NOT_PROVIDED_BY_USER
+ /* Version-Release number */ , package ? :
RHBZ_ITEM_NOT_AVAILABLE
+ /* How reproducible */ , how_reproducible ? :
RHBZ_ITEM_NOT_PROVIDED_BY_USER
+ /* Steps to reproduce */ , steps_to_reproduce ? :
RHBZ_ITEM_NOT_PROVIDED_BY_USER
+ /* Actual results */ , actual_results ? :
RHBZ_ITEM_NOT_PROVIDED_BY_USER
+ /* Expected results */ , expected_results ? :
RHBZ_ITEM_NOT_PROVIDED_BY_USER
+ /* Additional info */ , additional_info
+ );
+
+ free(additional_info);
+
+ /* exclude items list is set thus list join was made and result must be freed */
+ if(excluded_items)
+ free(real_black_list);
+
+ return full_dsc;
+}
+
/* suppress mail notify by {s:i} (nomail:1) (driven by flag) */
int rhbz_new_bug(struct abrt_xmlrpc *ax, problem_data_t *problem_data,
- const char *release)
+ const char *release, char **excluded_items)
{
const char *package = get_problem_item_content_or_NULL(problem_data,
FILENAME_PACKAGE);
@@ -436,23 +525,16 @@ int rhbz_new_bug(struct abrt_xmlrpc *ax, problem_data_t
*problem_data,
strbuf_append_strf(buf_summary, ": TAINTED %s", tainted_short);
}
}
- char *status_whiteboard = xasprintf("abrt_hash:%s", duphash);
-
- char *bz_dsc;
- if (analyzer && !strcmp(analyzer, "Kerneloops"))
- bz_dsc = make_description_koops(problem_data, CD_TEXT_ATT_SIZE_BZ);
- else
- bz_dsc = make_description_bz(problem_data, CD_TEXT_ATT_SIZE_BZ);
-
- char *full_dsc = xasprintf("libreport version: "VERSION"\n%s",
bz_dsc);
- free(bz_dsc);
+ char *status_whiteboard = xasprintf("abrt_hash:%s", duphash);
char *product = NULL;
char *version = NULL;
parse_release_for_bz(release, &product, &version);
xmlrpc_value* result = NULL;
char *summary = strbuf_free_nobuf(buf_summary);
+ char *full_dsc = rhbz_make_bug_full_description(problem_data, excluded_items);
+
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,
@@ -545,8 +627,9 @@ int rhbz_attach_fd(struct abrt_xmlrpc *ax, const char *filename,
}
/* suppress mail notify by {s:i} (nomail:1) (driven by flag) */
-int rhbz_attach_big_files(struct abrt_xmlrpc *ax, const char *bug_id,
- problem_data_t *problem_data, int flags)
+int rhbz_attach_big_and_ugly_files(struct abrt_xmlrpc *ax, const char *bug_id,
+ problem_data_t *problem_data, int flags,
+ char **sorted_black_list, char **sorted_white_list)
{
GHashTableIter iter;
char *name;
@@ -555,9 +638,16 @@ int rhbz_attach_big_files(struct abrt_xmlrpc *ax, const char
*bug_id,
const char *analyzer = get_problem_item_content_or_NULL(problem_data,
FILENAME_ANALYZER);
+ const size_t black_list_len = string_list_len(sorted_black_list);
+ const size_t white_list_len = string_list_len(sorted_white_list);
+
g_hash_table_iter_init(&iter, problem_data);
while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
{
+ /* Ignore blacklisted items */
+ if (is_in_sorted_string_list(name, sorted_black_list, black_list_len))
+ continue;
+
if (value->flags & CD_FLAG_TXT)
{
const char *content = value->content;
@@ -568,10 +658,12 @@ int rhbz_attach_big_files(struct abrt_xmlrpc *ax, const char
*bug_id,
// We were special-casing FILENAME_BACKTRACE here, but karel says
// he can retrieve it in inlined form from comments too.
- if (len > CD_TEXT_ATT_SIZE_BZ /*|| (strcmp(name, FILENAME_BACKTRACE) ==
0)*/)
+ if (len > CD_TEXT_ATT_SIZE_BZ /*|| (strcmp(name, FILENAME_BACKTRACE) ==
0))*/
+ || is_in_sorted_string_list(name, sorted_white_list, white_list_len))
{
- /* This text item wasn't added in comments, it is too big
- * for that. Attach it as a file.
+ /* This text item wasn't added in comments, it is too big for
+ * that or the text is considered as unreadable. Attach it as a
+ * file.
*/
rhbz_attach_blob(ax, name, bug_id, content, len, flags);
}
diff --git a/src/plugins/rhbz.h b/src/plugins/rhbz.h
index c9023e9..44e3ad6 100644
--- a/src/plugins/rhbz.h
+++ b/src/plugins/rhbz.h
@@ -30,6 +30,18 @@
extern "C" {
#endif
+/* reporter-bugzilla plugin specific additional file names
+ */
+#define RHBZ_FILENAME_HOW_REPRODUCIBLE "how_reproducible"
+#define RHBZ_FILENAME_STEPS_TO_REPRODUCE "steps_to_reproduce"
+#define RHBZ_FILENAME_ACTUAL_RESULTS "actual_results"
+#define RHBZ_FILENAME_EXPECTED_RESULTS "expected_results"
+
+/* reporter-bugzilla substitutional texts for missing problem items
+ */
+#define RHBZ_ITEM_NOT_PROVIDED_BY_USER "<this item is not provided by
user>"
+#define RHBZ_ITEM_NOT_AVAILABLE "<this item is not available>"
+
enum {
RHBZ_MANDATORY_MEMB = (1 << 0),
RHBZ_READ_STR = (1 << 1),
@@ -69,6 +81,8 @@ struct bugzilla_struct {
const char *b_release;
char *b_product;
int b_ssl_verify;
+ const char *b_excluded_files;
+ const char *b_always_attached_files;
};
#define INIT_BUGZILLA(name) \
@@ -99,11 +113,14 @@ int rhbz_array_size(xmlrpc_value *xml);
int rhbz_bug_id(xmlrpc_value *xml);
+char* rhbz_make_bug_full_description(problem_data_t *problem_data, char**
excluded_items);
+
int rhbz_new_bug(struct abrt_xmlrpc *ax, problem_data_t *problem_data,
- const char *release);
+ const char *release, char **excluded_items);
-int rhbz_attach_big_files(struct abrt_xmlrpc *ax, const char *bug_id,
- problem_data_t *problem_data, int flags);
+int rhbz_attach_big_and_ugly_files(struct abrt_xmlrpc *ax, const char *bug_id,
+ problem_data_t *problem_data, int flags,
+ char **sorted_black_list, char **sorted_white_list);
int rhbz_attach_blob(struct abrt_xmlrpc *ax, const char *filename,
const char *bug_id, const char *data, int data_len, int flags);
--
1.7.7.6