[PATCH] trac#333: Add code generating dso_list to the python hook
by Vratislav Podzimek
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
src/hooks/abrt_exception_handler.py.in | 84 ++++++++++++++++++++++++++++++++--
1 file changed, 80 insertions(+), 4 deletions(-)
diff --git a/src/hooks/abrt_exception_handler.py.in b/src/hooks/abrt_exception_handler.py.in
index 6c0659a..ecdb175 100644
--- a/src/hooks/abrt_exception_handler.py.in
+++ b/src/hooks/abrt_exception_handler.py.in
@@ -24,8 +24,22 @@ Module for the ABRT exception handling hook
import sys
import os
+import inspect
-def write_dump(tb):
+try:
+ import rpm
+ HAVE_RPM = True
+except ImportError as imperr:
+ HAVE_RPM = False
+ import syslog
+ syslog.syslog("RPM module not available, cannot query RPM db for package "\
+ "names")
+
+class RPMinfoError(Exception):
+ """Exception class for RPMdb-querying related errors"""
+ pass
+
+def write_dump(tb_text, tb):
if sys.argv[0][0] == "/":
executable = os.path.abspath(sys.argv[0])
else:
@@ -33,6 +47,11 @@ def write_dump(tb):
# (BTW, we *can't* assume the script is in current directory.)
executable = sys.argv[0]
+ if HAVE_RPM:
+ dso_list = get_dso_list(tb)
+ else:
+ dso_list = None
+
# Open ABRT daemon's socket and write data to it
try:
import socket
@@ -48,8 +67,12 @@ def write_dump(tb):
# This handler puts a short(er) crash descr in 1st line of the backtrace.
# Example:
# CCMainWindow.py:1:<module>:ZeroDivisionError: integer division or modulo by zero
- s.sendall("REASON=%s\0" % tb.splitlines()[0])
- s.sendall("BACKTRACE=%s\0" % tb)
+ s.sendall("REASON=%s\0" % tb_text.splitlines()[0])
+ s.sendall("BACKTRACE=%s\0" % tb_text)
+
+ if dso_list:
+ s.sendall("dso_list=%s\0" % "\n".join(dso_list))
+
s.shutdown(socket.SHUT_WR)
@@ -77,6 +100,59 @@ def write_dump(tb):
import syslog
syslog.syslog("can't communicate with ABRT daemon, is it running? %s" % str(ex))
+def get_package_for_file(fpath):
+ """
+ Returns package name for a given file.
+
+ @param fpath: filename
+ @type fpath: str
+ @return: package name for the file
+ @rtype: str
+ @throws RPMinfoError: if package for the file cannot be found
+
+ """
+
+ ts = rpm.TransactionSet()
+ mi = ts.dbMatch("basenames", fpath)
+ try:
+ header = mi.next()
+ except StopIteration:
+ raise RPMinfoError("Cannot get package and component for file "+
+ fpath)
+ package = "{0}-{1}-{2}.{3}".format(header["name"], header["version"],
+ header["release"], header["arch"])
+
+ return package
+
+def get_dso_list(tb):
+ """
+ Get the list of names of the packages whose files appear in the traceback.
+
+ @param tb: traceback
+ @type tb: traceback
+ @return: list of package names
+ @rtype: list
+
+ """
+
+ if inspect.istraceback(tb):
+ tb = inspect.getinnerframes(tb)
+
+ packages = set()
+ for (frame, fpath, lineno, func, ctx, idx) in tb:
+ try:
+ packages.add(get_package_for_file(fpath))
+ except RPMinfoError as rpmerr:
+ continue
+
+ # remove the package name of the executable itself
+ try:
+ packages.discard(get_package_for_file(sys.argv[0]))
+ except RPMinfoError as rpmerr:
+ pass
+
+ return list(packages)
+
def conf_enabled(var_name):
try:
file = open(@CONF_DIR@ + "/plugins/python.conf", "r")
@@ -187,7 +263,7 @@ def handleMyException((etype, value, tb)):
text += "".join(elist)
# Send data to the daemon
- write_dump(text)
+ write_dump(text, tb)
except:
# Silently ignore any error in this hook,
--
1.7.11.2
11 years, 7 months
[PATCH v4] Provide package data for kernel oops
by Richard Marko
Required for reporter-ureport to work with kernel oopses.
Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
abrt.spec.in | 1 +
src/plugins/Makefile.am | 3 ++-
src/plugins/abrt-action-save-kernel-data | 36 ++++++++++++++++++++++++++++++++
src/plugins/koops_event.conf | 1 +
4 files changed, 40 insertions(+), 1 deletion(-)
create mode 100755 src/plugins/abrt-action-save-kernel-data
diff --git a/abrt.spec.in b/abrt.spec.in
index a1c00ba..65a03d3 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -571,6 +571,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%endif
%{_bindir}/abrt-dump-oops
%{_bindir}/abrt-action-analyze-oops
+%{_bindir}/abrt-action-save-kernel-data
%{_mandir}/man1/abrt-action-analyze-oops.1*
%files addon-xorg
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 675b1a7..8829c06 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -4,7 +4,8 @@ bin_SCRIPTS = \
abrt-action-install-debuginfo \
abrt-action-analyze-core \
abrt-action-analyze-vmcore \
- abrt-action-list-dsos
+ abrt-action-list-dsos \
+ abrt-action-save-kernel-data
bin_PROGRAMS = \
abrt-watch-log \
diff --git a/src/plugins/abrt-action-save-kernel-data b/src/plugins/abrt-action-save-kernel-data
new file mode 100755
index 0000000..84bd447
--- /dev/null
+++ b/src/plugins/abrt-action-save-kernel-data
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Save pkg_{name, arch, version, release} for kernel oopses.
+#
+# These files are required by reporter-ureporter (mandatory
+# in uReport).
+#
+
+test -f kernel || exit 1
+
+echo "Looking for kernel package"
+kernel_package="kernel"
+kernel_version="$( sed 's/ .*//' kernel )"
+
+if grep -q "PAE" kernel; then
+ echo "Looking for PAE kernel"
+ kernel_package="kernel-PAE"
+ kernel_version="$( echo "$kernel_version" | sed 's/\.PAE//' )"
+fi
+
+package="$( rpm -q "$kernel_package" | grep "$kernel_version" )"
+if [ $? == 0 ]; then
+ echo "Kernel package $package found"
+ rpm -q --qf "%{name}\n" "$package" > pkg_name
+ rpm -q --qf "%{arch}\n" "$package" > pkg_arch
+ rpm -q --qf "%{version}\n" "$package" > pkg_version
+ rpm -q --qf "%{release}\n" "$package" > pkg_release
+ epoch="$( rpm -q --qf "%{epoch}" "$package" )"
+ if [ "$epoch" == "(none)" ]; then
+ echo "0" > pkg_epoch
+ else
+ echo "$epoch" > pkg_epoch
+ fi
+else
+ echo "Kernel package not found, tried version $kernel_version"
+fi
diff --git a/src/plugins/koops_event.conf b/src/plugins/koops_event.conf
index 91759b1..9369131 100644
--- a/src/plugins/koops_event.conf
+++ b/src/plugins/koops_event.conf
@@ -3,6 +3,7 @@ EVENT=post-create analyzer=Kerneloops
abrt-action-analyze-oops &&
dmesg >dmesg &&
abrt-action-generate-core-backtrace
+ abrt-action-save-kernel-data
# If you want behavior similar to one provided by kerneloops daemon
# distributed by kerneloops.org - that is, if you want
--
1.7.11.4
11 years, 7 months
[PATCH] fix core backtrace generation when debuginfo is present
by Richard Marko
In case when package debuginfo is present, gdb will output only
function names but no offsets preventing core backtrace generation.
Setting non-existent debuginfo directory resolves this.
---
src/lib/hooklib.c | 29 +++++++++++++++--------
src/plugins/abrt-action-generate-core-backtrace.c | 2 +-
2 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/src/lib/hooklib.c b/src/lib/hooklib.c
index 1b30a5b..ca799e0 100644
--- a/src/lib/hooklib.c
+++ b/src/lib/hooklib.c
@@ -249,17 +249,26 @@ char *get_backtrace(const char *dump_dir_name, unsigned timeout_sec, const char
// (https://bugzilla.redhat.com/show_bug.cgi?id=528668):
args[2] = (char*)"-ex";
struct strbuf *set_debug_file_directory = strbuf_new();
- strbuf_append_str(set_debug_file_directory, "set debug-file-directory /usr/lib/debug");
- const char *p = debuginfo_dirs;
- while (1)
+ if(debuginfo_dirs == NULL)
{
- while (*p == ':')
- p++;
- if (*p == '\0')
- break;
- const char *colon_or_nul = strchrnul(p, ':');
- strbuf_append_strf(set_debug_file_directory, ":%.*s/usr/lib/debug", (int)(colon_or_nul - p), p);
- p = colon_or_nul;
+ // set non-existent debug file directory to prevent resolving
+ // function names - we need offsets for core backtrace.
+ strbuf_append_str(set_debug_file_directory, "set debug-file-directory /");
+ }
+ else
+ {
+ strbuf_append_str(set_debug_file_directory, "set debug-file-directory /usr/lib/debug");
+ const char *p = debuginfo_dirs;
+ while (1)
+ {
+ while (*p == ':')
+ p++;
+ if (*p == '\0')
+ break;
+ const char *colon_or_nul = strchrnul(p, ':');
+ strbuf_append_strf(set_debug_file_directory, ":%.*s/usr/lib/debug", (int)(colon_or_nul - p), p);
+ p = colon_or_nul;
+ }
}
args[3] = strbuf_free_nobuf(set_debug_file_directory);
diff --git a/src/plugins/abrt-action-generate-core-backtrace.c b/src/plugins/abrt-action-generate-core-backtrace.c
index 5fccb89..9bd09a4 100644
--- a/src/plugins/abrt-action-generate-core-backtrace.c
+++ b/src/plugins/abrt-action-generate-core-backtrace.c
@@ -106,7 +106,7 @@ int main(int argc, char **argv)
if (strcmp(analyzer, "CCpp") == 0)
{
VERB1 log("Querying gdb for backtrace");
- char *gdb_out = get_backtrace(dump_dir_name, exec_timeout_sec, "");
+ char *gdb_out = get_backtrace(dump_dir_name, exec_timeout_sec, NULL);
if (gdb_out == NULL)
xfunc_die();
--
1.7.11.4
11 years, 7 months
[ABRT PATCH] translate each letters from tainted short to long string
by Jakub Filak
- the mapping was obtained from this link:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob;f=ker...
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/include/libabrt.h | 2 ++
src/lib/kernel.c | 74 +++++++++++++++++++++-----------------------
src/plugins/abrt-dump-oops.c | 24 ++++++--------
3 files changed, 48 insertions(+), 52 deletions(-)
diff --git a/src/include/libabrt.h b/src/include/libabrt.h
index 48d2ac3..22aed28 100644
--- a/src/include/libabrt.h
+++ b/src/include/libabrt.h
@@ -79,6 +79,8 @@ int daemon_is_ok();
char *koops_extract_version(const char *line);
#define kernel_tainted_short abrt_kernel_tainted_short
char *kernel_tainted_short(const char *kernel_bt);
+#define kernel_tainted_long abrt_kernel_tainted_long
+GList *kernel_tainted_long(const char *tainted_short);
#define koops_hash_str abrt_koops_hash_str
void koops_hash_str(char hash_str[SHA1_RESULT_LEN*2 + 1], char *oops_buf, const char *oops_ptr);
#define koops_extract_oopses abrt_koops_extract_oopses
diff --git a/src/lib/kernel.c b/src/lib/kernel.c
index 9655296..9ffcb72 100644
--- a/src/lib/kernel.c
+++ b/src/lib/kernel.c
@@ -555,56 +555,54 @@ char *kernel_tainted_short(const char *kernel_bt)
return tnt;
}
-#if 0 /* unused */
static const char *const tnts_long[] = {
- "Proprietary module has been loaded.",
- "Module has been forcibly loaded.",
- "SMP with CPUs not designed for SMP.",
- "User forced a module unload.",
- "System experienced a machine check exception.",
- "System has hit bad_page.",
- "Userspace-defined naughtiness.",
- "Kernel has oopsed before.",
- "ACPI table overridden.",
- "Taint on warning.",
- "Modules from drivers/staging are loaded.",
- "Working around severe firmware bug.",
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "Hardware is unsupported.",
- "Tech_preview",
+ /* A */ "ACPI table overridden.",
+ /* B */ "System has hit bad_page.",
+ /* C */ "Modules from drivers/staging are loaded.",
+ /* D */ "Kernel has oopsed before",
+ /* E */ NULL,
+ /* F */ "Module has been forcibly loaded.",
+ /* G */ "Proprietary module has not been loaded.",
+ /* H */ NULL,
+ /* I */ "Working around severe firmware bug.",
+ /* J */ NULL,
+ /* K */ NULL,
+ /* L */ NULL,
+ /* M */ "System experienced a machine check exception.",
+ /* N */ NULL,
+ /* O */ "Out-of-tree module has been loaded.",
+ /* P */ "Proprietary module has been loaded.",
+ /* Q */ NULL,
+ /* R */ "User forced a module unload.",
+ /* S */ "SMP with CPUs not designed for SMP.",
+ /* T */ NULL,
+ /* U */ "Userspace-defined naughtiness.",
+ /* V */ NULL,
+ /* W */ "Taint on warning.",
+ /* X */ NULL,
+ /* Y */ NULL,
+ /* Z */ NULL,
};
-GList *kernel_tainted_long(unsigned tainted)
+GList *kernel_tainted_long(const char *tainted_short)
{
int i = 0;
GList *tnt = NULL;
- while (tainted)
+ while (tainted_short[0] != '\0')
{
- if ((0x1 & tainted) && tnts_long[i])
- tnt = g_list_append(tnt, xstrdup(tnts_long[i]));
+ const int tnt_index = tainted_short[0] - 'A';
+ if (tnt_index >= 0 && tnt_index <= 'Z' - 'A')
+ {
+ const char *const txt = tnts_long[tnt_index];
+ if (txt)
+ tnt = g_list_append(tnt, (gpointer)txt);
+ }
++i;
- tainted >>= 1;
+ ++tainted_short;
}
return tnt;
}
-#endif
diff --git a/src/plugins/abrt-dump-oops.c b/src/plugins/abrt-dump-oops.c
index 29e74c5..016166c 100644
--- a/src/plugins/abrt-dump-oops.c
+++ b/src/plugins/abrt-dump-oops.c
@@ -128,6 +128,16 @@ static unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
{
VERB1 log("Kernel is tainted '%s'", tainted_short);
dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
+
+ GList *tainted_long = kernel_tainted_long(tainted_short);
+ struct strbuf *tnt_long = strbuf_new();
+ for (GList *li = tainted_long; li; li = li->next)
+ strbuf_append_strf(tnt_long, "%s\n", (char*) li->data);
+
+ dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long->buf);
+ strbuf_free(tnt_long);
+ g_list_free(tainted_long);
+
const char *fmt = _("A kernel problem occurred, but your kernel has been "
"tainted (flags:%s). Kernel maintainers are unable to "
"diagnose tainted reports.");
@@ -141,20 +151,6 @@ static unsigned save_oops_to_dump_dir(GList *oops_list, unsigned oops_cnt)
// kernel oops 1st line may look quite puzzling otherwise...
strchrnul(second_line, '\n')[0] = '\0';
dd_save_text(dd, FILENAME_REASON, second_line);
-
-/*
- GList *tainted_long = kernel_tainted_long(tainted);
-
- struct strbuf *tnt_long = strbuf_new();
- for (GList *li = tainted_long; li; li = li->next)
- strbuf_append_strf(tnt_long, "%s\n", (char*) li->data);
-
- dd_save_text(dd, FILENAME_TAINTED, tainted_str);
- dd_save_text(dd, FILENAME_TAINTED_SHORT, tainted_short);
- dd_save_text(dd, FILENAME_TAINTED_LONG, tnt_long->buf);
- strbuf_free(tnt_long);
- list_free_with_free(tainted_long);
-*/
dd_close(dd);
}
else
--
1.7.11.2
11 years, 7 months
[LIBREPORT PATCH] trac#698: make hyperlinks clickable in report-gkt event log
by Jakub Filak
- implementation of widget event callbacks is taken from gtk3-demo
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/gtk-helpers/hyperlinks.c | 116 +++++++++++++----
src/gtk-helpers/internal_libreport_gtk.h | 10 ++
src/gui-wizard-gtk/wizard.c | 207 ++++++++++++++++++++++++++++++-
3 files changed, 308 insertions(+), 25 deletions(-)
diff --git a/src/gtk-helpers/hyperlinks.c b/src/gtk-helpers/hyperlinks.c
index 3f8b570..044afe5 100644
--- a/src/gtk-helpers/hyperlinks.c
+++ b/src/gtk-helpers/hyperlinks.c
@@ -19,38 +19,110 @@ static char *find_end(const char* url_start)
return url_end;
}
-char *tag_url(const char* line, const char* prefix)
+/* Returns a list of pointers to url token begining and it's lenght
+ * This implementation parses the following line:
+ * https://partner-bugzilla.redhat.com/ftp://ftp.kernel.org/http://bugzilla....
+ * to the following tokens:
+ * https://partner-bugzilla.redhat.com/
+ * ftp://ftp.kernel.org/
+ * http://bugzilla.redhat.com/
+ * http://google.com/
+ * https://gmail.com/
+ */
+GList *find_url_tokens(const char *line)
{
static const char *const known_url_prefixes[] = {"http://", "https://", "ftp://", "file://", NULL};
-
- char *result = xstrdup(line);
-
const char *const *pfx = known_url_prefixes;
+ GList *tokens = NULL;
while (*pfx != NULL)
{
- char *cur_pos = result;
- char *url_start;
+ const char *cur_pos = line;
+ const char *url_start;
while ((url_start = strstr(cur_pos, *pfx)) != NULL)
{
char *url_end = find_end(url_start);
int len = url_end - url_start;
- char *hyperlink = xasprintf("%s<a href=\"%.*s\">%.*s</a>",
- prefix,
- len, url_start,
- len, url_start
- );
- len = url_start - result;
- char *old = result;
- result = xasprintf("%.*s%s%s",
- len, result,
- hyperlink,
- url_end
- );
- cur_pos = result + len + strlen(hyperlink);
- free(old);
- free(hyperlink);
+
+ GList *anc = tokens;
+ for (; anc; anc = g_list_next(anc))
+ {
+ const struct url_token *const t = (struct url_token *)anc->data;
+ if (t->start >= url_start)
+ break;
+ }
+
+ /* need it for overlap correction */
+ GList *prev = NULL;
+ /* initialize it after overlap correction */
+ struct url_token *tok = xmalloc(sizeof(*tok));
+ if (anc)
+ { /* insert a new token before token following in the str*/
+ prev = g_list_previous(anc);
+
+ struct url_token *following = anc->data;
+ if (url_end > following->start)
+ /* correct ovrelaps with following token */
+ len -= url_end - following->start;
+
+ GList *new = g_list_prepend(anc, tok);
+ /* a new token is to become head of the list*/
+ if (anc == tokens)
+ tokens = new;
+ }
+ else
+ { /* append a new token to the end of list */
+ prev = g_list_last(tokens);
+ tokens = g_list_append(tokens, tok);
+ }
+
+ if (prev)
+ { /* correct overlaps with previous token */
+ struct url_token *previous = prev->data;
+ const char *prev_end = previous->start + previous->len;
+
+ if (prev_end > url_start)
+ previous->len -= prev_end - url_start;
+ }
+
+ tok->start = url_start;
+ tok->len = len;
+
+ /* move right behind the current prefix */
+ cur_pos = url_start + strlen(*pfx);
}
pfx++;
}
- return result;
+
+ return tokens;
+}
+
+char *tag_url(const char* line, const char* prefix)
+{
+ struct strbuf *result = strbuf_new();
+ const char *last = line;
+ GList *urls = find_url_tokens(line);
+ for (GList *u = urls; u; u = g_list_next(u))
+ {
+ const struct url_token *const t = (struct url_token *)u->data;
+
+ /* add text between hyperlinks */
+ if (last < t->start)
+ /* TODO : add strbuf_append_strn() */
+ strbuf_append_strf(result, "%.*s", t->start - last, last);
+
+ strbuf_append_strf(result, "%s<a href=\"%.*s\">%.*s</a>",
+ prefix,
+ t->len, t->start,
+ t->len, t->start);
+
+ last = t->start + t->len;
+ }
+
+ g_list_free_full(urls, g_free);
+
+ /* add a text following the last link */
+ if (last[0] != '\0')
+ strbuf_append_str(result, last);
+
+ return strbuf_free_nobuf(result);
}
diff --git a/src/gtk-helpers/internal_libreport_gtk.h b/src/gtk-helpers/internal_libreport_gtk.h
index dd9ff87..aa28b16 100644
--- a/src/gtk-helpers/internal_libreport_gtk.h
+++ b/src/gtk-helpers/internal_libreport_gtk.h
@@ -49,6 +49,16 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent);
char * tag_url(const char* line, const char* prefix);
+#define url_token libreport_url_token
+struct url_token
+{
+ const char *start;
+ int len;
+};
+
+#define find_url_tokens libreport_find_url_tokens
+GList *find_url_tokens(const char *line);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index a669736..ea2394f 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -475,7 +475,7 @@ static void append_to_textview(GtkTextView *tv, const char *str)
/* Ensure we insert text at the end */
GtkTextIter text_iter;
- gtk_text_buffer_get_iter_at_offset(tb, &text_iter, -1);
+ gtk_text_buffer_get_end_iter(tb, &text_iter);
gtk_text_buffer_place_cursor(tb, &text_iter);
/* Deal with possible broken Unicode */
@@ -488,14 +488,207 @@ static void append_to_textview(GtkTextView *tv, const char *str)
gtk_text_buffer_insert_at_cursor(tb, buf, len);
str = end + 1;
}
- gtk_text_buffer_insert_at_cursor(tb, str, strlen(str));
+
+ gtk_text_buffer_get_end_iter(tb, &text_iter);
+
+ const char *last = str;
+ GList *urls = find_url_tokens(str);
+ for (GList *u = urls; u; u = g_list_next(u))
+ {
+ const struct url_token *const t = (struct url_token *)u->data;
+ if (last < t->start)
+ gtk_text_buffer_insert(tb, &text_iter, last, t->start - last);
+
+ GtkTextTag *tag;
+ tag = gtk_text_buffer_create_tag (tb, NULL, "foreground", "blue",
+ "underline", PANGO_UNDERLINE_SINGLE, NULL);
+ char *url = xstrndup(t->start, t->len);
+ g_object_set_data (G_OBJECT (tag), "url", url);
+
+ gtk_text_buffer_insert_with_tags(tb, &text_iter, url, -1, tag, NULL);
+
+ last = t->start + t->len;
+ }
+
+ g_list_free_full(urls, g_free);
+
+ if (last[0] != '\0')
+ gtk_text_buffer_insert(tb, &text_iter, last, strlen(last));
/* Scroll so that the end of the log is visible */
- gtk_text_buffer_get_iter_at_offset(tb, &text_iter, -1);
gtk_text_view_scroll_to_iter(tv, &text_iter,
/*within_margin:*/ 0.0, /*use_align:*/ FALSE, /*xalign:*/ 0, /*yalign:*/ 0);
}
+/* Looks at all tags covering the position of iter in the text view,
+ * and if one of them is a link, follow it by showing the page identified
+ * by the data attached to it.
+ */
+static void open_browse_if_link(GtkWidget *text_view, GtkTextIter *iter)
+{
+ GSList *tags = NULL, *tagp = NULL;
+
+ tags = gtk_text_iter_get_tags (iter);
+ for (tagp = tags; tagp != NULL; tagp = tagp->next)
+ {
+ GtkTextTag *tag = tagp->data;
+ const char *url = g_object_get_data (G_OBJECT (tag), "url");
+
+ if (url != 0)
+ {
+ if(fork() == 0)
+ {
+ execlp("gnome-open", "gnome-open", url, NULL);
+ execlp("xdg-open", "xdg-open", url, NULL);
+ exit(1);
+ }
+ break;
+ }
+ }
+
+ if (tags)
+ g_slist_free (tags);
+}
+
+/* Links can be activated by pressing Enter.
+ */
+static gboolean key_press_event(GtkWidget *text_view, GdkEventKey *event)
+{
+ GtkTextIter iter;
+ GtkTextBuffer *buffer;
+
+ switch (event->keyval)
+ {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (text_view));
+ gtk_text_buffer_get_iter_at_mark(buffer, &iter,
+ gtk_text_buffer_get_insert(buffer));
+ open_browse_if_link(text_view, &iter);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/* Links can also be activated by clicking.
+ */
+static gboolean event_after(GtkWidget *text_view, GdkEvent *ev)
+{
+ GtkTextIter start, end, iter;
+ GtkTextBuffer *buffer;
+ GdkEventButton *event;
+ gint x, y;
+
+ if (ev->type != GDK_BUTTON_RELEASE)
+ return FALSE;
+
+ event = (GdkEventButton *)ev;
+
+ if (event->button != GDK_BUTTON_PRIMARY)
+ return FALSE;
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
+
+ /* we shouldn't follow a link if the user has selected something */
+ gtk_text_buffer_get_selection_bounds(buffer, &start, &end);
+ if (gtk_text_iter_get_offset(&start) != gtk_text_iter_get_offset(&end))
+ return FALSE;
+
+ gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW (text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ event->x, event->y, &x, &y);
+
+ gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW (text_view), &iter, x, y);
+
+ open_browse_if_link(text_view, &iter);
+
+ return FALSE;
+}
+
+static gboolean hovering_over_link = FALSE;
+static GdkCursor *hand_cursor = NULL;
+static GdkCursor *regular_cursor = NULL;
+
+/* Looks at all tags covering the position (x, y) in the text view,
+ * and if one of them is a link, change the cursor to the "hands" cursor
+ * typically used by web browsers.
+ */
+static void set_cursor_if_appropriate(GtkTextView *text_view,
+ gint x,
+ gint y)
+{
+ GSList *tags = NULL, *tagp = NULL;
+ GtkTextIter iter;
+ gboolean hovering = FALSE;
+
+ gtk_text_view_get_iter_at_location(text_view, &iter, x, y);
+
+ tags = gtk_text_iter_get_tags(&iter);
+ for (tagp = tags; tagp != NULL; tagp = tagp->next)
+ {
+ GtkTextTag *tag = tagp->data;
+ gpointer url = g_object_get_data(G_OBJECT (tag), "url");
+
+ if (url != 0)
+ {
+ hovering = TRUE;
+ break;
+ }
+ }
+
+ if (hovering != hovering_over_link)
+ {
+ hovering_over_link = hovering;
+
+ if (hovering_over_link)
+ gdk_window_set_cursor(gtk_text_view_get_window(text_view, GTK_TEXT_WINDOW_TEXT), hand_cursor);
+ else
+ gdk_window_set_cursor(gtk_text_view_get_window(text_view, GTK_TEXT_WINDOW_TEXT), regular_cursor);
+ }
+
+ if (tags)
+ g_slist_free (tags);
+}
+
+
+/* Update the cursor image if the pointer moved.
+ */
+static gboolean motion_notify_event(GtkWidget *text_view, GdkEventMotion *event)
+{
+ gint x, y;
+
+ gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ event->x, event->y, &x, &y);
+
+ set_cursor_if_appropriate(GTK_TEXT_VIEW(text_view), x, y);
+ return FALSE;
+}
+
+/* Also update the cursor image if the window becomes visible
+ * (e.g. when a window covering it got iconified).
+ */
+static gboolean visibility_notify_event(GtkWidget *text_view, GdkEventVisibility *event)
+{
+ gint wx, wy, bx, by;
+
+ GdkWindow *win = gtk_text_view_get_window(GTK_TEXT_VIEW(text_view), GTK_TEXT_WINDOW_TEXT);
+ GdkDeviceManager *device_manager = gdk_display_get_device_manager(gdk_window_get_display (win));
+ GdkDevice *pointer = gdk_device_manager_get_client_pointer(device_manager);
+ gdk_window_get_device_position(gtk_widget_get_window(text_view), pointer, &wx, &wy, NULL);
+
+ gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(text_view),
+ GTK_TEXT_WINDOW_WIDGET,
+ wx, wy, &bx, &by);
+
+ set_cursor_if_appropriate(GTK_TEXT_VIEW (text_view), bx, by);
+
+ return FALSE;
+}
/* event_gui_data_t */
@@ -2680,6 +2873,14 @@ void create_assistant(void)
g_signal_connect(g_search_entry_bt, "changed", G_CALLBACK(search_timeout), NULL);
+ g_signal_connect (g_tv_event_log, "key-press-event", G_CALLBACK (key_press_event), NULL);
+ g_signal_connect (g_tv_event_log, "event-after", G_CALLBACK (event_after), NULL);
+ g_signal_connect (g_tv_event_log, "motion-notify-event", G_CALLBACK (motion_notify_event), NULL);
+ g_signal_connect (g_tv_event_log, "visibility-notify-event", G_CALLBACK (visibility_notify_event), NULL);
+
+ hand_cursor = gdk_cursor_new (GDK_HAND2);
+ regular_cursor = gdk_cursor_new (GDK_XTERM);
+
/* switch to right starting page */
on_page_prepare(g_assistant, gtk_notebook_get_nth_page(g_assistant, 0), NULL);
}
--
1.7.11.4
11 years, 8 months
[PATCH] fix CC updating in Bugzilla
by Denys Vlasenko
diff -x '*.po' -d -urpN libreport.5/src/plugins/rhbz.c libreport.6/src/plugins/rhbz.c
--- libreport.5/src/plugins/rhbz.c 2012-08-17 17:28:49.000000000 +0200
+++ libreport.6/src/plugins/rhbz.c 2012-08-28 13:28:48.770043600 +0200
@@ -17,6 +17,14 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+/* Bugzilla API doc:
+ * http://www.bugzilla.org/docs/4.2/en/html/api/Bugzilla/WebService.html
+ * http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService.html
+ *
+ * To make libxmlrpc print debug info to stdout (stderr?),
+ * export XMLRPC_TRACE_XML=1
+ */
+
#include "internal_libreport.h"
#include "rhbz.h"
#include <btparser/location.h>
@@ -758,9 +766,9 @@ int rhbz_attach_blob(struct abrt_xmlrpc
char *encoded64 = encode_base64(data, data_len);
char *fn = xasprintf("File: %s", filename);
xmlrpc_value* result;
- int nomail_notify = IS_NOMAIL_NOTIFY(flags);
+ int nomail_notify = !!IS_NOMAIL_NOTIFY(flags);
- result= abrt_xmlrpc_call(ax, "bugzilla.addAttachment", "(s{s:s,s:s,s:s,s:s,s:i})",
+ result = abrt_xmlrpc_call(ax, "bugzilla.addAttachment", "(s{s:s,s:s,s:s,s:s,s:i})",
bug_id,
"description", fn,
"filename", filename,
@@ -926,13 +934,41 @@ void rhbz_mail_to_cc(struct abrt_xmlrpc
func_entry();
xmlrpc_value *result;
- int nomail_notify = IS_NOMAIL_NOTIFY(flags);
+ int nomail_notify = !!IS_NOMAIL_NOTIFY(flags);
+#if 0 /* Obsolete API */
result = abrt_xmlrpc_call(ax, "Bug.update", "({s:i,s:{s:(s),s:i}})",
- "ids", bug_id, "updates", "add_cc", mail,
- "nomail", nomail_notify);
-
+ "ids", bug_id,
+ "updates", "add_cc", mail,
+ "nomail", nomail_notify
+ );
+#endif
+ /* Bugzilla 4.0+ uses this API: */
+ result = abrt_xmlrpc_call(ax, "Bug.update", "({s:i,s:{s:(s),s:i}})",
+ "ids", bug_id,
+ "cc", "add", mail,
+ "nomail", nomail_notify
+ );
if (result)
xmlrpc_DECREF(result);
+
+ /* TODO: check that result does indicate that CC was updated.
+ * The structure I see from Bugzilla 4.2:
+ * <struct>
+ * <member><name>bugs</name><value>
+ * <array><data><value><struct>
+ * <member><name>changes</name><value><struct>
+ * <member><name>cc</name><value><struct>
+ * <member><name>removed</name><value><string /></value></member>
+ * <member><name>added</name><value><string>USER(a)HOST.COM</string></value></member>
+ * </struct></value></member>
+ * </struct></value></member>
+ * <member><name>last_change_time</name><value><dateTime.iso8601>20120828T11:09:04</dateTime.iso8601></value></member>
+ * <member><name>id</name><value><int>NNNNNNN</int></value></member>
+ * <member><name>alias</name><value><array><data /></array></value></member>
+ * </struct></value></data>
+ * </array></value>
+ * </member></struct>
+ */
}
void rhbz_add_comment(struct abrt_xmlrpc *ax, int bug_id, const char *comment,
@@ -940,8 +976,8 @@ void rhbz_add_comment(struct abrt_xmlrpc
{
func_entry();
- int private = IS_PRIVATE(flags);
- int nomail_notify = IS_NOMAIL_NOTIFY(flags);
+ int private = !!IS_PRIVATE(flags);
+ int nomail_notify = !!IS_NOMAIL_NOTIFY(flags);
xmlrpc_value *result;
result = abrt_xmlrpc_call(ax, "Bug.add_comment", "({s:i,s:s,s:b,s:i})",
11 years, 8 months
[PATCH v3] Provide package data for kernel oops
by Richard Marko
Required for reporter-ureport to work with kernel oopses.
Signed-off-by: Richard Marko <rmarko(a)redhat.com>
---
abrt.spec.in | 1 +
src/plugins/Makefile.am | 3 ++-
src/plugins/abrt-action-save-kernel-data | 27 +++++++++++++++++++++++++++
src/plugins/koops_event.conf | 1 +
4 files changed, 31 insertions(+), 1 deletion(-)
create mode 100755 src/plugins/abrt-action-save-kernel-data
diff --git a/abrt.spec.in b/abrt.spec.in
index a1c00ba..65a03d3 100644
--- a/abrt.spec.in
+++ b/abrt.spec.in
@@ -571,6 +571,7 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
%endif
%{_bindir}/abrt-dump-oops
%{_bindir}/abrt-action-analyze-oops
+%{_bindir}/abrt-action-save-kernel-data
%{_mandir}/man1/abrt-action-analyze-oops.1*
%files addon-xorg
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 675b1a7..8829c06 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -4,7 +4,8 @@ bin_SCRIPTS = \
abrt-action-install-debuginfo \
abrt-action-analyze-core \
abrt-action-analyze-vmcore \
- abrt-action-list-dsos
+ abrt-action-list-dsos \
+ abrt-action-save-kernel-data
bin_PROGRAMS = \
abrt-watch-log \
diff --git a/src/plugins/abrt-action-save-kernel-data b/src/plugins/abrt-action-save-kernel-data
new file mode 100755
index 0000000..2a4ce98
--- /dev/null
+++ b/src/plugins/abrt-action-save-kernel-data
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# Save pkg_{name, arch, version, release} for kernel oopses.
+#
+# These files are required by reporter-ureporter (mandatory
+# in uReport).
+#
+
+test -f kernel || exit 1
+
+echo "Looking for kernel package"
+package="$( rpm -q kernel kernel-PAE | grep "$( sed 's/ .*//' kernel )")"
+if [ $? == 0 ]; then
+ echo "Kernel package $package found"
+ rpm -q --qf "%{name}\n" "$package" > pkg_name
+ rpm -q --qf "%{arch}\n" "$package" > pkg_arch
+ rpm -q --qf "%{version}\n" "$package" > pkg_version
+ rpm -q --qf "%{release}\n" "$package" > pkg_release
+ epoch="$( rpm -q --qf "%{epoch}" "$package" )"
+ if [ "$epoch" == "(none)" ]; then
+ echo "0" > pkg_epoch
+ else
+ echo "$epoch" > pkg_epoch
+ fi
+else
+ echo "Kernel package not found"
+fi
diff --git a/src/plugins/koops_event.conf b/src/plugins/koops_event.conf
index 91759b1..9369131 100644
--- a/src/plugins/koops_event.conf
+++ b/src/plugins/koops_event.conf
@@ -3,6 +3,7 @@ EVENT=post-create analyzer=Kerneloops
abrt-action-analyze-oops &&
dmesg >dmesg &&
abrt-action-generate-core-backtrace
+ abrt-action-save-kernel-data
# If you want behavior similar to one provided by kerneloops daemon
# distributed by kerneloops.org - that is, if you want
--
1.7.11.4
11 years, 8 months
[LIBREPORT PATCH] rhbz#851855: process ureport server errors correctly
by Jakub Filak
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/plugins/ureport.c | 245 ++++++++++++++++++++++++++------------------------
1 file changed, 127 insertions(+), 118 deletions(-)
diff --git a/src/plugins/ureport.c b/src/plugins/ureport.c
index b48cabb..f4f2d32 100644
--- a/src/plugins/ureport.c
+++ b/src/plugins/ureport.c
@@ -45,22 +45,25 @@ static void load_ureport_server_config(struct ureport_server_config *config)
config->ur_ssl_verify = environ ? string_to_bool(environ) : config->ur_ssl_verify;
}
-
-enum response_type
-{
- UREPORT_SERVER_RESP_UNKNOWN_TYPE,
- UREPORT_SERVER_RESP_KNOWN,
- UREPORT_SERVER_RESP_ERROR,
-};
-
struct ureport_server_response {
- enum response_type type;
+ /* need it because we don't want to make a copy of each response field */
+ json_object *source;
+ bool is_error;
const char *value;
const char *message;
const char *bthash;
GList *reported_to_list;
};
+void free_ureport_server_response(struct ureport_server_response *resp)
+{
+ if (!resp)
+ return;
+
+ json_object_put(resp->source);
+ free(resp);
+}
+
/* reported_to json element should be a list of structures
{ "reporter": "Bugzilla",
"type": "url",
@@ -127,22 +130,23 @@ static GList *parse_reported_to_from_json_list(struct json_object *list)
* {"response":"true"}
* {"response":"false"}
*/
-static bool ureport_server_parse_json(json_object *json, struct ureport_server_response *out_response)
+static struct ureport_server_response *ureport_server_parse_json(json_object *json)
{
json_object *obj = json_object_object_get(json, "error");
if (obj)
{
- out_response->type = UREPORT_SERVER_RESP_ERROR;
+ struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
+ out_response->is_error = true;
out_response->value = json_object_to_json_string(obj);
- return true;
+ return out_response;
}
obj = json_object_object_get(json, "result");
if (obj)
{
- out_response->type = UREPORT_SERVER_RESP_KNOWN;
+ struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
out_response->value = json_object_get_string(obj);
json_object *message = json_object_object_get(json, "message");
@@ -157,29 +161,83 @@ static bool ureport_server_parse_json(json_object *json, struct ureport_server_r
if (reported_to_list)
out_response->reported_to_list = parse_reported_to_from_json_list(reported_to_list);
- return true;
+ return out_response;
+ }
+
+ return NULL;
+}
+
+static struct ureport_server_response *get_server_response(post_state_t *post_state)
+{
+ if (post_state->http_resp_code == 404)
+ {
+ error_msg(_("Can't get server response because of invalid url"));
+ return NULL;
+ }
+
+ json_object *const json = json_tokener_parse(post_state->body);
+
+ if (is_error(json))
+ {
+ error_msg(_("Unable to parse response from ureport server"));
+ json_object_put(json);
+ return NULL;
+ }
+
+ struct ureport_server_response *response = ureport_server_parse_json(json);
+
+ if (response)
+ response->source = json;
+ else
+ json_object_put(json);
+
+ if (post_state->http_resp_code == 202)
+ {
+ if (!response)
+ error_msg(_("Server response data has invalid format"));
+ else if (response->is_error)
+ {
+ /* HTTP CODE 202 means that call was successful but the response */
+ /* has an error message */
+ error_msg(_("Server response type mismatch"));
+ free_ureport_server_response(response);
+ response = NULL;
+ }
+ }
+ else if (!response || !response->is_error)
+ {
+ /* can't print better error message */
+ error_msg(_("Unexpected HTTP status code: %d"), post_state->http_resp_code);
+ free_ureport_server_response(response);
+ response = NULL;
}
- out_response->type = UREPORT_SERVER_RESP_UNKNOWN_TYPE;
- return false;
+end_server_response:
+ return response;
}
-static bool check_response_statuscode(post_state_t *post_state,
- const char *url)
+static bool perform_attach(struct ureport_server_config *config, const char *ureport_hash, int rhbz_bug)
{
- if (post_state->http_resp_code != 202)
+ char *dest_url = xasprintf("%s%s", config->ur_url, ATTACH_URL_SFX);
+ const char *old_url = config->ur_url;
+ config->ur_url = dest_url;
+ post_state_t *post_state = ureport_attach_rhbz(ureport_hash, rhbz_bug, config);
+ config->ur_url = old_url;
+ free(dest_url);
+
+ struct ureport_server_response *resp = get_server_response(post_state);
+ free_post_state(post_state);
+ /* don't use str_bo_bool() because we require "true" string */
+ const int result = !resp || resp->is_error || strcmp(resp->value,"true") != 0;
+
+ if (resp && resp->is_error)
{
- char *errmsg = post_state->curl_error_msg;
- if (errmsg && *errmsg)
- error_msg("%s '%s'", errmsg, url);
- else
- error_msg("Unexpected HTTP status code: %d",
- post_state->http_resp_code);
-
- return false;
+ VERB1 error_msg(_("Server side error: '%s'"), resp->value);
}
- return true;
+ free_ureport_server_response(resp);
+
+ return result;
}
int main(int argc, char **argv)
@@ -226,15 +284,7 @@ int main(int argc, char **argv)
/* we either need both -b & -a or none of them */
if (ureport_hash && rhbz_bug > 0)
{
- char *dest_url = xasprintf("%s%s", config.ur_url, ATTACH_URL_SFX);
- config.ur_url = dest_url;
- post_state = ureport_attach_rhbz(ureport_hash, rhbz_bug, &config);
- const int result = !check_response_statuscode(post_state, dest_url);
-
- free_post_state(post_state);
- free(dest_url);
-
- return result;
+ return perform_attach(&config, ureport_hash, rhbz_bug);
}
else if (ureport_hash && rhbz_bug <= 0)
error_msg_and_die(_("You need to specify bug ID to attach."));
@@ -274,16 +324,7 @@ int main(int argc, char **argv)
free_report_result(bz_result);
- char *dest_url = xasprintf("%s%s", config.ur_url, ATTACH_URL_SFX);
- config.ur_url = dest_url;
- post_state = ureport_attach_rhbz(bthash, bugid, &config);
- free(bthash);
-
- int ret = !check_response_statuscode(post_state, dest_url);
- free_post_state(post_state);
- free(dest_url);
-
- return ret;
+ return perform_attach(&config, bthash, bugid);
}
/* -b, -a nor -r were specified - upload uReport from dump_dir */
@@ -295,96 +336,64 @@ int main(int argc, char **argv)
char *dest_url = xasprintf("%s%s", config.ur_url, REPORT_URL_SFX);
config.ur_url = dest_url;
post_state = post_ureport(pd, &config);
+ free(dest_url);
problem_data_free(pd);
int ret = 1; /* return 1 by default */
- if (!check_response_statuscode(post_state, dest_url))
- /* check_response_statuscode() already logged an error message */
- goto err;
-
- json_object *const json = json_tokener_parse(post_state->body);
-
- if (is_error(json))
- {
- error_msg("fatal: unable to parse response from ureport server");
- goto err;
- }
-
- struct ureport_server_response response = {
- .type=UREPORT_SERVER_RESP_UNKNOWN_TYPE,
- .value=NULL,
- .message=NULL,
- .bthash=NULL,
- };
-
- const bool is_valid_response = ureport_server_parse_json(json, &response);
+ struct ureport_server_response *response = get_server_response(post_state);
- if (!is_valid_response)
- {
- error_msg("fatal: wrong format of response from ureport server");
+ if (!response)
goto format_err;
- }
- switch (response.type)
+ if (!response->is_error)
{
- case UREPORT_SERVER_RESP_KNOWN:
- VERB1 log("is known: %s", response.value);
- ret = 0;
+ VERB1 log("is known: %s", response->value);
+ ret = 0;
- if (response.bthash)
- {
- dd = dd_opendir(dump_dir_path, /* flags */ 0);
- if (!dd)
- xfunc_die();
+ if (response->bthash)
+ {
+ dd = dd_opendir(dump_dir_path, /* flags */ 0);
+ if (!dd)
+ xfunc_die();
- char *msg = xasprintf("uReport: BTHASH=%s", response.bthash);
- add_reported_to(dd, msg);
- free(msg);
+ char *msg = xasprintf("uReport: BTHASH=%s", response->bthash);
+ add_reported_to(dd, msg);
+ free(msg);
- if (response.reported_to_list)
+ if (response->reported_to_list)
+ {
+ GList *elem = response->reported_to_list;
+ while (elem)
{
- GList *elem = response.reported_to_list;
- while (elem)
- {
- add_reported_to(dd, elem->data);
- free(elem->data);
- elem = g_list_next(elem);
- }
-
- g_list_free(response.reported_to_list);
+ add_reported_to(dd, elem->data);
+ free(elem->data);
+ elem = g_list_next(elem);
}
- dd_close(dd);
+ g_list_free(response->reported_to_list);
}
- /* If a reported problem is not known then emit NEEDMORE */
- if (strcmp("true", response.value) == 0)
- {
- log("This problem has already been reported.");
- if (response.message)
- log(response.message);
- log("THANKYOU");
- }
- break;
- case UREPORT_SERVER_RESP_ERROR:
- VERB1 log("server side error: %s", response.value);
- ret = 1; /* just to be sure */
- break;
- case UREPORT_SERVER_RESP_UNKNOWN_TYPE:
- error_msg("invalid server response: %s", response.value);
- ret = 1; /* just to be sure */
- break;
- default:
- error_msg("reporter internal error: missing handler for response type");
- ret = 1; /* just to be sure */
- break;
+ dd_close(dd);
+ }
+
+ /* If a reported problem is not known then emit NEEDMORE */
+ if (strcmp("true", response->value) == 0)
+ {
+ log("This problem has already been reported.");
+ if (response->message)
+ log(response->message);
+ log("THANKYOU");
+ }
+ }
+ else
+ {
+ VERB1 log("server side error: %s", response->value);
}
+ free_ureport_server_response(response);
+
format_err:
- json_object_put(json);
-err:
- free(dest_url);
free_post_state(post_state);
return ret;
--
1.7.11.4
11 years, 8 months
[LIBREPORT PATCH] trac#688: do not store configuration options as Item look attributes
by Jakub Filak
- all configuration options are stored as binary data in Secret
member of Item interface
- each option is stored as c-string 'name=value\0' and a secret value
consists from concatenation of corresponding strings for all options
- lookup attributes contain only 'libreportEventConfig' key and and the
key is associated with event name
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/gtk-helpers/secrets.c | 278 ++++++++++++++++++++++++++++++----------------
1 file changed, 185 insertions(+), 93 deletions(-)
diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c
index ee6a348..07f3be3 100644
--- a/src/gtk-helpers/secrets.c
+++ b/src/gtk-helpers/secrets.c
@@ -29,6 +29,7 @@
#define SECRETS_COLLECTION_ALIAS "default"
#define SECRETS_SEARCH_ATTRIBUTE "libreportEventConfig"
+#define SECRETS_OPTION_VALUE_DELIMITER '='
/* 5s timeout*/
#define SECRETS_CALL_DEFAULT_TIMEOUT 5000
@@ -47,12 +48,23 @@
Collection is a set of Items identified by labels (label is a string).
Libreport uses event names as labels for items which hold event config data.
+ One item holds all configuration items for one event.
+
+ Item has a set of (name,value) pairs called lookup attributes.
+ Libreport uses 'libreportEventConfig' attribute for searching. The
+ attribute hodls an event name.
+ Item has a secret value. The value holds an arbitrary binary data.
+ Libreport uses the value to store configuration items.
+ The value consists from several c-strings where each option is
+ represented by one c-string (bytes followed by '\0').
+ Each option string is concatenation of option name, delimiter and option value.
+
+
+ For example, "report_Bugzilla" item will have the lookup attribute
+ like ("libreportEventConfig", "report_Bugzilla") and the secret value
+ like ("Bugzilla_URL=https://bugzilla.redhat.com\0Bugzilla_Login=foo\0")
- Item is a set of (name,value) pairs called attributes.
- Libreport uses attributes to store config data.
- For example, "report_Bugzilla" item will have some attributes,
- like ("Bugzilla_BugzillaURL", "https://bugzilla.redhat.com").
DBus API:
=========
@@ -246,32 +258,6 @@ static GDBusProxy *secrets_object_get_properties_proxy(struct secrets_object *ob
return obj->property_proxy;
}
-
-static bool secrets_object_set_dbus_property(struct secrets_object *obj,
- const char *property,
- GVariant *value)
-{
- GDBusProxy *properties = secrets_object_get_properties_proxy(obj);
-
- if (!properties)
- return false;
-
- /* http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfac... */
- /* org.freedesktop.DBus.Properties.Set (IN String interface_name, IN String property_name, IN Variant value); */
- GVariant *const resp = dbus_call_sync(properties,
- "Set",
- g_variant_new("(ssv)",
- obj->interface_name,
- property,
- value)
- );
-
- if (resp)
- g_variant_unref(resp);
-
- return resp;
-}
-
/*******************************************************************************/
/* struct secrets_service */
/*******************************************************************************/
@@ -472,6 +458,7 @@ static GVariant *secrets_prompt(const char *prompt_path,
.closure_marshal = NULL,
};
+ /* TODO : leak */
GDBusProxy *const prompt_proxy = get_dbus_proxy(prompt_path, SECRETS_NAME_SPACE("Prompt"));
*dismissed = false;
@@ -544,6 +531,7 @@ static GVariant *secrets_service_unlock(const gchar *const *objects,
gchar *prompt = NULL;
GVariant *result = NULL;
+ /* TODO : leak */
g_variant_get(var, "(@aoo)", &result, &prompt);
*dismissed = false;
@@ -774,6 +762,7 @@ static struct secrets_object *secrets_service_create_collection(const gchar *lab
gchar *prompt = NULL;
GVariant *collection_var = NULL;
+ /* TODO : leak */
g_variant_get(resp, "(@oo)", &collection_var, &prompt);
if (is_prompt_required(prompt))
@@ -810,7 +799,7 @@ static struct secrets_object *secrets_service_create_collection(const gchar *lab
static GVariant *create_item_call_args(const char *event_name,
GVariant *attributes,
- GDBusProxy *session,
+ GVariant *secret,
bool full_property_name)
{
/* gnome-keyring accepts properties with namespace */
@@ -842,21 +831,60 @@ static GVariant *create_item_call_args(const char *event_name,
g_variant_builder_add(prop_builder, "{sv}", lbl_name, g_variant_new_string(event_name));
g_variant_builder_add(prop_builder, "{sv}", att_name, attributes);
- GVariantBuilder *const param_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ GVariant *const prop = g_variant_builder_end(prop_builder);
+
+ return g_variant_new("(@a{sv}@(oayays)b)", prop, secret, FALSE);
+}
+
+static GVariant *create_secret_from_options(GDBusProxy *session, GList *options, bool store_passwords)
+{
GVariantBuilder *const value_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ for (GList *iter = g_list_first(options); iter; iter = g_list_next(iter))
+ {
+ event_option_t *const op = (event_option_t *)iter->data;
+ /* TODO : is it still necessary? Passwords are encrypted now. */
+ if (op->eo_type != OPTION_TYPE_PASSWORD || store_passwords)
+ {
+ const char *byte = op->eo_name;
+ while(byte[0] != '\0')
+ g_variant_builder_add(value_builder, "y", *byte++);
+
+ g_variant_builder_add(value_builder, "y", SECRETS_OPTION_VALUE_DELIMITER);
- GVariant *const secret = g_variant_new("(o@ay@ays)",
- g_dbus_proxy_get_object_path(session),
- g_variant_builder_end(param_builder),
- g_variant_builder_end(value_builder),
- "text/plain, charset=utf8");
+ byte = op->eo_value;
+ while(byte[0] != '\0')
+ g_variant_builder_add(value_builder, "y", *byte++);
- return g_variant_new("(@a{sv}@(oayays)b)", g_variant_builder_end(prop_builder), secret, FALSE);
+ g_variant_builder_add(value_builder, "y", '\0');
+ }
+ }
+
+ GVariant *const value = g_variant_builder_end(value_builder);
+
+ return g_variant_new("(oay@ays)",
+ g_dbus_proxy_get_object_path(session),
+ /* param */ NULL,
+ value,
+ "application/libreport");
+}
+
+static GVariant *create_lookup_attributes(const char *event_name)
+{
+ GVariantBuilder *const attr_builder = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+ /* add extra attribute used for searching */
+ g_variant_builder_add(attr_builder, "{ss}", SECRETS_SEARCH_ATTRIBUTE, event_name);
+
+ /* An example of attributes: */
+ /* { */
+ /* "libreportEventConfig": "event_name", */
+ /* } */
+ return g_variant_builder_end(attr_builder);
}
static bool secrets_collection_create_text_item(struct secrets_object *collection,
const char *event_name,
GVariant *attributes,
+ GVariant *secret,
bool *dismissed)
{
bool succ = false;
@@ -903,8 +931,10 @@ static bool secrets_collection_create_text_item(struct secrets_object *collectio
/* prompt : A prompt object, or the special value '/' if no prompt */
/* is necessary. */
GVariant *const resp = g_dbus_proxy_call_sync(collection->proxy, "CreateItem",
- create_item_call_args(event_name, g_variant_ref(attributes),
- g_session_proxy, options[choice]),
+ create_item_call_args(event_name,
+ g_variant_ref(attributes),
+ g_variant_ref(secret),
+ options[choice]),
G_DBUS_PROXY_FLAGS_NONE, SECRETS_CALL_DEFAULT_TIMEOUT,
NULL, &error);
@@ -924,6 +954,7 @@ static bool secrets_collection_create_text_item(struct secrets_object *collectio
gchar *prompt = NULL;
gchar *item = NULL;
+ /* TODO : leak */
g_variant_get(resp, "(oo)", &item, &prompt);
/* if prompt is no required the function is successfull */
@@ -941,6 +972,7 @@ static bool secrets_collection_create_text_item(struct secrets_object *collectio
}
g_variant_unref(attributes);
+ g_variant_unref(secret);
return succ;
}
@@ -1052,68 +1084,119 @@ static bool get_default_collection(struct secrets_object **collection,
return succ;
}
-static void load_event_options_from_item(GList *options,
+static void load_event_options_from_item(GDBusProxy *session,
+ GList *options,
struct secrets_object *item)
{
- GVariant *const attributes =
- g_dbus_proxy_get_cached_property(item->proxy, "Attributes");
+ { /* for backward compatibility */
+ /* load configuration from lookup attributes but don't store configuration in lookup attributes */
+ GVariant *const attributes =
+ g_dbus_proxy_get_cached_property(item->proxy, "Attributes");
- GVariantIter *iter = NULL;
- g_variant_get(attributes, "a{ss}", &iter);
+ GVariantIter *iter = NULL;
+ g_variant_get(attributes, "a{ss}", &iter);
- gchar *name = NULL;
- gchar *value = NULL;
- while (g_variant_iter_loop(iter, "{ss}", &name, &value))
- {
- event_option_t *const option = get_event_option_from_list(name, options);
- if (option)
+ gchar *name = NULL;
+ gchar *value = NULL;
+ while (g_variant_iter_loop(iter, "{ss}", &name, &value))
{
- free(option->eo_value);
- option->eo_value = xstrdup(value);
- VERB2 log("loaded event option : '%s => %s'", name, option->eo_value);
+ event_option_t *const option = get_event_option_from_list(name, options);
+ if (option)
+ {
+ free(option->eo_value);
+ option->eo_value = xstrdup(value);
+ VERB2 log("loaded event option : '%s' => '%s'", name, option->eo_value);
+ }
}
+
+ g_variant_unref(attributes);
}
- g_variant_unref(attributes);
-}
+ { /* read configuration from the secret value */
+ GVariant *const resp =
+ dbus_call_sync(item->proxy, "GetSecret", g_variant_new("(o)", g_dbus_proxy_get_object_path(session)));
-static GVariant *create_attributes_from_options(GList *options,
- const char *event_name,
- bool store_passwords)
-{
- GVariantBuilder *const attr_builder = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
- for (GList *iter = g_list_first(options); iter; iter = g_list_next(iter))
- { /* we store data in the search attributes */
- event_option_t *const op = (event_option_t *)iter->data;
- if (op->eo_type != OPTION_TYPE_PASSWORD || store_passwords)
- g_variant_builder_add(attr_builder, "{ss}", op->eo_name, op->eo_value);
- }
+ if (!resp)
+ return;
- /* and finally, add extra attribute used for searching */
- g_variant_builder_add(attr_builder, "{ss}", SECRETS_SEARCH_ATTRIBUTE, event_name);
+ if (g_variant_n_children(resp) == 0)
+ {
+ VERB1 log("response from GetSecret() method doesn't contain data: '%s'", g_variant_print(resp, TRUE));
+ return;
+ }
- /* An example of attributes: */
- /* { */
- /* "BugzillaURL": "Value1", */
- /* "BugzillaPassword": "Value2", */
- /* "libreportEventConfig": "event_name", */
- /* } */
- return g_variant_builder_end(attr_builder);
+ /* All dbus responses are returned inside of an variant */
+ GVariant *const secret = g_variant_get_child_value(resp, 0);
+
+ /* DBus represents a structure as a tuple of values */
+ /* struct Secret
+ * {
+ * (o) object path
+ * (ay) byte array params
+ * (ay) byte array value
+ * (s) string content type
+ * }
+ */
+ if (g_variant_n_children(secret) != 4)
+ {
+ VERB1 log("secret value has invalid structure: '%s'", g_variant_print(secret, TRUE));
+ return;
+ }
+
+ /* get (ay) byte array value */
+ GVariant *const secret_value = g_variant_get_child_value(secret, 2);
+
+ gsize nelems;
+ gconstpointer data = g_variant_get_fixed_array(secret_value, &nelems, sizeof(guchar));
+
+ while(nelems > 0)
+ {
+ const size_t sz = strlen(data) + 1;
+ if (sz > nelems)
+ { /* check next size, if is too big then trailing 0 is probably missing */
+ VERB1 log("broken secret value, atttempts to read %zdB but only %zdB are available)", sz, nelems);
+ break;
+ }
+ nelems -= sz;
+
+ char *name = xstrdup(data);
+ char *value = strchr(name, SECRETS_OPTION_VALUE_DELIMITER);
+ if (!value)
+ {
+ VERB1 log("secret value has invalid format: missing delimiter after option name");
+ goto next_option;
+ }
+
+ *value++ = '\0';
+
+ event_option_t *const option = get_event_option_from_list(name, options);
+ if (option)
+ {
+ free(option->eo_value);
+ option->eo_value = xstrdup(value);
+ VERB2 log("loaded event option : '%s' => '%s'", name, option->eo_value);
+ }
+
+next_option:
+ free(name);
+ data += sz;
+ }
+
+ g_variant_unref(secret_value);
+ g_variant_unref(secret);
+ g_variant_unref(resp);
+ }
}
static bool find_item_by_event_name(const struct secrets_object *collection,
const char *event_name,
struct secrets_object **item)
{
- GVariantBuilder *const attrs = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
-
- /* For searching uses item's attribute holding an event name */
- g_variant_builder_add(attrs, "{ss}", SECRETS_SEARCH_ATTRIBUTE, event_name);
-
- return secrets_collection_search_one_item(collection, g_variant_builder_end(attrs), item);
+ return secrets_collection_search_one_item(collection, create_lookup_attributes(event_name), item);
}
-static void load_settings(struct secrets_object *collection, const char *event_name, event_config_t *ec)
+static void load_settings(GDBusProxy *session, struct secrets_object *collection,
+ const char *event_name, event_config_t *ec)
{
/* Locked property is not supported by ksecrets */
/* thus we have to perform Unlock for each call of load settings */
@@ -1128,7 +1211,7 @@ static void load_settings(struct secrets_object *collection, const char *event_n
if (succ && item)
{
VERB2 log("loading event config : '%s'", event_name);
- load_event_options_from_item(ec->options, item);
+ load_event_options_from_item(session, ec->options, item);
secrets_object_delete(item);
item = NULL;
}
@@ -1145,7 +1228,7 @@ static void load_event_config(gpointer key, gpointer value, gpointer user_data)
struct secrets_object *const collection = (struct secrets_object *)user_data;
if (is_event_config_user_storage_available())
- load_settings(collection, event_name, ec);
+ load_settings(g_session_proxy, collection, event_name, ec);
}
static bool save_options(struct secrets_object *collection,
@@ -1160,22 +1243,31 @@ static bool save_options(struct secrets_object *collection,
if (!succ)
return succ;
- GVariant *const attributes = create_attributes_from_options(options,
- event_name,
- store_passwords);
+ GVariant *const secret = create_secret_from_options(g_session_proxy, options, store_passwords);
if (item)
- { /* item exists, change Attributes */
+ { /* item exists, change a secret */
VERB2 log("updating event config : '%s'", event_name);
+ /* can't be dismissed */
*dismissed = false;
- succ = secrets_object_set_dbus_property(item, "Attributes", attributes);
+ GVariant *const args = g_variant_new("(@(oayays))", secret);
+ GVariant *const resp = dbus_call_sync(item->proxy, "SetSecret", args);
+ succ = resp;
+
+ if (succ)
+ g_variant_unref(resp);
+
secrets_object_delete(item);
- item = NULL;
}
else
- { /* create a new item with Attributes */
+ { /* create a new item */
+ GVariant *const attributes = create_lookup_attributes(event_name);
VERB2 log("creating event config : '%s'", event_name);
- succ = secrets_collection_create_text_item(collection, event_name, attributes, dismissed);
+ succ = secrets_collection_create_text_item(collection, event_name, attributes, secret, dismissed);
+
+ /* I can't figure out why I have to do the following */
+ g_variant_unref(attributes);
+ g_variant_unref(secret);
}
return succ;
--
1.7.11.4
11 years, 8 months
[PATCH] reporter-ureport: save reported_to from server response
by Michal Toman
---
src/plugins/ureport.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/src/plugins/ureport.c b/src/plugins/ureport.c
index 96c7878..b48cabb 100644
--- a/src/plugins/ureport.c
+++ b/src/plugins/ureport.c
@@ -58,8 +58,69 @@ struct ureport_server_response {
const char *value;
const char *message;
const char *bthash;
+ GList *reported_to_list;
};
+/* reported_to json element should be a list of structures
+{ "reporter": "Bugzilla",
+ "type": "url",
+ "value": "https://bugzilla.redhat.com/show_bug.cgi?id=XYZ" } */
+static GList *parse_reported_to_from_json_list(struct json_object *list)
+{
+ int i;
+ json_object *list_elem, *struct_elem;
+ const char *reporter, *value, *type;
+ char *reported_to_line, *prefix;
+ GList *result = NULL;
+
+ for (i = 0; i < json_object_array_length(list); ++i)
+ {
+ prefix = NULL;
+ list_elem = json_object_array_get_idx(list, i);
+ if (!list_elem)
+ continue;
+
+ struct_elem = json_object_object_get(list_elem, "reporter");
+ if (!struct_elem)
+ continue;
+
+ reporter = json_object_get_string(struct_elem);
+ if (!reporter)
+ continue;
+
+ struct_elem = json_object_object_get(list_elem, "value");
+ if (!struct_elem)
+ continue;
+
+ value = json_object_get_string(struct_elem);
+ if (!value)
+ continue;
+
+ struct_elem = json_object_object_get(list_elem, "type");
+ if (!struct_elem)
+ continue;
+
+ type = json_object_get_string(struct_elem);
+ if (type)
+ {
+ if (strcasecmp("url", type) == 0)
+ prefix = xstrdup("URL=");
+ else if (strcasecmp("bthash", type) == 0)
+ prefix = xstrdup("BTHASH=");
+ }
+
+ if (!prefix)
+ prefix = xstrdup("");
+
+ reported_to_line = xasprintf("%s: %s%s", reporter, prefix, value);
+ free(prefix);
+
+ result = g_list_append(result, reported_to_line);
+ }
+
+ return result;
+}
+
/*
* Reponse samples:
* {"error":"field 'foo' is required"}
@@ -92,6 +153,10 @@ static bool ureport_server_parse_json(json_object *json, struct ureport_server_r
if (bthash)
out_response->bthash = json_object_get_string(bthash);
+ json_object *reported_to_list = json_object_object_get(json, "reported_to");
+ if (reported_to_list)
+ out_response->reported_to_list = parse_reported_to_from_json_list(reported_to_list);
+
return true;
}
@@ -276,6 +341,20 @@ int main(int argc, char **argv)
char *msg = xasprintf("uReport: BTHASH=%s", response.bthash);
add_reported_to(dd, msg);
free(msg);
+
+ if (response.reported_to_list)
+ {
+ GList *elem = response.reported_to_list;
+ while (elem)
+ {
+ add_reported_to(dd, elem->data);
+ free(elem->data);
+ elem = g_list_next(elem);
+ }
+
+ g_list_free(response.reported_to_list);
+ }
+
dd_close(dd);
}
--
1.7.1
11 years, 8 months