diff options
author | Nikola Pajkovsky <npajkovs@redhat.com> | 2010-01-21 17:55:12 +0100 |
---|---|---|
committer | Nikola Pajkovsky <npajkovs@redhat.com> | 2010-01-21 17:55:12 +0100 |
commit | 6a332432509a6c7299d212b1bb769cf6dd054758 (patch) | |
tree | e935a2b4806f10fbb1b5ae448c7427d304f2c439 | |
parent | 2afa768308a7f00f0f0d5c4a95f5b20e8c62ef39 (diff) | |
parent | 44d7d1e6acb25dc719838560b002514fc51b62c3 (diff) | |
download | abrt-6a332432509a6c7299d212b1bb769cf6dd054758.tar.gz abrt-6a332432509a6c7299d212b1bb769cf6dd054758.tar.xz abrt-6a332432509a6c7299d212b1bb769cf6dd054758.zip |
Merge branch 'master' into hotfix
-rw-r--r-- | abrt.spec | 30 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | inc/CrashTypes.h | 50 | ||||
-rw-r--r-- | lib/Plugins/Bugzilla.cpp | 4 | ||||
-rw-r--r-- | lib/Plugins/Catcut.cpp | 2 | ||||
-rw-r--r-- | lib/Plugins/FileTransfer.cpp | 6 | ||||
-rw-r--r-- | lib/Plugins/Mailx.cpp | 20 | ||||
-rw-r--r-- | lib/Plugins/TicketUploader.h | 1 | ||||
-rw-r--r-- | lib/Utils/CrashTypes.cpp | 83 | ||||
-rw-r--r-- | lib/Utils/make_descr.cpp | 20 | ||||
-rw-r--r-- | lib/Utils/test.cpp | 8 | ||||
-rw-r--r-- | po/nl.po | 199 | ||||
-rwxr-xr-x | scripts/abrt-bz-stats | 156 | ||||
-rw-r--r-- | src/CLI/CLI.cpp | 18 | ||||
-rw-r--r-- | src/CLI/report.cpp | 12 | ||||
-rw-r--r-- | src/Daemon/CommLayerServerDBus.cpp | 7 | ||||
-rw-r--r-- | src/Daemon/CommLayerServerSocket.cpp | 3 | ||||
-rw-r--r-- | src/Daemon/CrashWatcher.cpp | 13 | ||||
-rw-r--r-- | src/Daemon/CrashWatcher.h | 2 | ||||
-rw-r--r-- | src/Daemon/Daemon.cpp | 14 | ||||
-rw-r--r-- | src/Daemon/MiddleWare.cpp | 273 | ||||
-rw-r--r-- | src/Gui/CCDump.py | 61 | ||||
-rw-r--r-- | src/Gui/CCMainWindow.py | 24 | ||||
-rw-r--r-- | src/Gui/CCReporterDialog.py | 160 | ||||
-rw-r--r-- | src/Gui/CC_gui_functions.py | 11 | ||||
-rw-r--r-- | src/Gui/PluginList.py | 5 |
26 files changed, 719 insertions, 465 deletions
@@ -3,7 +3,7 @@ %{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} Summary: Automatic bug detection and reporting tool Name: abrt -Version: 1.0.3 +Version: 1.0.4 Release: 1%{?dist} License: GPLv2+ Group: Applications/System @@ -402,6 +402,34 @@ fi %defattr(-,root,root,-) %changelog +* Wed Jan 20 2010 Jiri Moskovcak <jmoskovc@redhat.com> 1.0.4-1 +- GUI: redesign of reporter dialog (jmoskovc@redhat.com) +- Set the prgname to "Automatic Bug Reporting Tool" fixes rhbz#550357 (jmoskovc@redhat.com) +- CCpp analyzer: display __abort_msg in backtrace. closes rhbz#549735 (vda.linux@googlemail.com) +- s/os.exit/sys.exit - closes rhbz#556313 (vda.linux@googlemail.com) +- use repr() to print variable values in python hook rhbz#545070 (jmoskovc@redhat.com) +- gui: add logging infrastructure (vda.linux@googlemail.com) +- Added "Enabled = yes" to all plugin's config files (jmoskovc@redhat.com) +- *: disable plugin loading/unloading through GUI. Document keyring a bit (vda.linux@googlemail.com) +- fix memory leaks in catcut plugin (npajkovs@redhat.com) +- fix memory leaks in bugzilla (npajkovs@redhat.com) +- abrt-hook-python: sanitize input more; log to syslog (vda.linux@googlemail.com) +- Fixed /var/cache/abrt/ permissions (kklic@redhat.com) +- Kerneloops: we require commandline for every crash, save dummy one for oopses (vda.linux@googlemail.com) +- *: remove nss dependencies (vda.linux@googlemail.com) +- CCpp: use our own sha1 implementation (less pain with nss libs) (vda.linux@googlemail.com) +- DebugDump: more consistent logic in setting mode and uid:gid on dump dir (vda.linux@googlemail.com) +- fixes based on security review (vda.linux@googlemail.com) +- SOSreport/TicketUploader: use more restrictive file modes (vda.linux@googlemail.com) +- abrt-hook-python: add input sanitization and directory size guard (vda.linux@googlemail.com) +- RunApp: safer chdir. Overhauled "sparn a child and get its output" in general (vda.linux@googlemail.com) +- DebugDump: use more restrictive modes (vda.linux@googlemail.com) +- SQLite3: check for SQL injection (vda.linux@googlemail.com) +- replace plugin enabling via EnabledPlugins by par-plugin Enabled = yes/no (vda.linux@googlemail.com) +- abrt.spec: move "requires: gdb" to abrt-desktop (vda.linux@googlemail.com) +- ccpp: add a possibility to disable backtrace generation (vda.linux@googlemail.com) +- abrtd: limit the number of frames in backtrace to 3000 (vda.linux@googlemail.com) + * Tue Jan 5 2010 Jiri Moskovcak <jmoskovc@redhat.com> 1.0.3-1 - speed optimalization of abrt-debuginfo-install (jmoskovc@redhat.com) - updated credits (jmoskovc@redhat.com) diff --git a/configure.ac b/configure.ac index 4f73d07a..6cc65a8a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([abrt], [1.0.3], [crash-catcher@fedorahosted.org]) +AC_INIT([abrt], [1.0.4], [crash-catcher@fedorahosted.org]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) diff --git a/inc/CrashTypes.h b/inc/CrashTypes.h index 9daefa93..b14413d5 100644 --- a/inc/CrashTypes.h +++ b/inc/CrashTypes.h @@ -45,21 +45,18 @@ #define FILENAME_MEMORYMAP "memorymap" #define FILENAME_KERNELOOPS "kerneloops" +#define CD_DUPHASH "DUPHASH" #define CD_UUID "UUID" -#define CD_UID "UID" +#define CD_DUMPDIR "DumpDir" #define CD_COUNT "Count" -#define CD_EXECUTABLE "Executable" -#define CD_PACKAGE "Package" -#define CD_DESCRIPTION "Description" -#define CD_TIME "Time" #define CD_REPORTED "Reported" #define CD_MESSAGE "Message" -#define CD_COMMENT "Comment" -#define CD_REPRODUCE "How to reproduce" -#define CD_MWANALYZER "_MWAnalyzer" -#define CD_MWUID "_MWUID" -#define CD_MWUUID "_MWUUID" -#define CD_MWDDD "_MWDDD" + + +// Crash data is a map of 3-element vectors of strings: type, editable, content +#define CD_TYPE 0 +#define CD_EDITABLE 1 +#define CD_CONTENT 2 // SYS - system value, should not be displayed // BIN - binary data @@ -67,34 +64,35 @@ #define CD_SYS "s" #define CD_BIN "b" #define CD_TXT "t" - -/* Text bigger than this usually is attached, not added inline */ +// Text bigger than this usually is attached, not added inline #define CD_TEXT_ATT_SIZE (2*1024) -#define CD_ISEDITABLE "y" -#define CD_ISNOTEDITABLE "n" +#define CD_ISEDITABLE "y" +#define CD_ISNOTEDITABLE "n" + -#define CD_TYPE (0) -#define CD_EDITABLE (1) -#define CD_CONTENT (2) +extern const char *const must_have_files[]; + +bool is_editable_file(const char *file_name); -// currently, vector always has exactly 3 elements -> <type, editable, content> // <key, data> typedef map_vector_string_t map_crash_data_t; - typedef std::vector<map_crash_data_t> vector_map_crash_data_t; -void add_to_crash_data(map_crash_data_t& pCrashData, - const char *pItem, - const char *pContent); - void add_to_crash_data_ext(map_crash_data_t& pCrashData, const char *pItem, const char *pType, const char *pEditable, const char *pContent); +// Uses type:CD_TXT, editable:CD_ISNOTEDITABLE +void add_to_crash_data(map_crash_data_t& pCrashData, + const char *pItem, + const char *pContent); + +const char *get_crash_data_item_content_or_NULL(const map_crash_data_t& crash_data, const char *key); +// Aborts if key is not found: +const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key); -const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, - const char *key); +void log_map_crash_data(const map_crash_data_t& data, const char *name); #endif diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp index 5dc4298a..2fc2109a 100644 --- a/lib/Plugins/Bugzilla.cpp +++ b/lib/Plugins/Bugzilla.cpp @@ -297,7 +297,7 @@ uint32_t ctx::new_bug(const map_crash_data_t& pCrashData) const std::string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT); const std::string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE); const std::string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE); - const std::string& uuid = get_crash_data_item_content(pCrashData, CD_UUID); + const std::string& uuid = get_crash_data_item_content(pCrashData, CD_DUPHASH); std::string summary = "[abrt] crash in " + package; std::string status_whiteboard = "abrt_hash:" + uuid; @@ -444,7 +444,7 @@ std::string CReporterBugzilla::Report(const map_crash_data_t& pCrashData, } const std::string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT); - const std::string& uuid = get_crash_data_item_content(pCrashData, CD_UUID); + const std::string& uuid = get_crash_data_item_content(pCrashData, CD_DUPHASH); try { ctx bz_server(BugzillaXMLRPC.c_str(), NoSSLVerify); diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp index 1bc51f97..3580a3b4 100644 --- a/lib/Plugins/Catcut.cpp +++ b/lib/Plugins/Catcut.cpp @@ -272,7 +272,7 @@ ctx::new_bug(const char *auth_cookie, const map_crash_data_t& pCrashData) const string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT); const string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE); const string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE); - const string& uuid = get_crash_data_item_content(pCrashData, CD_UUID); + const string& uuid = get_crash_data_item_content(pCrashData, CD_DUPHASH); string summary = "[abrt] crash in " + package; string status_whiteboard = "abrt_hash:" + uuid; diff --git a/lib/Plugins/FileTransfer.cpp b/lib/Plugins/FileTransfer.cpp index b08ecd51..e28fbbee 100644 --- a/lib/Plugins/FileTransfer.cpp +++ b/lib/Plugins/FileTransfer.cpp @@ -25,12 +25,6 @@ #include <iostream> #include <sstream> #include <fstream> -#include <stdio.h> -#include <string.h> -#include <dirent.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> #include <zip.h> #include <libtar.h> #include <bzlib.h> diff --git a/lib/Plugins/Mailx.cpp b/lib/Plugins/Mailx.cpp index ae8c2dc9..2ee96455 100644 --- a/lib/Plugins/Mailx.cpp +++ b/lib/Plugins/Mailx.cpp @@ -74,13 +74,13 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData, args = append_str_to_vector(args, arg_size, MAILX_COMMAND); //TODO: move email body generation to make_descr.cpp - std::string binaryFiles, commonFiles, additionalFiles, UUIDFile; + std::string binaryFiles, commonFiles, additionalFiles, DUPHASHFile; map_crash_data_t::const_iterator it; for (it = pCrashData.begin(); it != pCrashData.end(); it++) { if (it->second[CD_TYPE] == CD_TXT) { - if (it->first != CD_UUID + if (it->first != CD_DUPHASH && it->first != FILENAME_ARCHITECTURE && it->first != FILENAME_KERNEL && it->first != FILENAME_PACKAGE @@ -90,12 +90,12 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData, additionalFiles += it->second[CD_CONTENT]; additionalFiles += "\n\n"; } - else if (it->first == CD_UUID) + else if (it->first == CD_DUPHASH) { - UUIDFile += it->first; - UUIDFile += "\n-----\n"; - UUIDFile += it->second[CD_CONTENT]; - UUIDFile += "\n\n"; + DUPHASHFile += it->first; + DUPHASHFile += "\n-----\n"; + DUPHASHFile += it->second[CD_CONTENT]; + DUPHASHFile += "\n\n"; } else { @@ -117,9 +117,9 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData, } } - std::string emailBody = "Duplicity check\n"; + std::string emailBody = "Duplicate check\n"; emailBody += "=====\n\n"; - emailBody += UUIDFile; + emailBody += DUPHASHFile; emailBody += "\nCommon information\n"; emailBody += "=====\n\n"; emailBody += commonFiles; @@ -135,7 +135,7 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData, args = append_str_to_vector(args, arg_size, m_sEmailTo.c_str()); update_client(_("Sending an email...")); - const char *uid_str = get_crash_data_item_content(pCrashData, CD_MWUID).c_str(); + const char *uid_str = get_crash_data_item_content(pCrashData, FILENAME_UID).c_str(); exec_and_feed_input(xatoi_u(uid_str), emailBody.c_str(), args); while (*args) diff --git a/lib/Plugins/TicketUploader.h b/lib/Plugins/TicketUploader.h index fcc59f06..7a371a3a 100644 --- a/lib/Plugins/TicketUploader.h +++ b/lib/Plugins/TicketUploader.h @@ -27,7 +27,6 @@ #include "Plugin.h" #include "Reporter.h" -//#include "CrashTypes.h" class CTicketUploader : public CReporter { diff --git a/lib/Utils/CrashTypes.cpp b/lib/Utils/CrashTypes.cpp index 4824e507..4fc93337 100644 --- a/lib/Utils/CrashTypes.cpp +++ b/lib/Utils/CrashTypes.cpp @@ -20,6 +20,40 @@ #include "abrtlib.h" #include "CrashTypes.h" +const char *const must_have_files[] = { + FILENAME_ARCHITECTURE, + FILENAME_KERNEL , + FILENAME_PACKAGE , + FILENAME_COMPONENT , + FILENAME_RELEASE , + FILENAME_EXECUTABLE , + NULL +}; + +static const char *const editable_files[] = { + FILENAME_DESCRIPTION, + FILENAME_COMMENT , + FILENAME_REPRODUCE , + FILENAME_BACKTRACE , + NULL +}; + +static bool is_editable(const char *name, const char *const *v) +{ + while (*v) { + if (strcmp(*v, name) == 0) + return true; + v++; + } + return false; +} + +bool is_editable_file(const char *file_name) +{ + return is_editable(file_name, editable_files); +} + + void add_to_crash_data_ext(map_crash_data_t& pCrashData, const char *pItem, const char *pType, @@ -28,9 +62,10 @@ void add_to_crash_data_ext(map_crash_data_t& pCrashData, { map_crash_data_t::iterator it = pCrashData.find(pItem); if (it == pCrashData.end()) { - pCrashData[pItem].push_back(pType); - pCrashData[pItem].push_back(pEditable); - pCrashData[pItem].push_back(pContent); + vector_string_t& v = pCrashData[pItem]; /* create empty vector */ + v.push_back(pType); + v.push_back(pEditable); + v.push_back(pContent); return; } vector_string_t& v = it->second; @@ -48,14 +83,50 @@ void add_to_crash_data(map_crash_data_t& pCrashData, add_to_crash_data_ext(pCrashData, pItem, CD_TXT, CD_ISNOTEDITABLE, pContent); } -const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key) +static const std::string* helper_get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key) { map_crash_data_t::const_iterator it = crash_data.find(key); if (it == crash_data.end()) { - error_msg_and_die("Error accessing crash data: no ['%s']", key); + return NULL; } if (it->second.size() <= CD_CONTENT) { + return NULL; + } + return &it->second[CD_CONTENT]; +} + +const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key) +{ + const std::string* sp = helper_get_crash_data_item_content(crash_data, key); + if (sp == NULL) { + if (crash_data.find(key) == crash_data.end()) + error_msg_and_die("Error accessing crash data: no ['%s']", key); error_msg_and_die("Error accessing crash data: no ['%s'][%d]", key, CD_CONTENT); } - return it->second[CD_CONTENT]; + return *sp; +} + +const char *get_crash_data_item_content_or_NULL(const map_crash_data_t& crash_data, const char *key) +{ + const std::string* sp = helper_get_crash_data_item_content(crash_data, key); + if (!sp) { + return NULL; + } + return sp->c_str(); +} + +void log_map_crash_data(const map_crash_data_t& data, const char *name) +{ + map_crash_data_t::const_iterator it = data.begin(); + while (it != data.end()) + { + ssize_t sz = it->second.size(); + log("%s[%s]:%s/%s/'%.20s'", + name, it->first.c_str(), + sz > 0 ? it->second[0].c_str() : "<NO [0]>", + sz > 1 ? it->second[1].c_str() : "<NO [1]>", + sz > 2 ? it->second[2].c_str() : "<NO [2]>" + ); + it++; + } } diff --git a/lib/Utils/make_descr.cpp b/lib/Utils/make_descr.cpp index e74e9b1d..a3ff5e24 100644 --- a/lib/Utils/make_descr.cpp +++ b/lib/Utils/make_descr.cpp @@ -58,13 +58,13 @@ string make_description_bz(const map_crash_data_t& pCrashData) map_crash_data_t::const_iterator end = pCrashData.end(); bool was_multiline = 0; - it = pCrashData.find(CD_REPRODUCE); + it = pCrashData.find(FILENAME_REPRODUCE); if (it != end && it->second[CD_CONTENT] != "1.\n2.\n3.\n") { add_content(was_multiline, description, "How to reproduce", it->second[CD_CONTENT].c_str()); } - it = pCrashData.find(CD_COMMENT); + it = pCrashData.find(FILENAME_COMMENT); if (it != end) { add_content(was_multiline, description, "Comment", it->second[CD_CONTENT].c_str()); @@ -80,11 +80,11 @@ string make_description_bz(const map_crash_data_t& pCrashData) { if (content.size() <= CD_TEXT_ATT_SIZE) { - if (filename != CD_UUID + if (filename != CD_DUPHASH && filename != FILENAME_ARCHITECTURE && filename != FILENAME_RELEASE - && filename != CD_REPRODUCE - && filename != CD_COMMENT + && filename != FILENAME_REPRODUCE + && filename != FILENAME_COMMENT ) { add_content(was_multiline, description, filename.c_str(), content.c_str()); } @@ -147,7 +147,7 @@ string make_description_catcut(const map_crash_data_t& pCrashData) map_crash_data_t::const_iterator it; string howToReproduce; - it = pCrashData.find(CD_REPRODUCE); + it = pCrashData.find(FILENAME_REPRODUCE); if (it != end) { howToReproduce = "\n\nHow to reproduce\n" @@ -155,7 +155,7 @@ string make_description_catcut(const map_crash_data_t& pCrashData) howToReproduce += it->second[CD_CONTENT]; } string comment; - it = pCrashData.find(CD_COMMENT); + it = pCrashData.find(FILENAME_COMMENT); if (it != end) { comment = "\n\nComment\n" @@ -178,11 +178,11 @@ string make_description_catcut(const map_crash_data_t& pCrashData) { if (content.length() <= CD_TEXT_ATT_SIZE) { - if (filename != CD_UUID + if (filename != CD_DUPHASH && filename != FILENAME_ARCHITECTURE && filename != FILENAME_RELEASE - && filename != CD_REPRODUCE - && filename != CD_COMMENT + && filename != FILENAME_REPRODUCE + && filename != FILENAME_COMMENT ) { pDescription += '\n'; pDescription += filename; diff --git a/lib/Utils/test.cpp b/lib/Utils/test.cpp index 160c107b..3711ef18 100644 --- a/lib/Utils/test.cpp +++ b/lib/Utils/test.cpp @@ -84,16 +84,16 @@ int main(int argc, char** argv) if (middleWare.SaveDebugDump(argv[1], crashInfo)) { std::cout << "Application Crashed! " << - crashInfo[CD_PACKAGE][CD_CONTENT] << ", " << - crashInfo[CD_EXECUTABLE][CD_CONTENT] << ", " << + crashInfo[FILENAME_PACKAGE][CD_CONTENT] << ", " << + crashInfo[FILENAME_EXECUTABLE][CD_CONTENT] << ", " << crashInfo[CD_COUNT][CD_CONTENT] << ", " << std::endl; /* Get Report, so user can change data (remove private stuff) * If we do not want user interaction, just send data immediately */ map_crash_data_t crashReport; - middleWare.CreateCrashReport(crashInfo[CD_UUID][CD_CONTENT], - crashInfo[CD_UID][CD_CONTENT], + middleWare.CreateCrashReport(crashInfo[CD_DUPHASH][CD_CONTENT], + crashInfo[FILENAME_UID][CD_CONTENT], crashReport); /* Report crash */ middleWare.Report(crashReport); @@ -7,13 +7,12 @@ # Geert Warrink <geert.warrink@onsnet.nu>, 2009. # Richard van der Luit <nippur@fedoraproject.org>, 2009. # Geert Warrink <geert.warrink@onsnet.nu>, 2009, 2010. -#: ../src/Gui/CCReporterDialog.py:208 msgid "" msgstr "" "Project-Id-Version: abrt.master\n" "Report-Msgid-Bugs-To: jmoskovc@redhat.com\n" -"POT-Creation-Date: 2010-01-14 15:35+0000\n" -"PO-Revision-Date: 2010-01-14 17:50+0100\n" +"POT-Creation-Date: 2010-01-21 04:02+0000\n" +"PO-Revision-Date: 2010-01-21 15:21+0100\n" "Last-Translator: Geert Warrink <geert.warrink@onsnet.nu>\n" "Language-Team: nl <fedora-trans-list@redhat.com>\n" "MIME-Version: 1.0\n" @@ -51,10 +50,6 @@ msgstr "Rapporteer plugins" msgid "Database plugins" msgstr "Databse plugins" -#: ../src/Gui/ABRTPlugin.py:99 -msgid "Plugin name is not set, can't load its settings" -msgstr "Plugin naam is niet ingesteld, kan zijn instellingen niet laden" - #: ../src/Gui/CCDBusBackend.py:74 ../src/Gui/CCDBusBackend.py:97 msgid "Can't connect to system dbus" msgstr "Kan niet verbinden met systeem dbus" @@ -79,7 +74,8 @@ msgstr "(C) 2009 Red Hat, Inc." msgid "About ABRT" msgstr "Over ABRT" -#: ../src/Gui/ccgui.glade.h:3 ../src/Gui/abrt.desktop.in.h:1 +#: ../src/Gui/ccgui.glade.h:3 ../src/Gui/CCMainWindow.py:9 +#: ../src/Gui/report.glade.h:15 ../src/Gui/abrt.desktop.in.h:1 msgid "Automatic Bug Reporting Tool" msgstr "Automatisch bug rapporteer gereedschap" @@ -103,7 +99,7 @@ msgstr "Wacht a.u.b..." msgid "Plugins" msgstr "Plugins" -#: ../src/Gui/ccgui.glade.h:9 ../src/Gui/report.glade.h:6 +#: ../src/Gui/ccgui.glade.h:9 msgid "Report" msgstr "Rapport" @@ -148,31 +144,31 @@ msgid "_Help" msgstr "_Hulp" #. add pixbuff separatelly -#: ../src/Gui/CCMainWindow.py:76 +#: ../src/Gui/CCMainWindow.py:78 msgid "Icon" msgstr "Icoon" -#: ../src/Gui/CCMainWindow.py:84 +#: ../src/Gui/CCMainWindow.py:86 msgid "Package" msgstr "Pakket" -#: ../src/Gui/CCMainWindow.py:85 +#: ../src/Gui/CCMainWindow.py:87 msgid "Application" msgstr "Toepassing" -#: ../src/Gui/CCMainWindow.py:86 +#: ../src/Gui/CCMainWindow.py:88 msgid "Date" msgstr "Datum" -#: ../src/Gui/CCMainWindow.py:87 +#: ../src/Gui/CCMainWindow.py:89 msgid "Crash count" msgstr "Crash count" -#: ../src/Gui/CCMainWindow.py:88 +#: ../src/Gui/CCMainWindow.py:90 msgid "User" msgstr "Gebruiker" -#: ../src/Gui/CCMainWindow.py:156 +#: ../src/Gui/CCMainWindow.py:158 #, python-format msgid "" "Can't show the settings dialog\n" @@ -181,7 +177,7 @@ msgstr "" "Kan de instellingen dialoog niet tonen\n" "%s" -#: ../src/Gui/CCMainWindow.py:167 +#: ../src/Gui/CCMainWindow.py:169 #, python-format msgid "" "Unable to finish current task!\n" @@ -191,7 +187,7 @@ msgstr "" "%s" #. there is something wrong with the daemon if we cant get the dumplist -#: ../src/Gui/CCMainWindow.py:194 +#: ../src/Gui/CCMainWindow.py:196 #, python-format msgid "" "Error while loading the dumplist.\n" @@ -200,15 +196,19 @@ msgstr "" "Fout tijdens het laden van de dumplijst.\n" "%s" -#: ../src/Gui/CCMainWindow.py:231 +#: ../src/Gui/CCMainWindow.py:233 +msgid "This crash has been reported:\n" +msgstr "Deze crash is gerapporteerd:\n" + +#: ../src/Gui/CCMainWindow.py:234 msgid "<b>This crash has been reported:</b>\n" msgstr "<b>Deze crash is gerapporteerd:</b>\n" -#: ../src/Gui/CCMainWindow.py:241 +#: ../src/Gui/CCMainWindow.py:250 msgid "<b>Not reported!</b>" msgstr "<b>Niet gerapporteerd!</b>" -#: ../src/Gui/CCMainWindow.py:290 +#: ../src/Gui/CCMainWindow.py:298 msgid "" "Unable to get report!\n" "Debuginfo is missing?" @@ -216,7 +216,7 @@ msgstr "" "Kan geen rapport krijgen!\n" "Mist debuginfo?" -#: ../src/Gui/CCMainWindow.py:309 +#: ../src/Gui/CCMainWindow.py:318 #, python-format msgid "" "Reporting failed!\n" @@ -225,25 +225,16 @@ msgstr "" "Rapporteren mislukte!\n" "%s" -#: ../src/Gui/CCMainWindow.py:328 ../src/Gui/CCMainWindow.py:355 +#: ../src/Gui/CCMainWindow.py:337 ../src/Gui/CCMainWindow.py:364 #, python-format msgid "Error getting the report: %s" msgstr "Fout tijdens het verkrijgen van het rapport: %s" -#: ../src/Gui/CCReporterDialog.py:136 -#, python-format -msgid "" -"Can't save plugin settings:\n" -" %s" -msgstr "" -"Kan de plugin instellingen niet opslaan:\n" -" %s" - -#: ../src/Gui/CCReporterDialog.py:194 -msgid "Brief description how to reproduce this or what you did..." -msgstr "Korte beschrijving hoe dit te reproduceren is of wat je deed..." +#: ../src/Gui/CCReporterDialog.py:90 +msgid "You must agree with submitting the backtrace." +msgstr "Je moet het goed vinden om de backtrace op te sturen." -#: ../src/Gui/CCReporterDialog.py:239 +#: ../src/Gui/CCReporterDialog.py:101 #, python-format msgid "" "Reporting disabled because the backtrace is unusable.\n" @@ -256,11 +247,11 @@ msgstr "" "<b>debuginfo-install %s</b> \n" "en gebruik dan de Verversen knop om de backtrace opnieuw te genereren." -#: ../src/Gui/CCReporterDialog.py:241 +#: ../src/Gui/CCReporterDialog.py:103 msgid "The backtrace is unusable, you can't report this!" msgstr "De backtrace in niet bruikbaar, je kunt dit niet rapporteren!" -#: ../src/Gui/CCReporterDialog.py:246 +#: ../src/Gui/CCReporterDialog.py:106 msgid "" "The backtrace is incomplete, please make sure you provide good steps to " "reproduce." @@ -268,18 +259,20 @@ msgstr "" "De backtrace is niet compleet, wees er zeker van om voor het genereren de " "juiste stappen op te volgen." -#: ../src/Gui/CCReporterDialog.py:296 +#: ../src/Gui/CCReporterDialog.py:148 #, python-format msgid "" -"<b>WARNING</b>, you're about to send data which might contain sensitive " -"information.\n" -"Do you really want to send <b>%s</b>?\n" +"Can't save plugin settings:\n" +" %s" msgstr "" -"<b>WAARSCHUWING</b>, je staat op het punt om data te versturen die gevoelige " -"informatie kan bevatten\n" -"Wil je <b>%s</b> echt versturen?\n" +"Kan de plugin instellingen niet opslaan:\n" +" %s" + +#: ../src/Gui/CCReporterDialog.py:266 +msgid "Brief description how to reproduce this or what you did..." +msgstr "Korte beschrijving hoe dit te reproduceren is of wat je deed..." -#: ../src/Gui/dialogs.glade.h:1 ../src/Gui/report.glade.h:5 +#: ../src/Gui/dialogs.glade.h:1 ../src/Gui/report.glade.h:17 msgid "Log" msgstr "Log" @@ -310,18 +303,68 @@ msgid " " msgstr " " #: ../src/Gui/report.glade.h:2 -msgid "<b>Comment</b>" -msgstr "<b>Commentaar</b>" +msgid "<b>Attachments</b>" +msgstr "<b>Bijlagen</b>" #: ../src/Gui/report.glade.h:3 -msgid "<b>Following items will be sent</b>" -msgstr "<b>De volgende items zullen verzonden worden</b>" +msgid "<b>Backtrace</b>" +msgstr "<b>Backtrace</b>" #: ../src/Gui/report.glade.h:4 +msgid "<b>Comment</b>" +msgstr "<b>Commentaar</b>" + +#: ../src/Gui/report.glade.h:5 msgid "<b>How to reproduce (in a few simple steps)</b>" msgstr "<b>Hoe het te reproduceren (in een paar eenvoudige stappen)</b>" +#: ../src/Gui/report.glade.h:6 +msgid "<b>Please fix the following problems</b>" +msgstr "<b>Los a.u.b. de volgende problemen op</b>" + #: ../src/Gui/report.glade.h:7 +msgid "<span fgcolor=\"blue\">Architecture:</span>" +msgstr "<span fgcolor=\"blue\">Architectuur:</span>" + +#: ../src/Gui/report.glade.h:8 +msgid "<span fgcolor=\"blue\">Cmdline:</span>" +msgstr "<span fgcolor=\"blue\">Cmdregel:</span>" + +#: ../src/Gui/report.glade.h:9 +msgid "<span fgcolor=\"blue\">Component:</span>" +msgstr "<span fgcolor=\"blue\">Onderdeel:</span>" + +#: ../src/Gui/report.glade.h:10 +msgid "<span fgcolor=\"blue\">Executable:</span>" +msgstr "<span fgcolor=\"blue\">Uitvoerbaar programma:</span>" + +#: ../src/Gui/report.glade.h:11 +msgid "<span fgcolor=\"blue\">Kernel:</span>" +msgstr "<span fgcolor=\"blue\">Kernel:</span>" + +#: ../src/Gui/report.glade.h:12 +msgid "<span fgcolor=\"blue\">Package:</span>" +msgstr "<span fgcolor=\"blue\">Pakket:</span>" + +#: ../src/Gui/report.glade.h:13 +msgid "<span fgcolor=\"blue\">Reason:</span>" +msgstr "<span fgcolor=\"blue\">Reden:</span>" + +#: ../src/Gui/report.glade.h:14 +msgid "<span fgcolor=\"blue\">Release:</span>" +msgstr "<span fgcolor=\"blue\">Vrijgave:</span>" + +#: ../src/Gui/report.glade.h:16 +msgid "I agree to submit this backtrace, which could contain sensitive data" +msgstr "" +"Ik ben er mee eens om deze backtrace in te dienen, hoewel hij gevoelige data " +"kan bevatten" + +#: ../src/Gui/report.glade.h:18 +msgid "N/A" +msgstr "n.v.t." + +#: ../src/Gui/report.glade.h:19 msgid "Send" msgstr "Verzenden" @@ -441,12 +484,12 @@ msgstr "gtk-ok" msgid "View and report application crashes" msgstr "Bekijk en rapporteer crashes van toepassingen" -#: ../src/Applet/Applet.cpp:79 +#: ../src/Applet/Applet.cpp:78 #, c-format msgid "A crash in package %s has been detected" msgstr "Een crash in pakket %s is ontdekt" -#: ../src/Applet/Applet.cpp:254 +#: ../src/Applet/Applet.cpp:253 msgid "ABRT service is not running" msgstr "ABRT service draait niet" @@ -454,7 +497,7 @@ msgstr "ABRT service draait niet" msgid "Warning" msgstr "Waarschuwing" -#: ../src/Daemon/Daemon.cpp:474 +#: ../src/Daemon/Daemon.cpp:473 msgid "" "Report size exceeded the quota. Please check system's MaxCrashReportsSize " "value in abrt.conf." @@ -476,51 +519,51 @@ msgstr "Nieuwe bug id: %i" msgid "Checking for duplicates..." msgstr "Controleren voor dubbele..." -#: ../lib/Plugins/Bugzilla.cpp:445 -msgid "Logging into bugzilla..." -msgstr "Inloggen bij bugzilla..." - -#: ../lib/Plugins/Bugzilla.cpp:449 +#: ../lib/Plugins/Bugzilla.cpp:448 msgid "Empty login and password. Please check Bugzilla.conf" msgstr "Leeg login en wachtwoord. Check a.u.b. Bugzilla.conf" +#: ../lib/Plugins/Bugzilla.cpp:450 +msgid "Logging into bugzilla..." +msgstr "Inloggen bij bugzilla..." + #: ../lib/Plugins/Bugzilla.cpp:455 msgid "Checking CC..." msgstr "Controleren van CC..." -#: ../lib/Plugins/Bugzilla.cpp:464 +#: ../lib/Plugins/Bugzilla.cpp:466 msgid "Creating new bug..." msgstr "Nieuwe bug aanmaken..." -#: ../lib/Plugins/Bugzilla.cpp:468 +#: ../lib/Plugins/Bugzilla.cpp:470 msgid "Logging out..." msgstr "Uitloggen..." -#: ../lib/Plugins/Kerneloops.cpp:37 +#: ../lib/Plugins/Kerneloops.cpp:35 msgid "Getting local universal unique identification" msgstr "Verkrijgen van locale universele unieke identificatie" -#: ../lib/Plugins/CCpp.cpp:257 +#: ../lib/Plugins/CCpp.cpp:253 msgid "Generating backtrace" msgstr "Aangemaakte backtrace" -#: ../lib/Plugins/CCpp.cpp:376 +#: ../lib/Plugins/CCpp.cpp:375 msgid "Starting debuginfo installation" msgstr "Start debuginfo installatie" -#: ../lib/Plugins/CCpp.cpp:527 +#: ../lib/Plugins/CCpp.cpp:526 msgid "Getting local universal unique identification..." msgstr "Verkrijgen van locale universele unieke identificatie..." -#: ../lib/Plugins/CCpp.cpp:546 +#: ../lib/Plugins/CCpp.cpp:545 msgid "Getting global universal unique identification..." msgstr "Verkrijgen van golbale universele unieke identificatie..." -#: ../lib/Plugins/CCpp.cpp:725 +#: ../lib/Plugins/CCpp.cpp:723 msgid "Skipping debuginfo installation" msgstr "Sla debuginfo installatie over" -#: ../lib/Plugins/KerneloopsReporter.cpp:102 +#: ../lib/Plugins/KerneloopsReporter.cpp:100 msgid "Creating and submitting a report..." msgstr "Aanmaken en indienen van rapport..." @@ -552,11 +595,11 @@ msgstr "Kan geen archief maken en versturen: %s" msgid "Can't create and send an archive %s" msgstr "Kan archief %s niet aanmaken en versturen" -#: ../lib/Plugins/KerneloopsScanner.cpp:84 +#: ../lib/Plugins/KerneloopsScanner.cpp:79 msgid "Creating kernel oops crash reports..." msgstr "Aanmaken van kernel oops crash rapporten..." -#: ../lib/Plugins/Mailx.cpp:147 +#: ../lib/Plugins/Mailx.cpp:137 msgid "Sending an email..." msgstr "Versturen van email..." @@ -573,6 +616,21 @@ msgstr "sosreport draaien: %s" msgid "done running sosreport" msgstr "klaar met het draaien van sosreport" +#~ msgid "Plugin name is not set, can't load its settings" +#~ msgstr "Plugin naam is niet ingesteld, kan zijn instellingen niet laden" + +#~ msgid "" +#~ "<b>WARNING</b>, you're about to send data which might contain sensitive " +#~ "information.\n" +#~ "Do you really want to send <b>%s</b>?\n" +#~ msgstr "" +#~ "<b>WAARSCHUWING</b>, je staat op het punt om data te versturen die " +#~ "gevoelige informatie kan bevatten\n" +#~ "Wil je <b>%s</b> echt versturen?\n" + +#~ msgid "<b>Following items will be sent</b>" +#~ msgstr "<b>De volgende items zullen verzonden worden</b>" + #~ msgid "Searching for debug-info packages..." #~ msgstr "Zoeken naar debug-info pakketten..." @@ -585,9 +643,6 @@ msgstr "klaar met het draaien van sosreport" #~ msgid "Starting report creation..." #~ msgstr "Beginnen met rapport aanmaken..." -#~ msgid "<span color=\"white\">Description</span>" -#~ msgstr "<span color=\"white\">Beschrijving</span>" - #~ msgid "Working..." #~ msgstr "Ben bezig..." diff --git a/scripts/abrt-bz-stats b/scripts/abrt-bz-stats index 3fb02bca..fd222dc9 100755 --- a/scripts/abrt-bz-stats +++ b/scripts/abrt-bz-stats @@ -13,6 +13,9 @@ import subprocess import datetime import pickle +# +# Parse the command line input +# parser = OptionParser(version="%prog 1.0") parser.add_option("-u", "--user", dest="user", help="Bugzilla user name (REQUIRED)", metavar="USERNAME") @@ -21,7 +24,6 @@ parser.add_option("-p", "--password", dest="password", parser.add_option("-b", "--bugzilla", dest="bugzilla", help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL") (options, args) = parser.parse_args() - if not options.user or len(options.user) == 0: parser.error("User name is required.\nTry {0} --help".format(sys.argv[0])) if not options.password or len(options.password) == 0: @@ -29,6 +31,9 @@ if not options.password or len(options.password) == 0: if not options.bugzilla or len(options.bugzilla) == 0: options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi" +# +# Connect to Bugzilla and get the list of all bugs reported by ABRT +# bz = RHBugzilla() bz.connect(options.bugzilla) bz.login(options.user, options.password) @@ -37,47 +42,150 @@ buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboar total = len(buginfos) print "{0} bugs found.".format(total) +# +# Load cache from previous run. Speeds up the case Bugzilla closes connection. +# buginfos_loaded = {} if os.path.isfile("cache"): f = open("cache", 'r') buginfos_loaded = pickle.load(f) f.close() +def save_to_cache(): + global buginfos_loaded + f = open("cache", 'w') + pickle.dump(buginfos_loaded, f, 2) + f.close() + +# +# Load data from Bugzilla +# count = 0 for buginfo in buginfos: count += 1 print "{0}/{1}".format(count, total) - dtkey = buginfo.delta_ts[0:7] # YEAR-MONTH - statuskey = buginfo.bug_status - if buginfo.resolution != "": - statuskey += "_" + buginfo.resolution - if not buginfos_loaded.has_key(buginfo.bug_id): - buginfos_loaded[buginfo.bug_id] = (dtkey, statuskey) + if count % 100 == 0: - f = open("cache", 'w') - pickle.dump(buginfos_loaded, f, 2) - f.close() + save_to_cache() + + if buginfos_loaded.has_key(buginfo.bug_id): + continue + + # creation date, format YEAR-MONTH + created = buginfo.creation_ts[0:7].replace(".", "-") + # last change to bug, format YEAR-MONTH + lastchange = buginfo.delta_ts[0:7].replace(".", "-") + status = buginfo.bug_status # status during the last change + if buginfo.resolution != "": + status += "_" + buginfo.resolution + buginfos_loaded[buginfo.bug_id] = { + 'created':created, + 'lastchange':lastchange, + 'status':status, + 'component':buginfo.component} + bz.logout() +save_to_cache() -stats = {} -for buginfo in buginfos_loaded.values(): - if buginfo[0] in stats: - stat = stats[buginfo[0]] - if buginfo[1] in stat: - stat[buginfo[1]] += 1 +# +# Interpret data from Bugzilla +# +# Bugs reported this month by ABRT +# Bugs closed as useful this month by ABRT +# Bugs closed as waste this month by ABRT +# Top crashers this month. +# +class Month: + def __init__(self): + # Number of bugs reported to certain component this month. + self.components = {} + + self.closed_as_useful = 0 + self.closed_as_waste = 0 + self.closed_as_other = 0 + + def bugs_reported(self): + result = 0 + for component in self.components.values(): + result += component + return result + + def top_crashers(self): + """ + Top five components causing crash this month. + Returns list of tuples (component, number of crashes) + """ + result = sorted(self.components.items(), key=lambda x: x[1]) + result.reverse() + return result[0:5] + + def closed_as_useful_percentage(self): + return int(100 * self.closed_as_useful / self.closed()) + + def closed_as_waste_percentage(self): + return int(100 * self.closed_as_waste / self.closed()) + + def closed_as_other_percentage(self): + return int(100 * self.closed_as_other / self.closed()) + + def closed(self): + return self.closed_as_useful + self.closed_as_waste + self.closed_as_other + + def add_component_crash(self, component): + if component in self.components: + self.components[component] += 1 else: - stat[buginfo[1]] = 1 + self.components[component] = 1 + + def add_resolution(self, resolution): + if resolution in ["CLOSED_NOTABUG", "CLOSED_WONTFIX", "CLOSED_DEFERRED", "CLOSED_WORKSFORME"]: + self.closed_as_other += 1 + elif resolution in ["CLOSED_CURRENTRELEASE", "CLOSED_RAWHIDE", "CLOSED_ERRATA", \ + "CLOSED_UPSTREAM", "CLOSED_NEXTRELEASE"]: + self.closed_as_useful += 1 + elif resolution in ["CLOSED_DUPLICATE", "CLOSED_CANTFIX", "CLOSED_INSUFFICIENT_DATA"]: + self.closed_as_waste += 1 + + +stats = {} # key == YEAR-MONTH, value == Month() + +def get_month(month): + global stats + if month in stats: + return stats[month] else: - stats[buginfo[0]] = { buginfo[1]:1 } + stats[month] = Month() + return stats[month] +for buginfo in buginfos_loaded.values(): + # Bugs reported this month by ABRT + # Top crashers this month + month = get_month(buginfo['created']) + month.add_component_crash(buginfo['component']) + + # Bugs closed as useful this month by ABRT + # Bugs closed as waste this month by ABRT + month = get_month(buginfo['lastchange']) + month.add_resolution(buginfo['status']) + +# +# Print interpreted data +# print "STATS" print "==========================================================================" months = stats.keys() months.sort() for month in months: - stat = stats[month] - statuses = stat.keys() - statuses.sort() - print "Month ", month - for status in statuses: - print status, stat[status] + m = stats[month] + print "MONTH ", month + print " -", m.bugs_reported(), "bugs reported" + if m.closed_as_useful > 0: + print " -", m.closed_as_useful, "bugs (" + str(m.closed_as_useful_percentage()) + "%) closed (ABRT was useful)" + if m.closed_as_waste > 0: + print " -", m.closed_as_waste, "bugs (" + str(m.closed_as_waste_percentage())+ "%) closed (ABRT was not useful)" + if m.closed_as_other > 0: + print " -", m.closed_as_other, "bugs (" + str(m.closed_as_other_percentage()) + "%) closed other way" + if len(m.top_crashers()) > 0: + print " - top crashers:" + for (component, num_crashes) in m.top_crashers(): + print " # ", component + ":", num_crashes, "crashes" diff --git a/src/CLI/CLI.cpp b/src/CLI/CLI.cpp index 2f3b4048..a8786e99 100644 --- a/src/CLI/CLI.cpp +++ b/src/CLI/CLI.cpp @@ -53,9 +53,9 @@ static void print_crash_infos(vector_map_crash_data_t& pCrashInfos, int pMode) for (ii = 0; ii < pCrashInfos.size(); ii++) { map_crash_data_t& info = pCrashInfos[ii]; - if (pMode == OPT_GET_LIST_FULL || info[CD_REPORTED][CD_CONTENT] != "1") + if (pMode == OPT_GET_LIST_FULL || get_crash_data_item_content(info, CD_REPORTED) != "1") { - const char *timestr = info[CD_TIME][CD_CONTENT].c_str(); + const char *timestr = get_crash_data_item_content(info, FILENAME_TIME).c_str(); long time = strtol(timestr, NULL, 10); if (time == 0) error_msg_and_die("Error while converting time string."); @@ -72,13 +72,13 @@ static void print_crash_infos(vector_map_crash_data_t& pCrashInfos, int pMode) "\tExecutable : %s\n" "\tCrash Time : %s\n" "\tCrash Count: %s\n"), - ii, - info[CD_UID][CD_CONTENT].c_str(), - info[CD_UUID][CD_CONTENT].c_str(), - info[CD_PACKAGE][CD_CONTENT].c_str(), - info[CD_EXECUTABLE][CD_CONTENT].c_str(), - timeloc, - info[CD_COUNT][CD_CONTENT].c_str() + ii, + get_crash_data_item_content(info, FILENAME_UID).c_str(), + get_crash_data_item_content(info, CD_UUID).c_str(), + get_crash_data_item_content(info, FILENAME_PACKAGE).c_str(), + get_crash_data_item_content(info, FILENAME_EXECUTABLE).c_str(), + timeloc, + get_crash_data_item_content(info, CD_COUNT).c_str() ); } } diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp index 11037ca7..76cd3d5a 100644 --- a/src/CLI/report.cpp +++ b/src/CLI/report.cpp @@ -192,13 +192,13 @@ static void write_crash_report(const map_crash_data_t &report, FILE *fp) fprintf(fp, "# Please check this report. Lines starting with '#' will be ignored.\n" "# Lines starting with '%%----' separate fields, please do not delete them.\n\n"); - write_crash_report_field(fp, report, CD_COMMENT, + write_crash_report_field(fp, report, FILENAME_COMMENT, _("# Describe the circumstances of this crash below.")); - write_crash_report_field(fp, report, CD_REPRODUCE, + write_crash_report_field(fp, report, FILENAME_REPRODUCE, _("# How to reproduce the crash?")); write_crash_report_field(fp, report, FILENAME_BACKTRACE, _("# Stack trace: a list of active stack frames at the time the crash occurred\n# Check that it does not contain any sensitive data such as passwords.")); - write_crash_report_field(fp, report, CD_UUID, _("# UUID")); + write_crash_report_field(fp, report, CD_DUPHASH, "# DUPHASH"); write_crash_report_field(fp, report, FILENAME_ARCHITECTURE, _("# Architecture")); write_crash_report_field(fp, report, FILENAME_CMDLINE, _("# Command line")); write_crash_report_field(fp, report, FILENAME_COMPONENT, _("# Component")); @@ -282,10 +282,10 @@ static int read_crash_report_field(const char *text, map_crash_data_t &report, static int read_crash_report(map_crash_data_t &report, const char *text) { int result = 0; - result |= read_crash_report_field(text, report, CD_COMMENT); - result |= read_crash_report_field(text, report, CD_REPRODUCE); + result |= read_crash_report_field(text, report, FILENAME_COMMENT); + result |= read_crash_report_field(text, report, FILENAME_REPRODUCE); result |= read_crash_report_field(text, report, FILENAME_BACKTRACE); - result |= read_crash_report_field(text, report, CD_UUID); + result |= read_crash_report_field(text, report, CD_DUPHASH); result |= read_crash_report_field(text, report, FILENAME_ARCHITECTURE); result |= read_crash_report_field(text, report, FILENAME_CMDLINE); result |= read_crash_report_field(text, report, FILENAME_COMPONENT); diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp index ddfbba49..f1f10e50 100644 --- a/src/Daemon/CommLayerServerDBus.cpp +++ b/src/Daemon/CommLayerServerDBus.cpp @@ -190,7 +190,8 @@ static int handle_CreateReport(DBusMessage* call, DBusMessage* reply) } long unix_uid = get_remote_uid(call); - map_crash_data_t report = CreateReport(pUUID, to_string(unix_uid).c_str(), /*force:*/ 0); + map_crash_data_t report; + CreateReport(pUUID, to_string(unix_uid).c_str(), /*force:*/ 0, report); DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); @@ -214,9 +215,9 @@ static int handle_Report(DBusMessage* call, DBusMessage* reply) return -1; } - map_crash_data_t::const_iterator it_comment = argin1.find(CD_COMMENT); + map_crash_data_t::const_iterator it_comment = argin1.find(FILENAME_COMMENT); const char* comment = (it_comment != argin1.end()) ? it_comment->second[CD_CONTENT].c_str() : ""; - map_crash_data_t::const_iterator it_reproduce = argin1.find(CD_REPRODUCE); + map_crash_data_t::const_iterator it_reproduce = argin1.find(FILENAME_REPRODUCE); const char* reproduce = (it_reproduce != argin1.end()) ? it_reproduce->second[CD_CONTENT].c_str() : ""; const char* errmsg = NULL; if (strlen(comment) > LIMIT_MESSAGE) diff --git a/src/Daemon/CommLayerServerSocket.cpp b/src/Daemon/CommLayerServerSocket.cpp index b54f9a6e..ab880fb2 100644 --- a/src/Daemon/CommLayerServerSocket.cpp +++ b/src/Daemon/CommLayerServerSocket.cpp @@ -145,7 +145,8 @@ void CCommLayerServerSocket::ProcessMessage(const std::string& pMessage, GIOChan else if (!strncmp(pMessage.c_str(), MESSAGE_CREATE_REPORT, sizeof(MESSAGE_CREATE_REPORT) - 1)) { // std::string UUID = pMessage.substr(sizeof(MESSAGE_CREATE_REPORT) - 1); -// map_crash_data_t crashReport = CreateReport(UUID, UID); +// map_crash_data_t crashReport; +// CreateReport(UUID, UID, crashReport); //use CreateReportThread instead of CreateReport? // std::string message = MESSAGE_CREATE_REPORT + crash_report_to_string(crashReport); // Send(message, pSource); diff --git a/src/Daemon/CrashWatcher.cpp b/src/Daemon/CrashWatcher.cpp index 80d8cd47..93365f3b 100644 --- a/src/Daemon/CrashWatcher.cpp +++ b/src/Daemon/CrashWatcher.cpp @@ -57,12 +57,11 @@ vector_map_crash_data_t GetCrashInfos(const char *pUID) unsigned int ii; for (ii = 0; ii < UUIDsUIDs.size(); ii++) { - mw_result_t res; - map_crash_data_t info; const char *uuid = UUIDsUIDs[ii].first.c_str(); const char *uid = UUIDsUIDs[ii].second.c_str(); - res = FillCrashInfo(uuid, uid, info); + map_crash_data_t info; + mw_result_t res = FillCrashInfo(uuid, uid, info); switch (res) { case MW_OK: @@ -96,18 +95,18 @@ vector_map_crash_data_t GetCrashInfos(const char *pUID) * StartJob dbus call already did all the processing, and we just retrieve * the result from dump directory, which is fast. */ -map_crash_data_t CreateReport(const char* pUUID, const char* pUID, int force) +void CreateReport(const char* pUUID, const char* pUID, int force, map_crash_data_t& crashReport) { /* FIXME: starting from here, any shared data must be protected with a mutex. * For example, CreateCrashReport does: * g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); * which is unsafe wrt concurrent updates to g_pPluginManager state. */ - map_crash_data_t crashReport; mw_result_t res = CreateCrashReport(pUUID, pUID, force, crashReport); switch (res) { case MW_OK: + VERB2 log_map_crash_data(crashReport, "crashReport"); break; case MW_IN_DB_ERROR: error_msg("Can't find crash with UUID %s in database", pUUID); @@ -120,7 +119,6 @@ map_crash_data_t CreateReport(const char* pUUID, const char* pUID, int force) DeleteDebugDump(pUUID, pUID); break; } - return crashReport; } typedef struct thread_data_t { @@ -140,7 +138,8 @@ static void* create_report(void* arg) try { log("Creating report..."); - map_crash_data_t crashReport = CreateReport(thread_data->UUID, thread_data->UID, thread_data->force); + map_crash_data_t crashReport; + CreateReport(thread_data->UUID, thread_data->UID, thread_data->force, crashReport); g_pCommLayer->JobDone(thread_data->peer, thread_data->UUID); } catch (CABRTException& e) diff --git a/src/Daemon/CrashWatcher.h b/src/Daemon/CrashWatcher.h index 1e672b96..31b72e08 100644 --- a/src/Daemon/CrashWatcher.h +++ b/src/Daemon/CrashWatcher.h @@ -50,7 +50,7 @@ class CCrashWatcher vector_map_crash_data_t GetCrashInfos(const char *pUID); int CreateReportThread(const char* pUUID, const char* pUID, int force, const char* pSender); -map_crash_data_t CreateReport(const char* pUUID, const char* pUID, int force); +void CreateReport(const char* pUUID, const char* pUID, int force, map_crash_data_t&); int DeleteDebugDump(const char *pUUID, const char *pUID); void DeleteDebugDump_by_dir(const char *dump_dir); diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index c7acffc3..83b1ceef 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -328,7 +328,7 @@ static void FindNewDumps(const char* pPath) { case MW_OK: VERB1 log("Saving %s into database", itt->c_str()); - RunActionsAndReporters(crashinfo[CD_MWDDD][CD_CONTENT].c_str()); + RunActionsAndReporters(get_crash_data_item_content(crashinfo, CD_DUMPDIR).c_str()); break; case MW_IN_DB: VERB1 log("%s is already saved in database", itt->c_str()); @@ -479,14 +479,14 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin try { std::string fullname = concat_path_file(DEBUG_DUMPS_DIR, name); - map_crash_data_t crashinfo; //todo: rename SaveDebugDump to ???? it does not save crashinfo, it FETCHES crashinfo + map_crash_data_t crashinfo; mw_result_t res = SaveDebugDump(fullname.c_str(), crashinfo); switch (res) { case MW_OK: log("New crash, saving"); - RunActionsAndReporters(crashinfo[CD_MWDDD][CD_CONTENT].c_str()); + RunActionsAndReporters(get_crash_data_item_content(crashinfo, CD_DUMPDIR).c_str()); /* Fall through */ case MW_REPORTED: case MW_OCCURED: @@ -494,8 +494,8 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin if (res != MW_OK) log("Already saved crash, just sending dbus signal"); - const char *analyzer = crashinfo[CD_MWANALYZER][CD_CONTENT].c_str(); - const char *uid_str = crashinfo[CD_UID][CD_CONTENT].c_str(); + const char *analyzer = get_crash_data_item_content(crashinfo, FILENAME_ANALYZER).c_str(); + const char *uid_str = get_crash_data_item_content(crashinfo, FILENAME_UID).c_str(); /* Autoreport it if configured to do so */ if (analyzer_has_AutoReportUIDs(analyzer, uid_str)) @@ -503,7 +503,7 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin VERB1 log("Reporting the crash automatically"); map_crash_data_t crash_report; mw_result_t crash_result = CreateCrashReport( - crashinfo[CD_UUID][CD_CONTENT].c_str(), + get_crash_data_item_content(crashinfo, CD_UUID).c_str(), uid_str, /*force:*/ 0, crash_report ); if (crash_result == MW_OK) @@ -525,7 +525,7 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin /* Send dbus signal */ if (analyzer_has_InformAllUsers(analyzer)) uid_str = NULL; - g_pCommLayer->Crash(crashinfo[CD_PACKAGE][CD_CONTENT].c_str(), uid_str); + g_pCommLayer->Crash(get_crash_data_item_content(crashinfo, FILENAME_PACKAGE).c_str(), uid_str); break; } case MW_BLACKLISTED: diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp index a2b20e68..9abb737b 100644 --- a/src/Daemon/MiddleWare.cpp +++ b/src/Daemon/MiddleWare.cpp @@ -148,37 +148,12 @@ static void load_crash_data_from_debug_dump(CDebugDump& dd, map_crash_data_t& da dd.LoadText(short_name.c_str(), content); free(text); - if (short_name == FILENAME_ARCHITECTURE - || short_name == FILENAME_KERNEL - || short_name == FILENAME_PACKAGE - || short_name == FILENAME_COMPONENT - || short_name == FILENAME_RELEASE - || short_name == FILENAME_EXECUTABLE - ) { - add_to_crash_data_ext(data, - short_name.c_str(), - CD_TXT, - CD_ISNOTEDITABLE, - content.c_str() - ); - continue; - } - - if (short_name != FILENAME_UID - && short_name != FILENAME_ANALYZER - && short_name != FILENAME_TIME - && short_name != FILENAME_DESCRIPTION - && short_name != FILENAME_REPRODUCE - && short_name != FILENAME_COMMENT - ) { - add_to_crash_data_ext( - data, - short_name.c_str(), - CD_TXT, - CD_ISEDITABLE, - content.c_str() - ); - } + add_to_crash_data_ext(data, + short_name.c_str(), + CD_TXT, + is_editable_file(short_name.c_str()) ? CD_ISEDITABLE : CD_ISNOTEDITABLE, + content.c_str() + ); } } @@ -190,16 +165,19 @@ static void load_crash_data_from_debug_dump(CDebugDump& dd, map_crash_data_t& da */ static void DebugDumpToCrashReport(const char *pDebugDumpDir, map_crash_data_t& pCrashData) { + VERB3 log(" DebugDumpToCrashReport('%s')", pDebugDumpDir); + CDebugDump dd; dd.Open(pDebugDumpDir); - if (!dd.Exist(FILENAME_ARCHITECTURE) - || !dd.Exist(FILENAME_KERNEL) - || !dd.Exist(FILENAME_PACKAGE) - || !dd.Exist(FILENAME_COMPONENT) - || !dd.Exist(FILENAME_RELEASE) - || !dd.Exist(FILENAME_EXECUTABLE) - ) { - throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): One or more of important file(s) are missing"); + + const char *const *v = must_have_files; + while (*v) + { + if (!dd.Exist(*v)) + { + throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): important file '%s' is missing", *v); + } + v++; } load_crash_data_from_debug_dump(dd, pCrashData); @@ -245,7 +223,7 @@ static std::string GetGlobalUUID(const char *pAnalyzer, * @param pAnalyzer A name of an analyzer plugin. * @param pDebugDumpPath A debugdump dir containing all necessary data. */ -static void CreateReport(const char *pAnalyzer, +static void run_analyser_CreateReport(const char *pAnalyzer, const char *pDebugDumpDir, int force) { @@ -278,63 +256,56 @@ mw_result_t CreateCrashReport(const char *pUUID, return MW_IN_DB_ERROR; } + mw_result_t r = MW_OK; try { - CDebugDump dd; - std::string analyzer; - std::string comment; - std::string reproduce = "1.\n2.\n3.\n"; - - VERB3 log(" LoadText(FILENAME_ANALYZER,'%s')", row.m_sDebugDumpDir.c_str()); - dd.Open(row.m_sDebugDumpDir.c_str()); - dd.LoadText(FILENAME_ANALYZER, analyzer); - if (dd.Exist(FILENAME_COMMENT)) { - dd.LoadText(FILENAME_COMMENT, comment); + CDebugDump dd; + dd.Open(row.m_sDebugDumpDir.c_str()); + load_crash_data_from_debug_dump(dd, pCrashData); } - if (dd.Exist(FILENAME_REPRODUCE)) - { - dd.LoadText(FILENAME_REPRODUCE, reproduce); - } - dd.Close(); - VERB3 log(" CreateReport('%s')", analyzer.c_str()); - CreateReport(analyzer.c_str(), row.m_sDebugDumpDir.c_str(), force); + std::string analyzer = get_crash_data_item_content(pCrashData, FILENAME_ANALYZER); + + // TODO: explain what run_analyser_CreateReport and RunAnalyzerActions are expected to do. + // Do they potentially add more files to dump dir? + // Why we calculate dup_hash after run_analyser_CreateReport but before RunAnalyzerActions? + // Why do we reload dump dir's data via DebugDumpToCrashReport? - std::string gUUID = GetGlobalUUID(analyzer.c_str(), row.m_sDebugDumpDir.c_str()); - VERB3 log(" GetGlobalUUID:'%s'", gUUID.c_str()); + VERB3 log(" run_analyser_CreateReport('%s')", analyzer.c_str()); + run_analyser_CreateReport(analyzer.c_str(), row.m_sDebugDumpDir.c_str(), force); + + std::string dup_hash = GetGlobalUUID(analyzer.c_str(), row.m_sDebugDumpDir.c_str()); + VERB3 log(" DUPHASH:'%s'", dup_hash.c_str()); VERB3 log(" RunAnalyzerActions('%s','%s')", analyzer.c_str(), row.m_sDebugDumpDir.c_str()); RunAnalyzerActions(analyzer.c_str(), row.m_sDebugDumpDir.c_str()); - VERB3 log(" DebugDumpToCrashReport"); + DebugDumpToCrashReport(row.m_sDebugDumpDir.c_str(), pCrashData); - add_to_crash_data_ext(pCrashData, CD_UUID , CD_TXT, CD_ISNOTEDITABLE, gUUID.c_str() ); - add_to_crash_data_ext(pCrashData, CD_MWANALYZER, CD_SYS, CD_ISNOTEDITABLE, analyzer.c_str() ); - add_to_crash_data_ext(pCrashData, CD_MWUID , CD_SYS, CD_ISNOTEDITABLE, pUID ); - add_to_crash_data_ext(pCrashData, CD_MWUUID , CD_SYS, CD_ISNOTEDITABLE, pUUID ); - add_to_crash_data_ext(pCrashData, CD_COMMENT , CD_TXT, CD_ISEDITABLE , comment.c_str() ); - add_to_crash_data_ext(pCrashData, CD_REPRODUCE , CD_TXT, CD_ISEDITABLE , reproduce.c_str()); + add_to_crash_data_ext(pCrashData, CD_DUPHASH, CD_TXT, CD_ISNOTEDITABLE, dup_hash.c_str()); + add_to_crash_data_ext(pCrashData, CD_UUID , CD_SYS, CD_ISNOTEDITABLE, pUUID); } catch (CABRTException& e) { + r = MW_CORRUPTED; error_msg("%s", e.what()); if (e.type() == EXCEP_DD_OPEN) { - return MW_ERROR; + r = MW_ERROR; } - if (e.type() == EXCEP_DD_LOAD) + else if (e.type() == EXCEP_DD_LOAD) { - return MW_FILE_ERROR; + r = MW_FILE_ERROR; } - if (e.type() == EXCEP_PLUGIN) + else if (e.type() == EXCEP_PLUGIN) { - return MW_PLUGIN_ERROR; + r = MW_PLUGIN_ERROR; } - return MW_CORRUPTED; } - return MW_OK; + VERB3 log("CreateCrashReport() returns %d", r); + return r; } void RunAction(const char *pActionDir, @@ -391,88 +362,70 @@ void RunActionsAndReporters(const char *pDebugDumpDir) } -static bool CheckReport(const map_crash_data_t& pCrashData) -{ - map_crash_data_t::const_iterator it_analyzer = pCrashData.find(CD_MWANALYZER); - map_crash_data_t::const_iterator it_mwuid = pCrashData.find(CD_MWUID); - map_crash_data_t::const_iterator it_mwuuid = pCrashData.find(CD_MWUUID); - - map_crash_data_t::const_iterator it_package = pCrashData.find(FILENAME_PACKAGE); - map_crash_data_t::const_iterator it_architecture = pCrashData.find(FILENAME_ARCHITECTURE); - map_crash_data_t::const_iterator it_kernel = pCrashData.find(FILENAME_KERNEL); - map_crash_data_t::const_iterator it_component = pCrashData.find(FILENAME_COMPONENT); - map_crash_data_t::const_iterator it_release = pCrashData.find(FILENAME_RELEASE); - map_crash_data_t::const_iterator it_executable = pCrashData.find(FILENAME_EXECUTABLE); - - map_crash_data_t::const_iterator end = pCrashData.end(); - - if (it_package == end) - { - return false; - } - - // FIXME: bypass the test if it's kerneloops - if (it_package->second[CD_CONTENT] == "kernel") - return true; - - if (it_analyzer == end || it_mwuid == end || - it_mwuuid == end || /* it_package == end || */ - it_architecture == end || it_kernel == end || - it_component == end || it_release == end || - it_executable == end) - { - return false; - } - - if (it_analyzer->second[CD_CONTENT] == "" || it_mwuid->second[CD_CONTENT] == "" || - it_mwuuid->second[CD_CONTENT] == "" || it_package->second[CD_CONTENT] == "" || - it_architecture->second[CD_CONTENT] == "" || it_kernel->second[CD_CONTENT] == "" || - it_component->second[CD_CONTENT] == "" || it_release->second[CD_CONTENT] == "" || - it_executable->second[CD_CONTENT] == "") - { - return false; - } - - return true; -} - -report_status_t Report(const map_crash_data_t& pCrashData, +// We must not trust client_report here! +// dbus handler passes it from user without checking +report_status_t Report(const map_crash_data_t& client_report, map_map_string_t& pSettings, const char *pUID) { - report_status_t ret; - - /* dbus handler passes pCrashData from user without checking it */ - - if (!CheckReport(pCrashData)) + // Get ID fields + const char *UID = get_crash_data_item_content_or_NULL(client_report, FILENAME_UID); + const char *UUID = get_crash_data_item_content_or_NULL(client_report, CD_UUID); + if (!UID || !UUID) { + throw CABRTException(EXCEP_ERROR, "Report(): UID or UUID is missing in client's report data"); + } + + // Retrieve corresponding stored record + map_crash_data_t stored_report; + mw_result_t r = FillCrashInfo(UUID, UID, stored_report); + if (r != MW_OK) + return report_status_t(); + const std::string& pDumpDir = get_crash_data_item_content(stored_report, CD_DUMPDIR); + + // Save comment, "how to reproduce", backtrace + const char *comment = get_crash_data_item_content_or_NULL(client_report, FILENAME_COMMENT); + const char *reproduce = get_crash_data_item_content_or_NULL(client_report, FILENAME_REPRODUCE); + const char *backtrace = get_crash_data_item_content_or_NULL(client_report, FILENAME_BACKTRACE); + if (comment || reproduce || backtrace) { - throw CABRTException(EXCEP_ERROR, "Report(): Some of mandatory report data are missing."); - } - - const std::string& analyzer = get_crash_data_item_content(pCrashData, CD_MWANALYZER); - const std::string& UID = get_crash_data_item_content(pCrashData, CD_MWUID); - const std::string& UUID = get_crash_data_item_content(pCrashData, CD_MWUUID); - const std::string& packageNVR = get_crash_data_item_content(pCrashData, FILENAME_PACKAGE); - std::string packageName = packageNVR.substr(0, packageNVR.rfind("-", packageNVR.rfind("-") - 1)); - - // Save comment and "how to reproduce" - map_crash_data_t::const_iterator it_comment = pCrashData.find(CD_COMMENT); - map_crash_data_t::const_iterator it_reproduce = pCrashData.find(CD_REPRODUCE); - if (it_comment != pCrashData.end() || it_reproduce != pCrashData.end()) - { - std::string pDumpDir = getDebugDumpDir(UUID.c_str(), UID.c_str()); CDebugDump dd; dd.Open(pDumpDir.c_str()); - if (it_comment != pCrashData.end()) + if (comment) { - dd.SaveText(FILENAME_COMMENT, it_comment->second[CD_CONTENT].c_str()); + dd.SaveText(FILENAME_COMMENT, comment); + add_to_crash_data_ext(stored_report, FILENAME_COMMENT, CD_TXT, CD_ISEDITABLE, comment); } - if (it_reproduce != pCrashData.end()) + if (reproduce) { - dd.SaveText(FILENAME_REPRODUCE, it_reproduce->second[CD_CONTENT].c_str()); + dd.SaveText(FILENAME_REPRODUCE, reproduce); + add_to_crash_data_ext(stored_report, FILENAME_REPRODUCE, CD_TXT, CD_ISEDITABLE, reproduce); + } + if (backtrace) + { + dd.SaveText(FILENAME_BACKTRACE, backtrace); + add_to_crash_data_ext(stored_report, FILENAME_BACKTRACE, CD_TXT, CD_ISEDITABLE, backtrace); } } + const std::string& analyzer = get_crash_data_item_content(stored_report, FILENAME_ANALYZER); + + std::string dup_hash = GetGlobalUUID(analyzer.c_str(), pDumpDir.c_str()); + VERB3 log(" DUPHASH:'%s'", dup_hash.c_str()); + add_to_crash_data_ext(stored_report, CD_DUPHASH, CD_TXT, CD_ISNOTEDITABLE, dup_hash.c_str()); + + // Run reporters + + VERB3 { + log("Run reporters"); + log_map_crash_data(client_report, " client_report"); + log_map_crash_data(stored_report, " stored_report"); + } +#define client_report client_report_must_not_be_used_below + + map_crash_data_t::const_iterator its_PACKAGE = stored_report.find(FILENAME_PACKAGE); + std::string packageNVR = its_PACKAGE->second[CD_CONTENT]; + std::string packageName = packageNVR.substr(0, packageNVR.rfind("-", packageNVR.rfind("-") - 1)); + // analyzer with package name (CCpp:xorg-x11-app) has higher priority std::string key = analyzer + ":" + packageName; map_analyzer_actions_and_reporters_t::iterator end = s_mapAnalyzerActionsAndReporters.end(); @@ -484,6 +437,7 @@ report_status_t Report(const map_crash_data_t& pCrashData, key = analyzer; } + report_status_t ret; std::string message; if (keyPtr != end) { @@ -518,7 +472,7 @@ report_status_t Report(const map_crash_data_t& pCrashData, } #endif map_plugin_settings_t plugin_settings = pSettings[plugin_name]; - std::string res = reporter->Report(pCrashData, plugin_settings, it_r->second.c_str()); + std::string res = reporter->Report(stored_report, plugin_settings, it_r->second.c_str()); #if 0 /* Using ~user/.abrt/ is bad wrt security */ if (home != "") @@ -544,10 +498,11 @@ report_status_t Report(const map_crash_data_t& pCrashData, CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); database->Connect(); - database->SetReported(UUID.c_str(), UID.c_str(), message.c_str()); + database->SetReported(UUID, UID, message.c_str()); database->DisConnect(); return ret; +#undef client_report } /** @@ -863,8 +818,7 @@ static mw_result_t SaveDebugDumpToDatabase(const char *pUUID, return res; } -std::string getDebugDumpDir(const char *pUUID, - const char *pUID) +std::string getDebugDumpDir(const char *pUUID, const char *pUID) { CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str()); database->Connect(); @@ -936,10 +890,7 @@ mw_result_t FillCrashInfo(const char *pUUID, { CDebugDump dd; dd.Open(row.m_sDebugDumpDir.c_str()); - dd.LoadText(FILENAME_EXECUTABLE, executable); - dd.LoadText(FILENAME_PACKAGE, package); - dd.LoadText(FILENAME_DESCRIPTION, description); - dd.LoadText(FILENAME_ANALYZER, analyzer); + load_crash_data_from_debug_dump(dd, pCrashData); } catch (CABRTException& e) { @@ -947,18 +898,14 @@ mw_result_t FillCrashInfo(const char *pUUID, return MW_ERROR; } - pCrashData.clear(); - add_to_crash_data(pCrashData, CD_EXECUTABLE , executable.c_str() ); - add_to_crash_data(pCrashData, CD_PACKAGE , package.c_str() ); - add_to_crash_data(pCrashData, CD_DESCRIPTION, description.c_str() ); - add_to_crash_data(pCrashData, CD_UUID , row.m_sUUID.c_str() ); - add_to_crash_data(pCrashData, CD_UID , row.m_sUID.c_str() ); - add_to_crash_data(pCrashData, CD_COUNT , row.m_sCount.c_str() ); - add_to_crash_data(pCrashData, CD_TIME , row.m_sTime.c_str() ); - add_to_crash_data(pCrashData, CD_REPORTED , row.m_sReported.c_str() ); - add_to_crash_data(pCrashData, CD_MESSAGE , row.m_sMessage.c_str() ); - add_to_crash_data(pCrashData, CD_MWDDD , row.m_sDebugDumpDir.c_str()); - add_to_crash_data(pCrashData, CD_MWANALYZER , analyzer.c_str() ); + add_to_crash_data(pCrashData, CD_UUID , row.m_sUUID.c_str() ); + add_to_crash_data(pCrashData, CD_COUNT , row.m_sCount.c_str() ); + add_to_crash_data(pCrashData, CD_REPORTED , row.m_sReported.c_str() ); + add_to_crash_data(pCrashData, CD_MESSAGE , row.m_sMessage.c_str() ); + add_to_crash_data(pCrashData, CD_DUMPDIR , row.m_sDebugDumpDir.c_str()); +//TODO: why do we keep uid and time in DB and in dumpdir?! + add_to_crash_data(pCrashData, FILENAME_UID , row.m_sUID.c_str() ); + add_to_crash_data(pCrashData, FILENAME_TIME , row.m_sTime.c_str() ); return MW_OK; } diff --git a/src/Gui/CCDump.py b/src/Gui/CCDump.py index 96d036c4..1f290929 100644 --- a/src/Gui/CCDump.py +++ b/src/Gui/CCDump.py @@ -3,20 +3,55 @@ from datetime import datetime from abrt_utils import _, init_logging, log, log1, log2 +# Should match CrashTypes.h! CD_TYPE = 0 CD_EDITABLE = 1 CD_CONTENT = 2 +CD_SYS = "s" +CD_BIN = "b" +CD_TXT = "t" + +FILENAME_ARCHITECTURE = "architecture" +FILENAME_KERNEL = "kernel" +FILENAME_TIME = "time" +FILENAME_UID = "uid" +FILENAME_PACKAGE = "package" +FILENAME_COMPONENT = "component" +FILENAME_DESCRIPTION = "description" +FILENAME_ANALYZER = "analyzer" +FILENAME_RELEASE = "release" +FILENAME_EXECUTABLE = "executable" +FILENAME_REASON = "reason" +FILENAME_COMMENT = "comment" +FILENAME_REPRODUCE = "reproduce" +FILENAME_RATING = "rating" +FILENAME_CMDLINE = "cmdline" +FILENAME_COREDUMP = "coredump" +FILENAME_BACKTRACE = "backtrace" +FILENAME_MEMORYMAP = "memorymap" +FILENAME_KERNELOOPS = "kerneloops" + +CD_DUPHASH = "DUPHASH" +CD_UUID = "UUID" +CD_DUMPDIR = "DumpDir" +CD_COUNT = "Count" +CD_REPORTED = "Reported" +CD_MESSAGE = "Message" + +# FIXME - create method or smth that returns type|editable|content + + class Dump(): """Class for mapping the debug dump to python object""" def __init__(self): self.UUID = None - self.UID = None + self.uid = None self.Count = None - self.Executable = None - self.Package = None - self.Time = None - self.Description = None + self.executable = None + self.package = None + self.time = None + self.description = None self.Message = None self.Reported = None @@ -24,16 +59,16 @@ class Dump(): return self.UUID[CD_CONTENT] def getUID(self): - return self.UID[CD_CONTENT] + return self.uid[CD_CONTENT] def getCount(self): return self.Count[CD_CONTENT] def getExecutable(self): - return self.Executable[CD_CONTENT] + return self.executable[CD_CONTENT] def getPackage(self): - return self.Package[CD_CONTENT] + return self.package[CD_CONTENT] def isReported(self): return self.Reported[CD_CONTENT] == "1" @@ -44,17 +79,17 @@ class Dump(): #return self.Message[CD_CONTENT].split('\n') return self.Message[CD_CONTENT] - def getTime(self,format): + def getTime(self, format): #print format if format: try: - return datetime.fromtimestamp(int(self.Time[CD_CONTENT])).strftime(format) + return datetime.fromtimestamp(int(self.time[CD_CONTENT])).strftime(format) except Exception, e: print e - return int(self.Time[CD_CONTENT]) + return int(self.time[CD_CONTENT]) def getPackageName(self): - return self.Package[CD_CONTENT][:self.Package[CD_CONTENT].find("-")] + return self.package[CD_CONTENT][:self.package[CD_CONTENT].find("-")] def getDescription(self): - return self.Description[CD_CONTENT] + return self.description[CD_CONTENT] diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py index f67cd06a..8222c17c 100644 --- a/src/Gui/CCMainWindow.py +++ b/src/Gui/CCMainWindow.py @@ -229,23 +229,29 @@ class MainWindow(): # this should work until we keep the row object in the last position dump = dumpsListStore.get_value(dumpsListStore.get_iter(path[0]), dumpsListStore.get_n_columns()-1) #move this to Dump class + lReported = self.wTree.get_widget("lReported") if dump.isReported(): + report_label_raw = _("This crash has been reported:\n") report_label = _("<b>This crash has been reported:</b>\n") # plugin message follows, but at least in case of kerneloops, # it is not informative (no URL to the report) for message in dump.getMessage().split(';'): - if message: + if message: message_clean = message.strip() if "http" in message_clean[0:5] or "file:///"[0:8] in message_clean: report_message = "<a href=\"%s\">%s</a>" % (message_clean, message_clean) else: report_message = message_clean report_label += "%s\n" % report_message + report_label_raw += "%s\n" % message_clean log2("setting markup '%s'", report_label) - self.wTree.get_widget("lReported").set_markup(report_label) + lReported.set_text(report_label_raw) + # Sometimes (!) set_markup() fails with + # "GtkWarning: Failed to set text from markup due to error parsing markup: Unknown tag 'a'" + # If it does, then set_text() above acts as a fallback + lReported.set_markup(report_label) else: - self.wTree.get_widget("lReported").set_markup(_("<b>Not reported!</b>")) - lPackage = self.wTree.get_widget("lPackage") + lReported.set_markup(_("<b>Not reported!</b>")) def on_bDelete_clicked(self, button, treeview): dumpsListStore, path = self.dlist.get_selection().get_selected_rows() @@ -303,14 +309,8 @@ class MainWindow(): try: self.pBarWindow.show_all() self.timer = gobject.timeout_add(100, self.progress_update_cb) - # Old way: it needs to talk to daemon - #reporters_settings = {} - ## self.pluginlist = getPluginInfoList(self.ccdaemon, refresh=True) - ## don't force refresh! - #self.pluginlist = getPluginInfoList(self.ccdaemon) - #for plugin in self.pluginlist.getReporterPlugins(): - # reporters_settings[str(plugin)] = plugin.Settings - reporters_settings = getCurrentConfBackend().load_all() + pluginlist = getPluginInfoList(self.ccdaemon) + reporters_settings = pluginlist.getReporterPluginsSettings() log2("Report(result,settings):") log2(" result:%s", str(result)) # Careful, this will print reporters_settings["Password"] too diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py index bc970d2f..023cc6e5 100644 --- a/src/Gui/CCReporterDialog.py +++ b/src/Gui/CCReporterDialog.py @@ -11,16 +11,10 @@ from ABRTPlugin import PluginInfo from PluginSettingsUI import PluginSettingsUI from PluginList import getPluginInfoList #from CCDumpList import getDumpList, DumpList +from CCDump import * # FILENAME_xxx, CD_xxx from abrt_utils import _, log, log1, log2 # FIXME - create method or smth that returns type|editable|content -CD_TYPE = 0 -CD_EDITABLE = 1 -CD_CONTENT = 2 - -CD_SYS = "s" -CD_BIN = "b" -CD_TXT = "t" # response REFRESH = -50 @@ -34,7 +28,7 @@ class ReporterDialog(): self.report = report #Set the Glade file # FIXME add to path - builderfile = "%s%sreport.glade" % (sys.path[0],"/") + builderfile = "%s/report.glade" % sys.path[0] self.builder = gtk.Builder() self.builder.add_from_file(builderfile) #Get the Main Window, and connect the "destroy" event @@ -47,21 +41,20 @@ class ReporterDialog(): # comment textview self.tvComment = self.builder.get_object("tvComment") self.tvComment.connect("focus-in-event", self.on_comment_focus_cb) - self.comment_changed = False + self.show_hint_comment = 1 # "how to reproduce" textview self.tevHowToReproduce = self.builder.get_object("tevHowToReproduce") - self.how_to_changed = False self.builder.get_object("fErrors").hide() self.builder.get_object("bLog").connect("clicked", self.show_log_cb, log) self.builder.get_object("cbSendBacktrace").connect("toggled", self.on_send_backtrace_toggled) self.allow_send() self.hydrate() - + def check_backtrace(self): print "checking backtrace" - + def warn_user(self, warnings): # FIXME: show in lError fErrors = self.builder.get_object("fErrors") @@ -74,12 +67,12 @@ class ReporterDialog(): warning_lbl = "* %s" % warning lErrors.set_label(warning_lbl) fErrors.show_all() - + def hide_warning(self): fErrors = self.builder.get_object("fErrors") lErrors = self.builder.get_object("lErrors") fErrors.hide() - + def allow_send(self): self.hide_warning() bSend = self.builder.get_object("bSend") @@ -87,7 +80,7 @@ class ReporterDialog(): send = True error_msgs = [] try: - rating = self.report["rating"] + rating = self.report[FILENAME_RATING] except: rating = None # active buttons acording to required fields @@ -96,31 +89,32 @@ class ReporterDialog(): send = False error_msgs.append(_("You must agree with submitting the backtrace.")) # we have both SendBacktrace and rating - elif rating: + if rating: try: - package = self.report["package"][CD_CONTENT] + package = self.report[FILENAME_PACKAGE][CD_CONTENT] # if we don't have package for some reason except: package = None # not usable report - if int(self.report["rating"][CD_CONTENT]) < 3: + if int(self.report[FILENAME_RATING][CD_CONTENT]) < 3: if package: error_msgs.append(_("Reporting disabled because the backtrace is unusable.\nPlease try to install debuginfo manually using command: <b>debuginfo-install %s</b> \nthen use Refresh button to regenerate the backtrace." % package[0:package.rfind('-',0,package.rfind('-'))])) else: error_msgs.append(_("The backtrace is unusable, you can't report this!")) # probably usable 3 - elif int(self.report["rating"][CD_CONTENT]) < 4: + elif int(self.report[FILENAME_RATING][CD_CONTENT]) < 4: error_msgs.append(_("The backtrace is incomplete, please make sure you provide good steps to reproduce.")) - + if error_msgs: self.warn_user(error_msgs) bSend.set_sensitive(send) - + def on_send_backtrace_toggled(self, toggle_button): self.allow_send() - + def show_log_cb(self, widget, log): show_log(log, parent=self.window) + # this callback is called when user press Cancel or Report button in Report dialog def on_response(self, dialog, response_id, daemon): # the button has been pressed (probably) @@ -136,9 +130,10 @@ class ReporterDialog(): model[path][3] = not model[path][3] def on_comment_focus_cb(self, widget, event): - if not self.comment_changed: + if self.show_hint_comment: + # clear "hint" text by supplying a fresh, empty TextBuffer widget.set_buffer(gtk.TextBuffer()) - self.comment_changed = True + self.show_hint_comment = 0 def on_config_plugin_clicked(self, button, plugin, image): ui = PluginSettingsUI(plugin, parent=self.window) @@ -204,66 +199,81 @@ class ReporterDialog(): if len(text) > label_widget.get_max_width_chars(): label_widget.set_tooltip_text(text) label_widget.set_text(text) - + def hydrate(self): self.editable = [] + self.old_comment = "" + self.old_how_to_reproduce = "" for item in self.report: - if item == "backtrace": + try: + log2("report[%s]:%s/%s/%s", item, self.report[item][0], self.report[item][1], self.report[item][2][0:20]) + except: + pass + + if item == FILENAME_BACKTRACE: buff = gtk.TextBuffer() tvBacktrace = self.builder.get_object("tvBacktrace") buff.set_text(self.report[item][CD_CONTENT]) tvBacktrace.set_buffer(buff) continue - if item == "Comment": - buff = gtk.TextBuffer() - comment = _("Brief description how to reproduce this or what you did...") + + if item == FILENAME_COMMENT: try: if self.report[item][CD_CONTENT]: - comment = self.report[item][CD_CONTENT] - self.comment_changed = True + self.old_comment = self.report[item][CD_CONTENT] except Exception, e: pass - - buff.set_text(comment) - - self.tvComment.set_buffer(buff) continue - if item == "How to reproduce": - buff = gtk.TextBuffer() - how_to_reproduce = _("") + + if item == FILENAME_REPRODUCE: try: if self.report[item][CD_CONTENT]: - how_to_reproduce = self.report[item][CD_CONTENT] - self.how_to_changed = True + self.old_how_to_reproduce = self.report[item][CD_CONTENT] except Exception, e: pass + continue - buff.set_text(how_to_reproduce) + if self.report[item][CD_TYPE] == CD_SYS: + continue - self.tevHowToReproduce.set_buffer(buff) + # item name 0| value 1| editable? 2| toggled? 3| visible?(attachment)4 + # FIXME: handle editable fields + if self.report[item][CD_TYPE] == CD_BIN: + self.builder.get_object("fAttachment").show() + vbAttachments = self.builder.get_object("vbAttachments") + toggle = gtk.CheckButton(self.report[item][CD_CONTENT]) + vbAttachments.pack_start(toggle) + # bind item to checkbox + toggle.item = item + toggle.show() continue - if self.report[item][CD_TYPE] != CD_SYS: - # item name 0| value 1| editable? 2| toggled? 3| visible?(attachment)4 - # FIXME: handle editable fields - if self.report[item][CD_TYPE] == CD_BIN: - self.builder.get_object("fAttachment").show() - vbAttachments = self.builder.get_object("vbAttachments") - toggle = gtk.CheckButton(self.report[item][CD_CONTENT]) - vbAttachments.pack_start(toggle) - # bind item to checkbox - toggle.item = item - toggle.show() - continue - item_label = self.builder.get_object("l%s" % item) - if item_label: - self.set_label(item_label, self.report[item][CD_CONTENT]) - else: - # no widget to show this item - # probably some new item need to adjust the GUI! - # FIXME: add some window+button to show all the info - # in raw form (smth like the old report dialog) - pass + # It must be CD_TXT field + item_label = self.builder.get_object("l%s" % item) + if item_label: + self.set_label(item_label, self.report[item][CD_CONTENT]) + else: + # no widget to show this item + # probably some new item need to adjust the GUI! + # FIXME: add some window+button to show all the info + # in raw form (smth like the old report dialog) + pass + #end for + + buff = gtk.TextBuffer() + self.show_hint_comment = (self.old_comment == "") + if self.show_hint_comment: + buff.set_text(_("Brief description how to reproduce this or what you did...")) + else: + buff.set_text(self.old_comment) + self.tvComment.set_buffer(buff) + + buff = gtk.TextBuffer() + if self.old_how_to_reproduce == "": + buff.set_text("1.\n2.\n3.\n") + else: + buff.set_text(self.old_how_to_reproduce) + self.tevHowToReproduce.set_buffer(buff) def dehydrate(self): # handle attachments @@ -271,23 +281,22 @@ class ReporterDialog(): for attachment in vbAttachments.get_children(): #print "%s file %s" % (["not sending","sending"][attachment.get_active()], attachment.get_label()) del self.report[attachment.item] - + # handle comment - if self.comment_changed: - buff = self.tvComment.get_buffer() - self.report["Comment"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())] - else: - del self.report["Comment"] + buff = self.tvComment.get_buffer() + text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) + if self.old_comment != text: + self.report[FILENAME_COMMENT] = [CD_TXT, 'y', text] # handle how to reproduce - if self.how_to_changed: - buff = self.tevHowToReproduce.get_buffer() - self.report["How to reproduce"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())] - else: - del self.report["How to reproduce"] + buff = self.tevHowToReproduce.get_buffer() + text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) + if self.old_how_to_reproduce != text: + self.report[FILENAME_REPRODUCE] = [CD_TXT, 'y', text] #handle backtrace tev_backtrace = self.builder.get_object("tvBacktrace") buff = tev_backtrace.get_buffer() - self.report["backtrace"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())] + text = buff.get_text(buff.get_start_iter(), buff.get_end_iter()) + self.report[FILENAME_BACKTRACE] = [CD_TXT, 'y', text] def check_report(self): # FIXME: check the report for passwords and some other potentially @@ -299,4 +308,3 @@ class ReporterDialog(): result = self.window.run() self.window.destroy() return (result, self.report) - diff --git a/src/Gui/CC_gui_functions.py b/src/Gui/CC_gui_functions.py index a9c47faf..e2260210 100644 --- a/src/Gui/CC_gui_functions.py +++ b/src/Gui/CC_gui_functions.py @@ -56,9 +56,14 @@ def gui_report_dialog ( report_status_dict, parent_dialog, status_hbox.pack_start(plugin_label, expand=False) status_hbox.pack_start(status_label, expand=False) # 0 means not succesfull - if report_status_dict[plugin][0] == '0': - status_label.set_markup("<span foreground='red'>%s</span>" % report_status_dict[plugin][1]) - elif report_status_dict[plugin][0] == '1': + #if report_status_dict[plugin][0] == '0': + # this first one is actually a fallback to set at least + # a raw text in case when set_markup() fails + status_label.set_text(report_status_dict[plugin][1]) + status_label.set_markup("<span foreground='red'>%s</span>" % report_status_dict[plugin][1]) + # if the report was not succesful then this won't pass so this runs only + # if report succeds and gets overwriten by the status message + if report_status_dict[plugin][0] == '1': if "http" in report_status_dict[plugin][1][0:4] or "file://" in report_status_dict[plugin][1][0:7]: status_label.set_markup("<a href=\"%s\">%s</a>" % (report_status_dict[plugin][1], report_status_dict[plugin][1])) # FIXME: make a new branch for rawhide with gtk 2.17 and remove this diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py index d2232bbc..82759ae3 100644 --- a/src/Gui/PluginList.py +++ b/src/Gui/PluginList.py @@ -38,6 +38,11 @@ class PluginInfoList(list): def getReporterPlugins(self): return [x for x in self if x["Enabled"] == 'yes' and x["Type"] == 'Reporter'] + def getReporterPluginsSettings(self): + reporters_settings = {} + for plugin in self.getReporterPlugins(): + reporters_settings[str(plugin)] = plugin.Settings + return reporters_settings __PFList = None |