diff options
| author | Karel Klic <kklic@redhat.com> | 2009-11-19 10:14:27 +0100 |
|---|---|---|
| committer | Karel Klic <kklic@redhat.com> | 2009-11-19 10:14:27 +0100 |
| commit | bd60681c8227bc31ef0991e98a9a3e849032c924 (patch) | |
| tree | 5d4f3cf03d54ecb30ab863c7cc349bfcd232346c /lib | |
| parent | 0ecc573a8ba79bca8e37809c41f92f0b629149e8 (diff) | |
| parent | 83aea71df4761ec10c0d947055e65102bcace489 (diff) | |
| download | abrt-bd60681c8227bc31ef0991e98a9a3e849032c924.tar.gz abrt-bd60681c8227bc31ef0991e98a9a3e849032c924.tar.xz abrt-bd60681c8227bc31ef0991e98a9a3e849032c924.zip | |
Merge branch 'master' of ssh://git.fedorahosted.org/git/abrt
Diffstat (limited to 'lib')
29 files changed, 1382 insertions, 783 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 6be37e8..459e270 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1 +1 @@ -SUBDIRS = Utils Plugins Python +SUBDIRS = Utils Plugins
\ No newline at end of file diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp index 06f9334..7ddacf7 100644 --- a/lib/Plugins/Bugzilla.cpp +++ b/lib/Plugins/Bugzilla.cpp @@ -16,7 +16,7 @@ static void create_new_bug_description(const map_crash_report_t& pCrashReport, std::string& pDescription) { - pDescription = "abrt detected a crash.\n\n"; + pDescription = "abrt "VERSION" detected a crash.\n\n"; pDescription += make_description_bz(pCrashReport); } @@ -527,8 +527,7 @@ PLUGIN_INFO(REPORTER, CReporterBugzilla, "Bugzilla", "0.0.4", - "Check if a bug isn't already reported in a bugzilla " - "and if not, report it.", + "Reports bugs to bugzilla", "npajkovs@redhat.com", "https://fedorahosted.org/abrt/wiki", PLUGINS_LIB_DIR"/Bugzilla.GTKBuilder"); diff --git a/lib/Plugins/CCpp.conf b/lib/Plugins/CCpp.conf index 988ddf3..459dff8 100644 --- a/lib/Plugins/CCpp.conf +++ b/lib/Plugins/CCpp.conf @@ -12,6 +12,11 @@ DebugInfo = install # debuginfos will be installed to @@LOCALSTATEDIR@@/cache/abrt-di InstallDebugInfo = yes +# Additional directories to search for debuginfos. +# For example, you can list a network-mounted shared store +# of all debuginfos here. +# ReadonlyLocalDebugInfoDirs = /path1:/path2:... + # Keep @@LOCALSTATEDIR@@/cache/abrt-di # from growing out-of-bounds. DebugInfoCacheMB = 4000 diff --git a/lib/Plugins/CCpp.cpp b/lib/Plugins/CCpp.cpp index 82c5677..83b0e9a 100644 --- a/lib/Plugins/CCpp.cpp +++ b/lib/Plugins/CCpp.cpp @@ -33,6 +33,8 @@ #include "CommLayerInner.h" #include "Polkit.h" +using namespace std; + #define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern" #define CORE_PATTERN "|"CCPP_HOOK_PATH" "DEBUG_DUMPS_DIR" %p %s %u" @@ -48,9 +50,9 @@ CAnalyzerCCpp::CAnalyzerCCpp() : m_nDebugInfoCacheMB(4000) {} -static std::string CreateHash(const std::string& pInput) +static string CreateHash(const char *pInput) { - std::string ret = ""; + string ret; HASHContext* hc; unsigned char hash[SHA1_LENGTH]; unsigned int len; @@ -61,7 +63,7 @@ static std::string CreateHash(const std::string& pInput) error_msg_and_die("HASH_Create(HASH_AlgSHA1) failed"); /* paranoia */ } HASH_Begin(hc); - HASH_Update(hc, reinterpret_cast<const unsigned char*>(pInput.c_str()), pInput.length()); + HASH_Update(hc, (const unsigned char*)pInput, strlen(pInput)); HASH_End(hc, hash, &len, sizeof(hash)); HASH_Destroy(hc); @@ -80,9 +82,9 @@ static std::string CreateHash(const std::string& pInput) return hash_str; } -static std::string concat_str_vector(char **strings) +static string concat_str_vector(char **strings) { - std::string result; + string result; while (*strings) { result += *strings++; @@ -92,7 +94,7 @@ static std::string concat_str_vector(char **strings) return result; } -static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput) +static pid_t ExecVP(char** pArgs, uid_t uid, string& pOutput) { int pipeout[2]; pid_t child; @@ -100,7 +102,7 @@ static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput) struct passwd* pw = getpwuid(uid); if (!pw) { - throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": cannot get GID for UID."); + throw CABRTException(EXCEP_PLUGIN, string(__func__) + ": cannot get GID for UID."); } xpipe(pipeout); @@ -217,7 +219,7 @@ static int rate_backtrace(const char *backtrace) { if (backtrace[i] == '#') /* this separates frames from each other */ { - std::string s(backtrace + i + 1, len); + string s(backtrace + i + 1, len); for (j=0; j<len; j++) /* replace tabs with spaces */ if (s[j] == '\t') s[j] = ' '; @@ -249,12 +251,12 @@ static int rate_backtrace(const char *backtrace) return 0; } -static void GetBacktrace(const char *pDebugDumpDir, std::string& pBacktrace) +static void GetBacktrace(const char *pDebugDumpDir, const char *pDebugInfoDirs, string& pBacktrace) { update_client(_("Getting backtrace...")); - std::string UID; - std::string executable; + string UID; + string executable; { CDebugDump dd; dd.Open(pDebugDumpDir); @@ -270,10 +272,24 @@ static void GetBacktrace(const char *pDebugDumpDir, std::string& pBacktrace) char* args[11]; args[0] = (char*)"gdb"; args[1] = (char*)"-batch"; + // when/if gdb supports it: // (https://bugzilla.redhat.com/show_bug.cgi?id=528668): args[2] = (char*)"-ex"; - args[3] = (char*)"set debug-file-directory /usr/lib/debug:" DEBUGINFO_CACHE_DIR"/usr/lib/debug"; + string dfd = "set debug-file-directory /usr/lib/debug"; + const char *p = pDebugInfoDirs; + while (1) + { + const char *colon_or_nul = strchrnul(p, ':'); + dfd += ':'; + dfd.append(p, colon_or_nul - p); + dfd += "/usr/lib/debug"; + if (*colon_or_nul != ':') + break; + p = colon_or_nul + 1; + } + args[3] = (char*)dfd.c_str(); + /* * Unfortunately, "file BINARY_FILE" doesn't work well if BINARY_FILE * was deleted (as often happens during system updates): @@ -282,22 +298,23 @@ static void GetBacktrace(const char *pDebugDumpDir, std::string& pBacktrace) * See https://bugzilla.redhat.com/show_bug.cgi?id=525721 */ args[4] = (char*)"-ex"; - args[5] = xasprintf("file %s", executable.c_str()); + string file = ssprintf("file %s", executable.c_str()); + args[5] = (char*)file.c_str(); + args[6] = (char*)"-ex"; - args[7] = xasprintf("core-file %s/"FILENAME_COREDUMP, pDebugDumpDir); + string corefile = ssprintf("core-file %s/"FILENAME_COREDUMP, pDebugDumpDir); + args[7] = (char*)corefile.c_str(); + args[8] = (char*)"-ex"; args[9] = (char*)"thread apply all backtrace full"; args[10] = NULL; ExecVP(args, atoi(UID.c_str()), pBacktrace); - - free(args[5]); - free(args[7]); } -static std::string GetIndependentBacktrace(const std::string& pBacktrace) +static string GetIndependentBacktrace(const char *pBacktrace) { - std::string header; + string header; bool in_bracket = false; bool in_quote = false; bool in_header = false; @@ -305,7 +322,7 @@ static std::string GetIndependentBacktrace(const std::string& pBacktrace) bool has_at = false; bool has_filename = false; bool has_bracket = false; - std::set<std::string> set_headers; + set<string> set_headers; /* Backtrace example: #0 0x00007f047e21af70 in __nanosleep_nocancel () from /lib64/libc-2.10.1.so @@ -328,7 +345,7 @@ static std::string GetIndependentBacktrace(const std::string& pBacktrace) seconds = 1260 ok = true */ - const char *bk = pBacktrace.c_str(); + const char *bk = pBacktrace; while (*bk) { if (bk[0] == '#' @@ -348,11 +365,11 @@ static std::string GetIndependentBacktrace(const std::string& pBacktrace) { in_digit = true; } - else if (bk[0] == '\\' && bk[1] == '\"') + else if (bk[0] == '\\' && bk[1] == '"') { bk++; } - else if (*bk == '\"') + else if (*bk == '"') { in_quote = in_quote == true ? false : true; } @@ -406,8 +423,8 @@ static std::string GetIndependentBacktrace(const std::string& pBacktrace) bk++; } - std::string pIndependentBacktrace; - std::set<std::string>::iterator it = set_headers.begin(); + string pIndependentBacktrace; + set<string>::iterator it = set_headers.begin(); for (; it != set_headers.end(); it++) { pIndependentBacktrace += *it; @@ -416,39 +433,35 @@ static std::string GetIndependentBacktrace(const std::string& pBacktrace) return pIndependentBacktrace; } -static void GetIndependentBuildIdPC(const std::string& pBuildIdPC, std::string& pIndependentBuildIdPC) +static void GetIndependentBuildIdPC(const char *unstrip_n_output, string& pIndependentBuildIdPC) { - int ii = 0; - while (ii < pBuildIdPC.length()) + // lines look like this: + // 0x400000+0x209000 23c77451cf6adff77fc1f5ee2a01d75de6511dda@0x40024c - - [exe] + // 0x400000+0x209000 ab3c8286aac6c043fd1bb1cc2a0b88ec29517d3e@0x40024c /bin/sleep /usr/lib/debug/bin/sleep.debug [exe] + // 0x7fff313ff000+0x1000 389c7475e3d5401c55953a425a2042ef62c4c7df@0x7fff313ff2f8 . - linux-vdso.so.1 + const char *line = unstrip_n_output; + while (*line) { - std::string line; - int jj = 0; - - while (pBuildIdPC[ii] != '\n' && ii < pBuildIdPC.length()) - { - line += pBuildIdPC[ii]; - ii++; - } - while (line[jj] != '+' && jj < line.length()) + const char *eol = strchrnul(line, '\n'); + const char *plus = (char*)memchr(line, '+', eol - line); + if (plus) { - jj++; - } - jj++; - while (line[jj] != '@' && jj < line.length()) - { - if (!isspace(line[jj])) + while (++plus < eol && *plus != '@') { - pIndependentBuildIdPC += line[jj]; + if (!isspace(*plus)) + { + pIndependentBuildIdPC += *plus; + } } - jj++; } - ii++; + if (*eol != '\n') break; + line = eol + 1; } } -static std::string run_unstrip_n(const char *pDebugDumpDir) +static string run_unstrip_n(const char *pDebugDumpDir) { - std::string UID; + string UID; { CDebugDump dd; dd.Open(pDebugDumpDir); @@ -461,7 +474,7 @@ static std::string run_unstrip_n(const char *pDebugDumpDir) args[2] = (char*)"-n"; args[3] = NULL; - std::string output; + string output; ExecVP(args, atoi(UID.c_str()), output); free(args[1]); @@ -481,10 +494,10 @@ static bool is_hexstr(const char* str) } return true; } -static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) +static void InstallDebugInfos(const char *pDebugDumpDir, const char *debuginfo_dirs, string& build_ids) { log("Getting module names, file names, build IDs from core file"); - std::string unstrip_list = run_unstrip_n(pDebugDumpDir); + string unstrip_list = run_unstrip_n(pDebugDumpDir); log("Builting list of missing debuginfos"); // lines look like this: @@ -542,7 +555,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) } //missing vector is unused for now, but TODO: use it to install only needed debuginfos - std::string package; + string package; { CDebugDump dd; dd.Open(pDebugDumpDir); @@ -629,7 +642,7 @@ Another application is holding the yum lock, cannot continue bool already_installed = false; #endif char buff[1024]; - std::string packageName = package.substr(0, package.rfind("-", package.rfind("-")-1)); + string packageName = package.substr(0, package.rfind("-", package.rfind("-")-1)); while (fgets(buff, sizeof(buff), pipeout_fp)) { int last = strlen(buff) - 1; @@ -662,7 +675,7 @@ Another application is holding the yum lock, cannot continue fclose(pipeout_fp); kill(child, SIGTERM); wait(NULL); - throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": cannot install debuginfos for " + pPackage); + throw CABRTException(EXCEP_PLUGIN, string(__func__) + ": cannot install debuginfos for " + pPackage); } #endif } @@ -674,7 +687,7 @@ Another application is holding the yum lock, cannot continue /* Needs gdb feature from here: https://bugzilla.redhat.com/show_bug.cgi?id=528668 * It is slated to be in F12/RHEL6. */ -static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) +static void InstallDebugInfos(const char *pDebugDumpDir, const char *debuginfo_dirs, string& build_ids) { update_client(_("Searching for debug-info packages...")); @@ -703,8 +716,8 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) /* SELinux guys are not happy with /tmp, using /var/run/abrt */ char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%u-%lu", (int)getpid(), (long)time(NULL)); /* log() goes to stderr/syslog, it's ok to use it here */ - VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR); - execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR, NULL); + VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, debuginfo_dirs); + execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, debuginfo_dirs, NULL); exit(1); } @@ -750,7 +763,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) wait(NULL); } -static double get_dir_size(const char *dirname, std::string *worst_file, double *maxsz) +static double get_dir_size(const char *dirname, string *worst_file, double *maxsz) { DIR *dp = opendir(dirname); if (dp == NULL) @@ -763,7 +776,7 @@ static double get_dir_size(const char *dirname, std::string *worst_file, double { if (dot_or_dotdot(ep->d_name)) continue; - std::string dname = concat_path_file(dirname, ep->d_name); + string dname = concat_path_file(dirname, ep->d_name); if (lstat(dname.c_str(), &stats) != 0) continue; if (S_ISDIR(stats.st_mode)) @@ -801,7 +814,7 @@ static void trim_debuginfo_cache(unsigned max_mb) { while (1) { - std::string worst_file; + string worst_file; double maxsz = 0; double cache_sz = get_dir_size(DEBUGINFO_CACHE_DIR, &worst_file, &maxsz); if (cache_sz / (1024 * 1024) < max_mb) @@ -813,12 +826,12 @@ static void trim_debuginfo_cache(unsigned max_mb) } } -std::string CAnalyzerCCpp::GetLocalUUID(const char *pDebugDumpDir) +string CAnalyzerCCpp::GetLocalUUID(const char *pDebugDumpDir) { log(_("Getting local universal unique identification...")); - std::string executable; - std::string package; + string executable; + string package; { CDebugDump dd; dd.Open(pDebugDumpDir); @@ -826,19 +839,19 @@ std::string CAnalyzerCCpp::GetLocalUUID(const char *pDebugDumpDir) dd.LoadText(FILENAME_PACKAGE, package); } - std::string buildIdPC = run_unstrip_n(pDebugDumpDir); - std::string independentBuildIdPC; - GetIndependentBuildIdPC(buildIdPC, independentBuildIdPC); - return CreateHash(package + executable + independentBuildIdPC); + string unstrip_n_output = run_unstrip_n(pDebugDumpDir); + string independentBuildIdPC; + GetIndependentBuildIdPC(unstrip_n_output.c_str(), independentBuildIdPC); + return CreateHash((package + executable + independentBuildIdPC).c_str()); } -std::string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) +string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) { log(_("Getting global universal unique identification...")); - std::string backtrace; - std::string executable; - std::string package; + string backtrace; + string executable; + string package; { CDebugDump dd; dd.Open(pDebugDumpDir); @@ -846,8 +859,8 @@ std::string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) dd.LoadText(FILENAME_EXECUTABLE, executable); dd.LoadText(FILENAME_PACKAGE, package); } - std::string independentBacktrace = GetIndependentBacktrace(backtrace); - return CreateHash(package + executable + independentBacktrace); + string independentBacktrace = GetIndependentBacktrace(backtrace.c_str()); + return CreateHash((package + executable + independentBacktrace).c_str()); } static bool DebuginfoCheckPolkit(int uid) @@ -881,9 +894,9 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force) { update_client(_("Starting report creation...")); - std::string package; - std::string backtrace; - std::string UID; + string package; + string backtrace; + string UID; CDebugDump dd; dd.Open(pDebugDumpDir); @@ -901,18 +914,21 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force) dd.LoadText(FILENAME_UID, UID); dd.Close(); /* do not keep dir locked longer than needed */ - std::string build_ids; - if (m_bInstallDebugInfo && DebuginfoCheckPolkit(atoi(UID.c_str()))) { - if (m_nDebugInfoCacheMB > 0) + string build_ids; + if (m_bInstallDebugInfo && DebuginfoCheckPolkit(atoi(UID.c_str()))) + { + if (m_nDebugInfoCacheMB > 0) + { trim_debuginfo_cache(m_nDebugInfoCacheMB); - InstallDebugInfos(pDebugDumpDir, build_ids); + } + InstallDebugInfos(pDebugDumpDir, m_sDebugInfoDirs.c_str(), build_ids); } else { VERB1 log(_("Skipping debuginfo installation")); } - GetBacktrace(pDebugDumpDir, backtrace); + GetBacktrace(pDebugDumpDir, m_sDebugInfoDirs.c_str(), backtrace); dd.Open(pDebugDumpDir); dd.SaveText(FILENAME_BACKTRACE, (build_ids + backtrace).c_str()); @@ -926,7 +942,7 @@ void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force) void CAnalyzerCCpp::Init() { - std::ifstream fInCorePattern; + ifstream fInCorePattern; fInCorePattern.open(CORE_PATTERN_IFACE); if (fInCorePattern.is_open()) { @@ -951,22 +967,22 @@ void CAnalyzerCCpp::Init() } } - std::ofstream fOutCorePattern; + ofstream fOutCorePattern; fOutCorePattern.open(CORE_PATTERN_IFACE); if (fOutCorePattern.is_open()) { - fOutCorePattern << CORE_PATTERN << std::endl; + fOutCorePattern << CORE_PATTERN << endl; fOutCorePattern.close(); } } void CAnalyzerCCpp::DeInit() { - std::ofstream fOutCorePattern; + ofstream fOutCorePattern; fOutCorePattern.open(CORE_PATTERN_IFACE); if (fOutCorePattern.is_open()) { - fOutCorePattern << m_sOldCorePattern << std::endl; + fOutCorePattern << m_sOldCorePattern << endl; fOutCorePattern.close(); } } @@ -999,6 +1015,13 @@ void CAnalyzerCCpp::SetSettings(const map_plugin_settings_t& pSettings) { m_bInstallDebugInfo = string_to_bool(it->second.c_str()); } + m_sDebugInfoDirs = DEBUGINFO_CACHE_DIR; + it = pSettings.find("ReadonlyLocalDebugInfoDirs"); + if (it != end) + { + m_sDebugInfoDirs += ':'; + m_sDebugInfoDirs += it->second; + } } //ok to delete? @@ -1016,7 +1039,7 @@ PLUGIN_INFO(ANALYZER, CAnalyzerCCpp, "CCpp", "0.0.1", - "Simple C/C++ analyzer plugin.", + "Analyzes crashes in C/C++ programs", "zprikryl@redhat.com", "https://fedorahosted.org/abrt/wiki", ""); diff --git a/lib/Plugins/CCpp.h b/lib/Plugins/CCpp.h index 3fa0d99..26dedea 100644 --- a/lib/Plugins/CCpp.h +++ b/lib/Plugins/CCpp.h @@ -35,6 +35,7 @@ class CAnalyzerCCpp : public CAnalyzer unsigned m_nDebugInfoCacheMB; std::string m_sOldCorePattern; std::string m_sDebugInfo; + std::string m_sDebugInfoDirs; public: CAnalyzerCCpp(); diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp index e6d16b4..cf1d7d9 100644 --- a/lib/Plugins/Catcut.cpp +++ b/lib/Plugins/Catcut.cpp @@ -33,7 +33,7 @@ static void create_new_bug_description(const map_crash_report_t& pCrashReport, s "-----\n" + pCrashReport.find(CD_COMMENT)->second[CD_CONTENT]; } - pDescription = "\nabrt detected a crash.\n" + + pDescription = "\nabrt "VERSION" detected a crash.\n" + howToReproduce + comment + "\n\nAdditional information\n" @@ -573,7 +573,7 @@ PLUGIN_INFO(REPORTER, CReporterCatcut, "Catcut", "0.0.1", - "Test plugin to report bugs to catcut and if not, report it.", + "Reports bugs to catcut", "dvlasenk@redhat.com", "https://fedorahosted.org/abrt/wiki", PLUGINS_LIB_DIR"/Catcut.GTKBuilder"); diff --git a/lib/Plugins/Firefox.cpp b/lib/Plugins/Firefox.cpp new file mode 100644 index 0000000..68dbd39 --- /dev/null +++ b/lib/Plugins/Firefox.cpp @@ -0,0 +1,1022 @@ +/* + Firefox.cpp + + Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <sys/wait.h> +#include <fstream> +#include <sstream> +#include <set> +#include <iomanip> +#include <nss.h> +#include <sechash.h> +#include "abrtlib.h" +#include "Firefox.h" +#include "ABRTException.h" +#include "DebugDump.h" +#include "CommLayerInner.h" +#include "Polkit.h" + +#define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern" +#define CORE_PATTERN "|"CCPP_HOOK_PATH" "DEBUG_DUMPS_DIR" %p %s %u" + +#define FILENAME_COREDUMP "coredump" +#define FILENAME_BACKTRACE "backtrace" +#define FILENAME_MEMORYMAP "memorymap" + +#define DEBUGINFO_CACHE_DIR LOCALSTATEDIR"/cache/abrt-di" + +CAnalyzerFirefox::CAnalyzerFirefox() : + m_bMemoryMap(false), + m_bInstallDebugInfo(true), + m_nDebugInfoCacheMB(4000) +{} + +static std::string CreateHash(const std::string& pInput) +{ + std::string ret = ""; + HASHContext* hc; + unsigned char hash[SHA1_LENGTH]; + unsigned int len; + + hc = HASH_Create(HASH_AlgSHA1); + if (!hc) + { + error_msg_and_die("HASH_Create(HASH_AlgSHA1) failed"); /* paranoia */ + } + HASH_Begin(hc); + HASH_Update(hc, reinterpret_cast<const unsigned char*>(pInput.c_str()), pInput.length()); + HASH_End(hc, hash, &len, sizeof(hash)); + HASH_Destroy(hc); + + char hash_str[SHA1_LENGTH*2 + 1]; + char *d = hash_str; + unsigned char *s = hash; + while (len) + { + *d++ = "0123456789abcdef"[*s >> 4]; + *d++ = "0123456789abcdef"[*s & 0xf]; + s++; + len--; + } + *d = '\0'; + + return hash_str; +} + +static std::string concat_str_vector(char **strings) +{ + std::string result; + while (*strings) + { + result += *strings++; + if (*strings) + result += ' '; + } + return result; +} + +static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput) +{ + int pipeout[2]; + pid_t child; + + struct passwd* pw = getpwuid(uid); + if (!pw) + { + throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": cannot get GID for UID."); + } + + xpipe(pipeout); + child = fork(); + if (child == -1) + { + perror_msg_and_die("fork"); + } + if (child == 0) + { + VERB1 log("Executing: %s", concat_str_vector(pArgs).c_str()); + close(pipeout[0]); /* read side of the pipe */ + xmove_fd(pipeout[1], STDOUT_FILENO); + /* Make sure stdin is safely open to nothing */ + close(STDIN_FILENO); + if (open("/dev/null", O_RDONLY)) + if (open("/", O_RDONLY)) + abort(); /* never happens */ + /* Not a good idea, we won't see any error messages */ + /* close(STDERR_FILENO); */ + + setgroups(1, &pw->pw_gid); + setregid(pw->pw_gid, pw->pw_gid); + setreuid(uid, uid); + setsid(); + + /* Nuke everything which may make setlocale() switch to non-POSIX locale: + * we need to avoid having gdb output in some obscure language. + */ + unsetenv("LANG"); + unsetenv("LC_ALL"); + unsetenv("LC_COLLATE"); + unsetenv("LC_CTYPE"); + unsetenv("LC_MESSAGES"); + unsetenv("LC_MONETARY"); + unsetenv("LC_NUMERIC"); + unsetenv("LC_TIME"); + + execvp(pArgs[0], pArgs); + /* VERB1 since sometimes we expect errors here */ + VERB1 perror_msg("Can't execute '%s'", pArgs[0]); + exit(1); + } + + close(pipeout[1]); /* write side of the pipe */ + + int r; + char buff[1024]; + while ((r = read(pipeout[0], buff, sizeof(buff) - 1)) > 0) + { + buff[r] = '\0'; + pOutput += buff; + } + + close(pipeout[0]); + wait(NULL); /* prevent having zombie child process */ + + return 0; +} + +enum LineRating +{ + // RATING EXAMPLE + MissingEverything = 0, // #0 0x0000dead in ?? () + MissingFunction = 1, // #0 0x0000dead in ?? () from /usr/lib/libfoobar.so.4 + MissingLibrary = 2, // #0 0x0000dead in foobar() + MissingSourceFile = 3, // #0 0x0000dead in FooBar::FooBar () from /usr/lib/libfoobar.so.4 + Good = 4, // #0 0x0000dead in FooBar::crash (this=0x0) at /home/user/foobar.cpp:204 + BestRating = Good, +}; + +static LineRating rate_line(const char *line) +{ +#define FOUND(x) (strstr(line, x) != NULL) + /* see the "enum LineRating" comments for possible combinations */ + if (FOUND(" at ")) + return Good; + const char *function = strstr(line, " in "); + if (function) + { + if (function[4] == '?') /* " in ??" does not count */ + { + function = NULL; + } + } + bool library = FOUND(" from "); + if (function && library) + return MissingSourceFile; + if (function) + return MissingLibrary; + if (library) + return MissingFunction; + + return MissingEverything; +#undef FOUND +} + +/* returns number of "stars" to show */ +static int rate_backtrace(const char *backtrace) +{ + int i, j, len; + int multiplier = 0; + int rating = 0; + int best_possible_rating = 0; + + /* We look at the frames in reversed order, since: + * - rate_line() checks starting from the first line of the frame + * (note: it may need to look at more than one line!) + * - we increase weight (multiplier) for every frame, + * so that topmost frames end up most important + */ + len = 0; + for (i = strlen(backtrace) - 1; i >= 0; i--) + { + if (backtrace[i] == '#') /* this separates frames from each other */ + { + std::string s(backtrace + i + 1, len); + for (j=0; j<len; j++) /* replace tabs with spaces */ + if (s[j] == '\t') + s[j] = ' '; + multiplier++; + rating += rate_line(s.c_str()) * multiplier; + best_possible_rating += BestRating * multiplier; + len = 0; /* starting new line */ + } + else + { + len++; + } + } + + /* Bogus "backtrace" with zero frames? */ + if (best_possible_rating == 0) + return 0; + + /* Returning number of "stars" to show */ + if (rating*10 >= best_possible_rating*8) /* >= 0.8 */ + return 4; + if (rating*10 >= best_possible_rating*6) + return 3; + if (rating*10 >= best_possible_rating*4) + return 2; + if (rating*10 >= best_possible_rating*2) + return 1; + + return 0; +} + +static void GetBacktrace(const char *pDebugDumpDir, std::string& pBacktrace) +{ + update_client(_("Getting backtrace...")); + + std::string UID; + std::string executable; + { + CDebugDump dd; + dd.Open(pDebugDumpDir); + dd.LoadText(FILENAME_EXECUTABLE, executable); + dd.LoadText(FILENAME_UID, UID); + } + + // Workaround for + // http://sourceware.org/bugzilla/show_bug.cgi?id=9622 + unsetenv("TERM"); + putenv((char*)"TERM=dumb"); + + char* args[11]; + args[0] = (char*)"gdb"; + args[1] = (char*)"-batch"; + // when/if gdb supports it: + // (https://bugzilla.redhat.com/show_bug.cgi?id=528668): + args[2] = (char*)"-ex"; + args[3] = (char*)"set debug-file-directory /usr/lib/debug:" DEBUGINFO_CACHE_DIR"/usr/lib/debug"; + /* + * Unfortunately, "file BINARY_FILE" doesn't work well if BINARY_FILE + * was deleted (as often happens during system updates): + * gdb uses specified BINARY_FILE + * even if it is completely unrelated to the coredump + * See https://bugzilla.redhat.com/show_bug.cgi?id=525721 + */ + args[4] = (char*)"-ex"; + args[5] = xasprintf("file %s", executable.c_str()); + args[6] = (char*)"-ex"; + args[7] = xasprintf("core-file %s/"FILENAME_COREDUMP, pDebugDumpDir); + args[8] = (char*)"-ex"; + args[9] = (char*)"thread apply all backtrace full"; + args[10] = NULL; + + ExecVP(args, atoi(UID.c_str()), pBacktrace); + + free(args[5]); + free(args[7]); +} + +static std::string GetIndependentBacktrace(const std::string& pBacktrace) +{ + std::string header; + bool in_bracket = false; + bool in_quote = false; + bool in_header = false; + bool in_digit = false; + bool has_at = false; + bool has_filename = false; + bool has_bracket = false; + std::set<std::string> set_headers; + + /* Backtrace example: + #0 0x00007f047e21af70 in __nanosleep_nocancel () from /lib64/libc-2.10.1.so + + Thread 1 (Thread 30750): + #0 0x00007f047e21af70 in __nanosleep_nocancel () from /lib64/libc-2.10.1.so + No symbol table info available. + #1 0x00000000004037bb in rpl_nanosleep (requested_delay=0x7fff8999e400, + remaining_delay=0x0) at nanosleep.c:69 + r = -516 + delay = {tv_sec = 1260, tv_nsec = 0} + t0 = {tv_sec = 12407, tv_nsec = 291505364} + #2 0x000000000040322b in xnanosleep (seconds=<value optimized out>) + at xnanosleep.c:112 + overflow = false + ts_sleep = {tv_sec = 1260, tv_nsec = 0} + __PRETTY_FUNCTION__ = "xnanosleep" + #3 0x0000000000401779 in main (argc=2, argv=0x7fff8999e598) at sleep.c:147 + i = 2 + seconds = 1260 + ok = true + */ + const char *bk = pBacktrace.c_str(); + while (*bk) + { + if (bk[0] == '#' + && bk[1] >= '0' && bk[1] <= '7' + && bk[2] == ' ' /* take only #0...#7 (8 last stack frames) */ + && !in_quote + ) { + if (in_header && !has_filename) + { + header = ""; + } + in_header = true; + } + if (in_header) + { + if (isdigit(*bk) && !in_quote && !has_at) + { + in_digit = true; + } + else if (bk[0] == '\\' && bk[1] == '\"') + { + bk++; + } + else if (*bk == '\"') + { + in_quote = in_quote == true ? false : true; + } + else if (*bk == '(' && !in_quote) + { + in_bracket = true; + in_digit = false; + header += '('; + } + else if (*bk == ')' && !in_quote) + { + in_bracket = false; + has_bracket = true; + in_digit = false; + header += ')'; + } + else if (*bk == '\n' && has_filename) + { + set_headers.insert(header); + in_bracket = false; + in_quote = false; + in_header = false; + in_digit = false; + has_at = false; + has_filename = false; + has_bracket = false; + header = ""; + } + else if (*bk == ',' && !in_quote) + { + in_digit = false; + } + else if (isspace(*bk) && !in_quote) + { + in_digit = false; + } + else if (bk[0] == 'a' && bk[1] == 't' && has_bracket && !in_quote) + { + has_at = true; + header += 'a'; + } + else if (bk[0] == ':' && has_at && isdigit(bk[1]) && !in_quote) + { + has_filename = true; + } + else if (in_header && !in_digit && !in_quote && !in_bracket) + { + header += *bk; + } + } + bk++; + } + + std::string pIndependentBacktrace; + std::set<std::string>::iterator it = set_headers.begin(); + for (; it != set_headers.end(); it++) + { + pIndependentBacktrace += *it; + } + VERB3 log("IndependentBacktrace:'%s'", pIndependentBacktrace.c_str()); + return pIndependentBacktrace; +} + +static void GetIndependentBuildIdPC(const std::string& pBuildIdPC, std::string& pIndependentBuildIdPC) +{ + int ii = 0; + while (ii < pBuildIdPC.length()) + { + std::string line; + int jj = 0; + + while (pBuildIdPC[ii] != '\n' && ii < pBuildIdPC.length()) + { + line += pBuildIdPC[ii]; + ii++; + } + while (line[jj] != '+' && jj < line.length()) + { + jj++; + } + jj++; + while (line[jj] != '@' && jj < line.length()) + { + if (!isspace(line[jj])) + { + pIndependentBuildIdPC += line[jj]; + } + jj++; + } + ii++; + } +} + +static std::string run_unstrip_n(const char *pDebugDumpDir) +{ + std::string UID; + { + CDebugDump dd; + dd.Open(pDebugDumpDir); + dd.LoadText(FILENAME_UID, UID); + } + + char* args[4]; + args[0] = (char*)"eu-unstrip"; + args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, pDebugDumpDir); + args[2] = (char*)"-n"; + args[3] = NULL; + + std::string output; + ExecVP(args, atoi(UID.c_str()), output); + + free(args[1]); + + return output; +} + +#if 0 +/* older code */ +static bool is_hexstr(const char* str) +{ + while (*str) + { + if (!isxdigit(*str)) + return false; + str++; + } + return true; +} +static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) +{ + log("Getting module names, file names, build IDs from core file"); + std::string unstrip_list = run_unstrip_n(pDebugDumpDir); + + log("Builting list of missing debuginfos"); + // lines look like this: + // 0x400000+0x209000 23c77451cf6adff77fc1f5ee2a01d75de6511dda@0x40024c - - [exe] + // 0x400000+0x209000 ab3c8286aac6c043fd1bb1cc2a0b88ec29517d3e@0x40024c /bin/sleep /usr/lib/debug/bin/sleep.debug [exe] + // 0x7fff313ff000+0x1000 389c7475e3d5401c55953a425a2042ef62c4c7df@0x7fff313ff2f8 . - linux-vdso.so.1 + vector_string_t missing; + char *dup = xstrdup(unstrip_list.c_str()); + char *p = dup; + char c; + do { + char* end = strchrnul(p, '\n'); + c = *end; + *end = '\0'; + char* word2 = strchr(p, ' '); + if (!word2) + continue; + word2++; + char* endsp = strchr(word2, ' '); + if (!endsp) + continue; + /* endsp points to 2nd space in the line now*/ + + /* This filters out linux-vdso.so, among others */ + if (strstr(endsp, "[exe]") == NULL && endsp[1] != '/') + continue; + *endsp = '\0'; + char* at = strchrnul(word2, '@'); + *at = '\0'; + + bool file_exists = 1; + if (word2[0] && word2[1] && is_hexstr(word2)) + { + struct stat sb; + char *fn = xasprintf("/usr/lib/debug/.build-id/%.2s/%s.debug", word2, word2 + 2); + /* Not lstat: this is a symlink and we want link's TARGET to exist */ + file_exists = stat(fn, &sb) == 0 && S_ISREG(sb.st_mode); + free(fn); + build_ids += "build-id "; + build_ids += word2; + build_ids += file_exists ? " (debuginfo present)\n" : " (debuginfo absent)\n"; + } + log("build_id:%s exists:%d", word2, (int)file_exists); + if (!file_exists) + missing.push_back(word2); + + p = end + 1; + } while (c); + free(dup); + + if (missing.size() == 0) + { + log("All debuginfos are present, not installing debuginfo packages"); + return; + } + //missing vector is unused for now, but TODO: use it to install only needed debuginfos + + std::string package; + { + CDebugDump dd; + dd.Open(pDebugDumpDir); + dd.LoadText(FILENAME_PACKAGE, package); + } + + update_client(_("Searching for debug-info packages...")); + + int pipein[2], pipeout[2]; + xpipe(pipein); + xpipe(pipeout); + + pid_t child = fork(); + if (child < 0) + { + /*close(pipein[0]); close(pipeout[0]); - why bother */ + /*close(pipein[1]); close(pipeout[1]); */ + perror_msg_and_die("fork"); + } + if (child == 0) + { + close(pipein[1]); + close(pipeout[0]); + xmove_fd(pipein[0], STDIN_FILENO); + xmove_fd(pipeout[1], STDOUT_FILENO); + /* Not a good idea, we won't see any error messages */ + /*close(STDERR_FILENO);*/ + + setsid(); +/* Honestly, I do not know what is worse, pk-debuginfo-install or debuginfo-install: + +# pk-debuginfo-install -y -- coreutils-7.2-4.fc11 +1. Getting sources list...OK. Found 16 enabled and 23 disabled sources. +2. Finding debugging sources...OK. Found 0 disabled debuginfo repos. +3. Enabling debugging sources...OK. Enabled 0 debugging sources. +4. Finding debugging packages...Failed to find the package : more than one package found for +Failed to find the package : more than one package found for +FAILED. Found no packages to install. +5. Disabling sources previously enabled...OK. Disabled 0 debugging sources. + +:( FAIL! + +# debuginfo-install -y -- coreutils-7.2-4.fc11 +Loaded plugins: refresh-packagekit +Another application is holding the yum lock, cannot continue + +:( FAIL! + +# debuginfo-install -y -- coreutils-7.2-4.fc11 +(second time in a row - it worked) + +*/ + /* log() goes to stderr/syslog, it's ok to use it here */ + VERB1 log("Executing: %s %s %s %s", "pk-debuginfo-install", "-y", "--", package.c_str()); + execlp("pk-debuginfo-install", "pk-debuginfo-install", "-y", "--", package.c_str(), NULL); + /* fall back */ + VERB1 log("Executing: %s %s %s %s", "debuginfo-install", "-y", "--", package.c_str()); + execlp("debuginfo-install", "debuginfo-install", "-y", "--", package.c_str(), NULL); + exit(1); + } + + close(pipein[0]); + close(pipeout[1]); + + /* Should not be needed (we use -y option), but just in case: */ + safe_write(pipein[1], "y\n", sizeof("y\n")-1); + close(pipein[1]); + + update_client(_("Downloading and installing debug-info packages...")); + + FILE *pipeout_fp = fdopen(pipeout[0], "r"); + if (pipeout_fp == NULL) /* never happens */ + { + close(pipeout[0]); + wait(NULL); + return; + } + +/* glx-utils, for example, do not have glx-utils-debuginfo package. + * Disabled code was causing failures in backtrace decoding. + * This does not seem to be useful. + */ +#ifdef COMPLAIN_IF_NO_DEBUGINFO + bool already_installed = false; +#endif + char buff[1024]; + std::string packageName = package.substr(0, package.rfind("-", package.rfind("-")-1)); + while (fgets(buff, sizeof(buff), pipeout_fp)) + { + int last = strlen(buff) - 1; + if (last >= 0 && buff[last] == '\n') + buff[last] = '\0'; + + log("%s", buff); + update_client("%s", buff); /* maybe only if buff != ""? */ + +#ifdef COMPLAIN_IF_NO_DEBUGINFO + if (already_installed == false) + { + /* "Package foo-debuginfo-1.2-5.ARCH already installed and latest version" */ + char* pn = strstr(buff, packageName.c_str()); + if (pn) + { + char* already_str = strstr(pn, "already installed and latest version"); + if (already_str) + { + already_installed = true; + } + } + } + + if (already_installed == false && + (strstr(buff, "No debuginfo packages available to install") != NULL || + strstr(buff, "Could not find debuginfo for main pkg") != NULL || + strstr(buff, "Could not find debuginfo pkg for dependency package") != NULL)) + { + fclose(pipeout_fp); + kill(child, SIGTERM); + wait(NULL); + throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": cannot install debuginfos for " + pPackage); + } +#endif + } + + fclose(pipeout_fp); + wait(NULL); +} +#endif +/* Needs gdb feature from here: https://bugzilla.redhat.com/show_bug.cgi?id=528668 + * It is slated to be in F12/RHEL6. + */ +static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) +{ + update_client(_("Searching for debug-info packages...")); + + int pipeout[2]; //TODO: can we use ExecVP? + xpipe(pipeout); + + pid_t child = fork(); + if (child < 0) + { + /*close(pipeout[0]); - why bother */ + /*close(pipeout[1]); */ + perror_msg_and_die("fork"); + } + if (child == 0) + { + close(pipeout[0]); + xmove_fd(pipeout[1], STDOUT_FILENO); + close(STDIN_FILENO); + xopen("/dev/null", O_RDONLY); + /* Not a good idea, we won't see any error messages */ + /*close(STDERR_FILENO);*/ + + setsid(); + + char *coredump = xasprintf("%s/"FILENAME_COREDUMP, pDebugDumpDir); + /* SELinux guys are not happy with /tmp, using /var/run/abrt */ + char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%u-%lu", (int)getpid(), (long)time(NULL)); + /* log() goes to stderr/syslog, it's ok to use it here */ + VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR); + execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR, NULL); + exit(1); + } + + close(pipeout[1]); + + update_client(_("Downloading and installing debug-info packages...")); + + FILE *pipeout_fp = fdopen(pipeout[0], "r"); + if (pipeout_fp == NULL) /* never happens */ + { + close(pipeout[0]); + wait(NULL); + return; + } + + char buff[1024]; + while (fgets(buff, sizeof(buff), pipeout_fp)) + { + int last = strlen(buff) - 1; + if (last >= 0 && buff[last] == '\n') + buff[last] = '\0'; + + if (strncmp(buff, "MISSING:", 8) == 0) + { + build_ids += "Debuginfo absent: "; + build_ids += buff + 8; + build_ids += "\n"; + } + + const char *p = buff; + while (*p == ' ' || *p == '\t') + { + p++; + } + if (*p) + { + log("%s", buff); + update_client("%s", buff); + } + } + + fclose(pipeout_fp); + wait(NULL); +} + +static double get_dir_size(const char *dirname, std::string *worst_file, double *maxsz) +{ + DIR *dp = opendir(dirname); + if (dp == NULL) + return 0; + + struct dirent *ep; + struct stat stats; + double size = 0; + while ((ep = readdir(dp)) != NULL) + { + if (dot_or_dotdot(ep->d_name)) + continue; + std::string dname = concat_path_file(dirname, ep->d_name); + if (lstat(dname.c_str(), &stats) != 0) + continue; + if (S_ISDIR(stats.st_mode)) + { + double sz = get_dir_size(dname.c_str(), worst_file, maxsz); + size += sz; + } + else if (S_ISREG(stats.st_mode)) + { + double sz = stats.st_size; + size += sz; + + if (worst_file) + { + /* Calculate "weighted" size and age + * w = sz_kbytes * age_mins */ + sz /= 1024; + long age = (time(NULL) - stats.st_mtime) / 60; + if (age > 0) + sz *= age; + + if (sz > *maxsz) + { + *maxsz = sz; + *worst_file = dname; + } + } + } + } + closedir(dp); + return size; +} + +static void trim_debuginfo_cache(unsigned max_mb) +{ + while (1) + { + std::string worst_file; + double maxsz = 0; + double cache_sz = get_dir_size(DEBUGINFO_CACHE_DIR, &worst_file, &maxsz); + if (cache_sz / (1024 * 1024) < max_mb) + break; + VERB1 log("%s is %.0f bytes (over %u MB), deleting '%s'", + DEBUGINFO_CACHE_DIR, cache_sz, max_mb, worst_file.c_str()); + if (unlink(worst_file.c_str()) != 0) + perror_msg("Can't unlink '%s'", worst_file.c_str()); + } +} + +std::string CAnalyzerFirefox::GetLocalUUID(const char *pDebugDumpDir) +{ + log(_("Getting local universal unique identification...")); + + std::string executable; + std::string package; + { + CDebugDump dd; + dd.Open(pDebugDumpDir); + dd.LoadText(FILENAME_EXECUTABLE, executable); + dd.LoadText(FILENAME_PACKAGE, package); + } + + std::string buildIdPC = run_unstrip_n(pDebugDumpDir); + std::string independentBuildIdPC; + GetIndependentBuildIdPC(buildIdPC, independentBuildIdPC); + return CreateHash(package + executable + independentBuildIdPC); +} + +std::string CAnalyzerFirefox::GetGlobalUUID(const char *pDebugDumpDir) +{ + log(_("Getting global universal unique identification...")); + + std::string backtrace; + std::string executable; + std::string package; + { + CDebugDump dd; + dd.Open(pDebugDumpDir); + dd.LoadText(FILENAME_BACKTRACE, backtrace); + dd.LoadText(FILENAME_EXECUTABLE, executable); + dd.LoadText(FILENAME_PACKAGE, package); + } + std::string independentBacktrace = GetIndependentBacktrace(backtrace); + return CreateHash(package + executable + independentBacktrace); +} + +static bool DebuginfoCheckPolkit(int uid) +{ + int child_pid = fork(); + if (child_pid < 0) + { + perror_msg_and_die("fork"); + } + if (child_pid == 0) + { + //child + if (setuid(uid)) + exit(1); //paranoia + PolkitResult result = polkit_check_authorization(getpid(), + "org.fedoraproject.abrt.install-debuginfos"); + exit(result != PolkitYes); //exit 1 (failure) if not allowed + } + + //parent + int status; + if (waitpid(child_pid, &status, 0) > 0 && WEXITSTATUS(status) == 0) + { + return true; //authorization OK + } + log("UID %d is not authorized to install debuginfos", uid); + return false; +} + +void CAnalyzerFirefox::CreateReport(const char *pDebugDumpDir, int force) +{ + update_client(_("Starting report creation...")); + + std::string package; + std::string backtrace; + std::string UID; + + CDebugDump dd; + dd.Open(pDebugDumpDir); + + if (!force) + { + bool bt_exists = dd.Exist(FILENAME_BACKTRACE); + if (bt_exists) + { + return; /* backtrace already exists */ + } + } + + dd.LoadText(FILENAME_PACKAGE, package); + dd.LoadText(FILENAME_UID, UID); + dd.Close(); /* do not keep dir locked longer than needed */ + + std::string build_ids; + if (m_bInstallDebugInfo && DebuginfoCheckPolkit(atoi(UID.c_str()))) { + if (m_nDebugInfoCacheMB > 0) + trim_debuginfo_cache(m_nDebugInfoCacheMB); + InstallDebugInfos(pDebugDumpDir, build_ids); + } + else + { + VERB1 log(_("Skipping debuginfo installation")); + } + + GetBacktrace(pDebugDumpDir, backtrace); + + dd.Open(pDebugDumpDir); + dd.SaveText(FILENAME_BACKTRACE, (build_ids + backtrace).c_str()); + if (m_bMemoryMap) + { + dd.SaveText(FILENAME_MEMORYMAP, "memory map of the crashed C/C++ application, not implemented yet"); + } + dd.SaveText(FILENAME_RATING, to_string(rate_backtrace(backtrace.c_str())).c_str()); + dd.Close(); +} + +void CAnalyzerFirefox::Init() +{ + std::ifstream fInCorePattern; + fInCorePattern.open(CORE_PATTERN_IFACE); + if (fInCorePattern.is_open()) + { + getline(fInCorePattern, m_sOldCorePattern); + fInCorePattern.close(); + } + if (m_sOldCorePattern[0] == '|') + { + if (m_sOldCorePattern == CORE_PATTERN) + { + log("warning: %s already contains %s, " + "did abrt daemon crash recently?", + CORE_PATTERN_IFACE, CORE_PATTERN); + /* There is no point in "restoring" CORE_PATTERN_IFACE + * to CORE_PATTERN on exit. Will restore to a default value: + */ + m_sOldCorePattern = "core"; + } else { + log("warning: %s was already set to run a crash analyser (%s), " + "abrt may interfere with it", + CORE_PATTERN_IFACE, CORE_PATTERN); + } + } + + std::ofstream fOutCorePattern; + fOutCorePattern.open(CORE_PATTERN_IFACE); + if (fOutCorePattern.is_open()) + { + fOutCorePattern << CORE_PATTERN << std::endl; + fOutCorePattern.close(); + } +} + +void CAnalyzerFirefox::DeInit() +{ + std::ofstream fOutCorePattern; + fOutCorePattern.open(CORE_PATTERN_IFACE); + if (fOutCorePattern.is_open()) + { + fOutCorePattern << m_sOldCorePattern << std::endl; + fOutCorePattern.close(); + } +} + +void CAnalyzerFirefox::SetSettings(const map_plugin_settings_t& pSettings) +{ + m_pSettings = pSettings; + + map_plugin_settings_t::const_iterator end = pSettings.end(); + map_plugin_settings_t::const_iterator it; + it = pSettings.find("MemoryMap"); + if (it != end) + { + m_bMemoryMap = string_to_bool(it->second.c_str()); + } + it = pSettings.find("DebugInfo"); + if (it != end) + { + m_sDebugInfo = it->second; + } + it = pSettings.find("DebugInfoCacheMB"); + if (it != end) + { + m_nDebugInfoCacheMB = atoi(it->second.c_str()); + } + it = pSettings.find("InstallDebugInfo"); + if (it == end) //compat, remove after 0.0.11 + it = pSettings.find("InstallDebuginfo"); + if (it != end) + { + m_bInstallDebugInfo = string_to_bool(it->second.c_str()); + } +} + +//ok to delete? +//const map_plugin_settings_t& CAnalyzerCCpp::GetSettings() +//{ +// m_pSettings["MemoryMap"] = m_bMemoryMap ? "yes" : "no"; +// m_pSettings["DebugInfo"] = m_sDebugInfo; +// m_pSettings["DebugInfoCacheMB"] = to_string(m_nDebugInfoCacheMB); +// m_pSettings["InstallDebugInfo"] = m_bInstallDebugInfo ? "yes" : "no"; +// +// return m_pSettings; +//} + +PLUGIN_INFO(ANALYZER, + CAnalyzerFirefox, + "Firefox", + "0.0.1", + "Firefox analyzer plugin.", + "zprikryl@redhat.com", + "https://fedorahosted.org/abrt/wiki", + ""); diff --git a/lib/Plugins/Firefox.h b/lib/Plugins/Firefox.h new file mode 100644 index 0000000..0669f4f --- /dev/null +++ b/lib/Plugins/Firefox.h @@ -0,0 +1,51 @@ +/* + Firefox.h - header file for Firefox analyzer plugin + - it can get UUID and memory maps from core files + + Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef CCPP_H_ +#define CCPP_H_ + +#include <string> +#include "Plugin.h" +#include "Analyzer.h" + +class CAnalyzerFirefox : public CAnalyzer +{ + private: + bool m_bMemoryMap; + bool m_bInstallDebugInfo; + unsigned m_nDebugInfoCacheMB; + std::string m_sOldCorePattern; + std::string m_sDebugInfo; + + public: + CAnalyzerFirefox(); + virtual std::string GetLocalUUID(const char *pDebugDumpDir); + virtual std::string GetGlobalUUID(const char *pDebugDumpDir); + virtual void CreateReport(const char *pDebugDumpDir, int force); + virtual void Init(); + virtual void DeInit(); + virtual void SetSettings(const map_plugin_settings_t& pSettings); +//ok to delete? +// virtual const map_plugin_settings_t& GetSettings(); +}; + +#endif /* CCPP */ diff --git a/lib/Plugins/Kerneloops.cpp b/lib/Plugins/Kerneloops.cpp index b99183c..2e28cf4 100644 --- a/lib/Plugins/Kerneloops.cpp +++ b/lib/Plugins/Kerneloops.cpp @@ -67,7 +67,7 @@ PLUGIN_INFO(ANALYZER, CAnalyzerKerneloops, "Kerneloops", "0.0.2", - "Abrt's Kerneloops plugin.", + "Analyzes kernel oopses", "anton@redhat.com", "https://people.redhat.com/aarapov", ""); diff --git a/lib/Plugins/KerneloopsReporter.cpp b/lib/Plugins/KerneloopsReporter.cpp index f7a6cbb..f38f503 100644 --- a/lib/Plugins/KerneloopsReporter.cpp +++ b/lib/Plugins/KerneloopsReporter.cpp @@ -140,7 +140,7 @@ PLUGIN_INFO(REPORTER, CKerneloopsReporter, "KerneloopsReporter", "0.0.1", - "Sends the Kerneloops crash information to Kerneloops.org", + "Sends kernel oops information to kerneloops.org", "anton@redhat.com", "http://people.redhat.com/aarapov", PLUGINS_LIB_DIR"/KerneloopsReporter.GTKBuilder"); diff --git a/lib/Plugins/KerneloopsScanner.cpp b/lib/Plugins/KerneloopsScanner.cpp index 8c8cd4b..3831f9e 100644 --- a/lib/Plugins/KerneloopsScanner.cpp +++ b/lib/Plugins/KerneloopsScanner.cpp @@ -163,7 +163,7 @@ int CKerneloopsScanner::ScanSysLogFile(const char *filename) */ sz = statb.st_size + 1024; if (statb.st_size > (32*1024*1024 - 1024)) { - xlseek(fd, -(32*1024*1024 - 1024), SEEK_END); + xlseek(fd, statb.st_size - (32*1024*1024 - 1024), SEEK_SET); sz = 32*1024*1024; } buffer = (char*)xzalloc(sz); @@ -184,7 +184,7 @@ PLUGIN_INFO(ACTION, CKerneloopsScanner, "KerneloopsScanner", "0.0.1", - "Save new Kerneloops crashes into debug dump dir", + "Periodically scans for and saves kernel oopses", "anton@redhat.com", "http://people.redhat.com/aarapov", ""); diff --git a/lib/Plugins/Logger.cpp b/lib/Plugins/Logger.cpp index 6babc73..7267b64 100644 --- a/lib/Plugins/Logger.cpp +++ b/lib/Plugins/Logger.cpp @@ -91,7 +91,7 @@ PLUGIN_INFO(REPORTER, CLogger, "Logger", "0.0.1", - "Write a report to a specific file", + "Writes report to a file", "zprikryl@redhat.com", "https://fedorahosted.org/abrt/wiki", PLUGINS_LIB_DIR"/Logger.GTKBuilder"); diff --git a/lib/Plugins/Mailx.cpp b/lib/Plugins/Mailx.cpp index 1979f9e..32eeb25 100644 --- a/lib/Plugins/Mailx.cpp +++ b/lib/Plugins/Mailx.cpp @@ -33,168 +33,143 @@ CMailx::CMailx() : m_sEmailFrom("user@localhost"), m_sEmailTo("root@localhost"), m_sSubject("[abrt] full crash report"), - m_bSendBinaryData(false), - m_nArgs(0), - m_pArgs(NULL) + m_bSendBinaryData(false) {} -void CMailx::FreeMailxArgs() -{ - int ii; - for (ii = 0; ii < m_nArgs; ii++) - { - free(m_pArgs[ii]); - } - free((void*) m_pArgs); - m_pArgs = NULL; - m_nArgs = 0; -} - -void CMailx::AddMailxArg(const std::string& pArg) -{ - m_pArgs = (char**) realloc((void*)m_pArgs, (++m_nArgs) * (sizeof(char*))); - if (pArg == "") - { - m_pArgs[m_nArgs - 1] = NULL; - } - else - { - m_pArgs[m_nArgs - 1] = strdup(pArg.c_str()); - } -} - -void CMailx::ExecMailx(uid_t uid, const std::string& pText) +static void exec_and_feed_input(uid_t uid, const char* pText, char **pArgs) { int pipein[2]; pid_t child; - struct passwd* pw = getpwuid(uid); - if (!pw) - { - throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": cannot get GID for UID."); - } - xpipe(pipein); child = fork(); if (child == -1) { close(pipein[0]); close(pipein[1]); - throw CABRTException(EXCEP_PLUGIN, std::string(__func__) + ": fork failed."); + throw CABRTException(EXCEP_PLUGIN, "Can't fork"); } if (child == 0) { - close(pipein[1]); xmove_fd(pipein[0], STDIN_FILENO); - setgroups(1, &pw->pw_gid); - setregid(pw->pw_gid, pw->pw_gid); + struct passwd* pw = getpwuid(uid); + gid_t gid = pw ? pw->pw_gid : uid; + setgroups(1, &gid); + setregid(gid, gid); setreuid(uid, uid); - setsid(); + setsid(); /* why? I propose removing this */ - execvp(MAILX_COMMAND, m_pArgs); - exit(0); + execvp(pArgs[0], pArgs); + exit(1); /* exec failed */ } close(pipein[0]); - safe_write(pipein[1], pText.c_str(), pText.length()); + safe_write(pipein[1], pText, strlen(pText)); close(pipein[1]); - wait(NULL); /* why? */ + wait(NULL); /* wait for command completion */ } -void CMailx::SendEmail(const std::string& pSubject, const std::string& pText, const std::string& pUID) +static char** append_str_to_vector(char **vec, unsigned &size, const char *str) { - update_client(_("Sending an email...")); - - AddMailxArg("-s"); - AddMailxArg(pSubject); - AddMailxArg("-r"); - AddMailxArg(m_sEmailFrom); - AddMailxArg(m_sEmailTo); - AddMailxArg(""); - - ExecMailx(atoi(pUID.c_str()), pText); + //log("old vec: %p", vec); + vec = (char**) xrealloc(vec, (size+2) * sizeof(vec[0])); + vec[size] = xstrdup(str); + //log("new vec: %p, added [%d] %p", vec, size, vec[size]); + size++; + vec[size] = NULL; + return vec; } -std::string CMailx::Report(const map_crash_report_t& pCrashReport, +std::string CMailx::Report(const map_crash_report_t& pCrashReport, const map_plugin_settings_t& pSettings, const std::string& pArgs) { - update_client(_("Creating a report...")); - - std::stringstream emailBody; - std::stringstream binaryFiles, commonFiles, bigTextFiles, additionalFiles, UUIDFile; - - AddMailxArg(MAILX_COMMAND); + char **args = NULL; + unsigned arg_size = 0; + args = append_str_to_vector(args, arg_size, MAILX_COMMAND); + std::string binaryFiles, commonFiles, bigTextFiles, additionalFiles, UUIDFile; map_crash_report_t::const_iterator it; for (it = pCrashReport.begin(); it != pCrashReport.end(); it++) { if (it->second[CD_TYPE] == CD_TXT) { - if (it->first != CD_UUID && - it->first != FILENAME_ARCHITECTURE && - it->first != FILENAME_KERNEL && - it->first != FILENAME_PACKAGE) - { - additionalFiles << it->first << std::endl; - additionalFiles << "-----" << std::endl; - additionalFiles << it->second[CD_CONTENT] << std::endl << std::endl; + if (it->first != CD_UUID + && it->first != FILENAME_ARCHITECTURE + && it->first != FILENAME_KERNEL + && it->first != FILENAME_PACKAGE + ) { + additionalFiles += it->first; + additionalFiles += "\n-----\n"; + additionalFiles += it->second[CD_CONTENT]; + additionalFiles += "\n\n"; } else if (it->first == CD_UUID) { - UUIDFile << it->first << std::endl; - UUIDFile << "-----" << std::endl; - UUIDFile << it->second[CD_CONTENT] << std::endl << std::endl; + UUIDFile += it->first; + UUIDFile += "\n-----\n"; + UUIDFile += it->second[CD_CONTENT]; + UUIDFile += "\n\n"; } else { - commonFiles << it->first << std::endl; - commonFiles << "-----" << std::endl; - commonFiles << it->second[CD_CONTENT] << std::endl << std::endl; + commonFiles += it->first; + commonFiles += "\n-----\n"; + commonFiles += it->second[CD_CONTENT]; + commonFiles += "\n\n"; } } if (it->second[CD_TYPE] == CD_ATT) { - bigTextFiles << it->first << std::endl; - bigTextFiles << "-----" << std::endl; - bigTextFiles << it->second[CD_CONTENT] << std::endl << std::endl; + bigTextFiles += it->first; + bigTextFiles += "\n-----\n"; + bigTextFiles += it->second[CD_CONTENT]; + bigTextFiles += "\n\n"; } if (it->second[CD_TYPE] == CD_BIN) { - binaryFiles << " -a " << it->second[CD_CONTENT]; + binaryFiles += " -a "; + binaryFiles += it->second[CD_CONTENT]; if (m_bSendBinaryData) { - AddMailxArg("-a"); - AddMailxArg(it->second[CD_CONTENT]); + args = append_str_to_vector(args, arg_size, "-a"); + args = append_str_to_vector(args, arg_size, it->second[CD_CONTENT].c_str()); } } } - emailBody << "Duplicity check" << std::endl; - emailBody << "=====" << std::endl << std::endl; - emailBody << UUIDFile.str() << std::endl; - emailBody << "Common information" << std::endl; - emailBody << "=====" << std::endl << std::endl; - emailBody << commonFiles.str() << std::endl; - emailBody << "Additional information" << std::endl; - emailBody << "=====" << std::endl << std::endl; - emailBody << additionalFiles.str() << std::endl; - emailBody << "Other information" << std::endl; - emailBody << "=====" << std::endl << std::endl; - emailBody << bigTextFiles.str() << std::endl; - - if (pArgs != "") - { - SendEmail(pArgs, emailBody.str(), pCrashReport.find(CD_MWUID)->second[CD_CONTENT]); - } - else + std::string emailBody = "Duplicity check\n"; + emailBody += "=====\n\n"; + emailBody += UUIDFile; + emailBody += "\nCommon information\n"; + emailBody += "=====\n\n"; + emailBody += commonFiles; + emailBody += "\nAdditional information\n"; + emailBody += "=====\n\n"; + emailBody += additionalFiles; + emailBody += "\nOther information\n"; + emailBody += "=====\n\n"; + emailBody += bigTextFiles; + emailBody += '\n'; + + args = append_str_to_vector(args, arg_size, "-s"); + args = append_str_to_vector(args, arg_size, (pArgs != "" ? pArgs.c_str() : m_sSubject.c_str())); + args = append_str_to_vector(args, arg_size, "-r"); + args = append_str_to_vector(args, arg_size, m_sEmailFrom.c_str()); + args = append_str_to_vector(args, arg_size, m_sEmailTo.c_str()); + + update_client(_("Sending an email...")); + const char *uid_str = pCrashReport.find(CD_MWUID)->second[CD_CONTENT].c_str(); + exec_and_feed_input(atoi(uid_str), emailBody.c_str(), args); + + while (*args) { - SendEmail(m_sSubject, emailBody.str(), pCrashReport.find(CD_MWUID)->second[CD_CONTENT]); + free(*args++); } - - FreeMailxArgs(); + args -= arg_size; + free(args); return "Email was sent to: " + m_sEmailTo; } @@ -242,7 +217,7 @@ PLUGIN_INFO(REPORTER, CMailx, "Mailx", "0.0.2", - "Sends an email with a report via mailx command", + "Sends an email with a report (via mailx command)", "zprikryl@redhat.com", "https://fedorahosted.org/abrt/wiki", PLUGINS_LIB_DIR"/Mailx.GTKBuilder"); diff --git a/lib/Plugins/Mailx.h b/lib/Plugins/Mailx.h index 4aa861f..d6d66bd 100644 --- a/lib/Plugins/Mailx.h +++ b/lib/Plugins/Mailx.h @@ -35,14 +35,6 @@ class CMailx : public CReporter std::string m_sSubject; bool m_bSendBinaryData; - int m_nArgs; - char** m_pArgs; - - void FreeMailxArgs(); - void AddMailxArg(const std::string& pArg); - void ExecMailx(uid_t uid, const std::string& pText); - void SendEmail(const std::string& pSubject, const std::string& pText, const std::string& pUID); - public: CMailx(); @@ -54,4 +46,4 @@ class CMailx : public CReporter const std::string& pArgs); }; -#endif /* MAILX_H_ */ +#endif diff --git a/lib/Plugins/Makefile.am b/lib/Plugins/Makefile.am index 0502f5e..9d80d91 100644 --- a/lib/Plugins/Makefile.am +++ b/lib/Plugins/Makefile.am @@ -15,6 +15,7 @@ pluginslib_LTLIBRARIES = \ libTicketUploader.la \ libPython.la \ libFileTransfer.la +# libFirefox.la dist_pluginslib_DATA = \ KerneloopsReporter.GTKBuilder Logger.GTKBuilder \ @@ -58,6 +59,17 @@ libCCpp_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils \ -DLOCALSTATEDIR='"$(localstatedir)"' \ $(NSS_CFLAGS) + +# Firefox - disabled for now +#libFirefox_la_SOURCES = Firefox.cpp Firefox.h +#libFirefox_la_LDFLAGS = -avoid-version +#libFirefox_la_LIBADD = $(NSS_LIBS) +#libFirefox_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils \ +# -DCCPP_HOOK_PATH=\"${libexecdir}/hookCCpp\" \ +# -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ +# -DLOCALSTATEDIR='"$(localstatedir)"' \ +# $(NSS_CFLAGS) + # Kerneloops libKerneloops_la_SOURCES = Kerneloops.cpp Kerneloops.h libKerneloops_la_LDFLAGS = -avoid-version diff --git a/lib/Plugins/Python.cpp b/lib/Plugins/Python.cpp index 9fb7880..a5e9909 100644 --- a/lib/Plugins/Python.cpp +++ b/lib/Plugins/Python.cpp @@ -51,7 +51,7 @@ PLUGIN_INFO(ANALYZER, CAnalyzerPython, "Python", "0.0.1", - "Simple Python analyzer plugin.", + "Analyzes crashes in Python programs", "zprikryl@redhat.com, jmoskovc@redhat.com", "https://fedorahosted.org/abrt/wiki", ""); diff --git a/lib/Plugins/RunApp.cpp b/lib/Plugins/RunApp.cpp index e525d89..f7cbc01 100644 --- a/lib/Plugins/RunApp.cpp +++ b/lib/Plugins/RunApp.cpp @@ -21,7 +21,6 @@ #include "RunApp.h" -#include <stdio.h> #include "DebugDump.h" #include "ABRTException.h" #include "CommLayerInner.h" @@ -30,28 +29,49 @@ #define COMMAND 0 #define FILENAME 1 +using namespace std; + void CActionRunApp::Run(const char *pActionDir, const char *pArgs) { - update_client(_("Executing RunApp plugin...")); + /* Don't update_client() - actions run at crash time */ + log("RunApp('%s','%s')", pActionDir, pArgs); - std::string output; vector_string_t args; - parse_args(pArgs, args, '"'); - FILE *fp = popen(args[COMMAND].c_str(), "r"); + const char *cmd = args[COMMAND].c_str(); + if (!cmd[0]) + { + return; + } + +//FIXME: need to be able to escape " in .conf + /* Chdir to the dump dir. Command can analyze component and such. + * Example: + * test x"`cat component`" = x"xorg-x11-apps" && cp /var/log/Xorg.0.log . + */ +//Can do it using chdir() in child if we'd open-code popen + string cd_and_cmd = ssprintf("cd '%s'; %s", pActionDir, cmd); + VERB1 log("RunApp: executing '%s'", cd_and_cmd.c_str()); + FILE *fp = popen(cd_and_cmd.c_str(), "r"); if (fp == NULL) { - throw CABRTException(EXCEP_PLUGIN, "Can't execute " + args[COMMAND]); + /* Happens only on resource starvation (fork fails or out-of-mem) */ + return; } + +//FIXME: RunApp("gzip -9 </var/log/Xorg.0.log", "Xorg.0.log.gz") fails +//since we mangle NULs. + string output; char line[1024]; while (fgets(line, 1024, fp) != NULL) { - output += line; + if (args.size() > FILENAME) + output += line; } pclose(fp); - if (args.size() > 1) + if (args.size() > FILENAME) { CDebugDump dd; dd.Open(pActionDir); @@ -63,8 +83,7 @@ PLUGIN_INFO(ACTION, CActionRunApp, "RunApp", "0.0.1", - "Simple action plugin which runs a command " - "and it can save command's output", + "Runs a command, saves its output", "zprikryl@redhat.com", "https://fedorahosted.org/abrt/wiki", ""); diff --git a/lib/Plugins/SOSreport.cpp b/lib/Plugins/SOSreport.cpp index 287c01e..65d01a7 100644 --- a/lib/Plugins/SOSreport.cpp +++ b/lib/Plugins/SOSreport.cpp @@ -116,7 +116,7 @@ PLUGIN_INFO(ACTION, CActionSOSreport, "SOSreport", "0.0.2", - "Run sosreport, save the output in the crash dump", + "Runs sosreport, saves the output", "gavin@redhat.com", "https://fedorahosted.org/abrt/wiki", ""); diff --git a/lib/Plugins/SQLite3.cpp b/lib/Plugins/SQLite3.cpp index 3aad054..cc639da 100644 --- a/lib/Plugins/SQLite3.cpp +++ b/lib/Plugins/SQLite3.cpp @@ -34,7 +34,7 @@ // after a while, we can drop support for update, so a table can stay in // normal limits -static const char* upate_sql_commands[][ABRT_TABLE_VERSION + 1] = { +static const char *const upate_sql_commands[][ABRT_TABLE_VERSION + 1] = { // v0 -> * { // v0 -> v0 @@ -421,7 +421,7 @@ PLUGIN_INFO(DATABASE, CSQLite3, "SQLite3", "0.0.2", - "SQLite3 database plugin.", + "Keeps SQLite3 database about all crashes", "zprikryl@redhat.com,jmoskovc@redhat.com", "https://fedorahosted.org/abrt/wiki", ""); diff --git a/lib/Plugins/TicketUploader.cpp b/lib/Plugins/TicketUploader.cpp index 76bda40..847efdc 100644 --- a/lib/Plugins/TicketUploader.cpp +++ b/lib/Plugins/TicketUploader.cpp @@ -295,28 +295,47 @@ string CTicketUploader::Report(const map_crash_report_t& pCrashReport, } // generate a reciept telling md5sum and encryption key - ostringstream msgbuf; + // note: do not internationalize these strings! + string msg; if (have_ticket_name) - msgbuf << _("Please copy this into ticket: ") << ticket_name << endl; + { + msg += "Please copy this into ticket: "; + msg += ticket_name; + msg += '\n'; + } else - msgbuf << _("Please send this to your technical support: ") << endl; + { + msg += "Please send this to your technical support:\n"; + } if (do_upload) - msgbuf << _("RHUPLOAD: This report was sent to ") + upload_url << endl; + { + msg += "RHUPLOAD: This report was sent to "; + msg += upload_url; + msg += '\n'; + } else - msgbuf << _("RHUPLOAD: This report was copied into /tmp/: ") << endl; + { + msg += "RHUPLOAD: This report was copied into /tmp/:\n"; + } if (have_ticket_name) - msgbuf << _("TICKET: ") << ticket_name << endl; - msgbuf << _("FILE: ") << outfile_basename << endl; - msgbuf << _("MD5SUM: ") << endl; - msgbuf << md5sum; + { + msg += "TICKET: "; + msg += ticket_name; + msg += '\n'; + } + msg += "FILE: "; + msg += outfile_basename; + msg += "\nMD5SUM:\n"; + msg += md5sum; if (do_encrypt) { - msgbuf << _("KEY: aes-128-cbc") << endl; - msgbuf << key; + msg += "KEY: aes-128-cbc\n"; + msg += key; } - msgbuf << _("END: ") << endl; + msg += "END:\n"; - error_msg("%s", msgbuf.str().c_str()); + /* warn the client: */ + error_msg("%s", msg.c_str()); string ret; if (do_upload) @@ -400,7 +419,7 @@ PLUGIN_INFO(REPORTER, CTicketUploader, "TicketUploader", "0.0.1", - "input ticket# and customer name from user, send report to FTP", + "Asks ticket# and customer name from user, sends report to FTP", "gavin@redhat.com", - "https://fedorahosted.org/abtr/wiki", + "https://fedorahosted.org/abrt/wiki", PLUGINS_LIB_DIR"/TicketUploader.GTKBuilder"); diff --git a/lib/Python/Makefile.am b/lib/Python/Makefile.am deleted file mode 100644 index dd9eeca..0000000 --- a/lib/Python/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -pyexec_LTLIBRARIES = ABRTUtils.la -ABRTUtils_la_SOURCES = PyDebugDump.cpp -ABRTUtils_la_LDFLAGS = -module -avoid-version -ABRTUtils_la_LIBADD = ../Utils/libABRTUtils.la -ABRTUtils_la_CPPFLAGS = -fPIC -shared `python-config --cflags` -I../Utils diff --git a/lib/Python/PyABRTUtils.cpp b/lib/Python/PyABRTUtils.cpp deleted file mode 100644 index e56ba07..0000000 --- a/lib/Python/PyABRTUtils.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* This file was generated by PyBindGen 0.10.0 */ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <stddef.h> - - -#if PY_VERSION_HEX < 0x020400F0 - -#define PyEval_ThreadsInitialized() 1 - -#define Py_CLEAR(op) \ - do { \ - if (op) { \ - PyObject *tmp = (PyObject *)(op); \ - (op) = NULL; \ - Py_DECREF(tmp); \ - } \ - } while (0) - - -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit((PyObject *)(op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) - -#endif - - - -#if PY_VERSION_HEX < 0x020500F0 - -typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -typedef inquiry lenfunc; -typedef intargfunc ssizeargfunc; -typedef intobjargproc ssizeobjargproc; - -#endif - - -#if __GNUC__ > 2 -# define PYBINDGEN_UNUSED(param) param __attribute__((__unused__)) -#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) -# define PYBINDGEN_UNUSED(param) __attribute__((__unused__)) param -#else -# define PYBINDGEN_UNUSED(param) -#endif /* !__GNUC__ */ - -#include "../Utils/DebugDump.h" -/* --- forward declarations --- */ - - -typedef struct { - PyObject_HEAD - CDebugDump *obj; -} PyCDebugDump; - - -extern PyTypeObject PyCDebugDump_Type; - -static PyMethodDef ABRTUtils_functions[] = { - {NULL, NULL, 0, NULL} -}; -/* --- classes --- */ - - - -static int -_wrap_PyCDebugDump__tp_init(PyCDebugDump *self, PyObject *args, PyObject *kwargs) -{ - const char *keywords[] = {NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "", (char **) keywords)) { - return -1; - } - self->obj = new CDebugDump(); - return 0; -} - - -PyObject * -_wrap_PyCDebugDump_Close(PyCDebugDump *self) -{ - PyObject *py_retval; - - self->obj->Close(); - Py_INCREF(Py_None); - py_retval = Py_None; - return py_retval; -} - - -PyObject * -_wrap_PyCDebugDump_Create(PyCDebugDump *self, PyObject *args, PyObject *kwargs) -{ - PyObject *py_retval; - char *pFilename2; - char *pUID2; - const char *keywords[] = {"pFilename", "pUID", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ss", (char **) keywords, &pFilename2, &pUID2)) { - return NULL; - } - self->obj->Create(pFilename2); - Py_INCREF(Py_None); - py_retval = Py_None; - return py_retval; -} - - -PyObject * -_wrap_PyCDebugDump_SaveText(PyCDebugDump *self, PyObject *args, PyObject *kwargs) -{ - PyObject *py_retval; - char *pName2; - char *pData2; - const char *keywords[] = {"pName", "pData", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ss", (char **) keywords, &pName2, &pData2)) { - return NULL; - } - self->obj->SaveText(pName2, pData2); - Py_INCREF(Py_None); - py_retval = Py_None; - return py_retval; -} - -static PyMethodDef PyCDebugDump_methods[] = { - {(char *) "Close", (PyCFunction) _wrap_PyCDebugDump_Close, METH_NOARGS, NULL }, - {(char *) "Create", (PyCFunction) _wrap_PyCDebugDump_Create, METH_KEYWORDS|METH_VARARGS, NULL }, - {(char *) "SaveText", (PyCFunction) _wrap_PyCDebugDump_SaveText, METH_KEYWORDS|METH_VARARGS, NULL }, - {NULL, NULL, 0, NULL} -}; - -static void -_wrap_PyCDebugDump__tp_dealloc(PyCDebugDump *self) -{ - CDebugDump *tmp = self->obj; - self->obj = NULL; - delete tmp; - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject* -_wrap_PyCDebugDump__tp_richcompare (PyCDebugDump *self, PyCDebugDump *other, int opid) -{ - - if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyCDebugDump_Type)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - switch (opid) - { - case Py_LT: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_LE: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_EQ: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_NE: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_GE: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_GT: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } /* closes switch (opid) */ - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -PyTypeObject PyCDebugDump_Type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - (char *) "ABRTUtils.CDebugDump", /* tp_name */ - sizeof(PyCDebugDump), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)_wrap_PyCDebugDump__tp_dealloc, /* tp_dealloc */ - (printfunc)0, /* tp_print */ - (getattrfunc)NULL, /* tp_getattr */ - (setattrfunc)NULL, /* tp_setattr */ - (cmpfunc)NULL, /* tp_compare */ - (reprfunc)NULL, /* tp_repr */ - (PyNumberMethods*)NULL, /* tp_as_number */ - (PySequenceMethods*)NULL, /* tp_as_sequence */ - (PyMappingMethods*)NULL, /* tp_as_mapping */ - (hashfunc)NULL, /* tp_hash */ - (ternaryfunc)NULL, /* tp_call */ - (reprfunc)NULL, /* tp_str */ - (getattrofunc)NULL, /* tp_getattro */ - (setattrofunc)NULL, /* tp_setattro */ - (PyBufferProcs*)NULL, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - NULL, /* Documentation string */ - (traverseproc)NULL, /* tp_traverse */ - (inquiry)NULL, /* tp_clear */ - (richcmpfunc)_wrap_PyCDebugDump__tp_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)NULL, /* tp_iter */ - (iternextfunc)NULL, /* tp_iternext */ - (struct PyMethodDef*)PyCDebugDump_methods, /* tp_methods */ - (struct PyMemberDef*)0, /* tp_members */ - 0, /* tp_getset */ - NULL, /* tp_base */ - NULL, /* tp_dict */ - (descrgetfunc)NULL, /* tp_descr_get */ - (descrsetfunc)NULL, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)_wrap_PyCDebugDump__tp_init, /* tp_init */ - (allocfunc)PyType_GenericAlloc, /* tp_alloc */ - (newfunc)PyType_GenericNew, /* tp_new */ - (freefunc)0, /* tp_free */ - (inquiry)NULL, /* tp_is_gc */ - NULL, /* tp_bases */ - NULL, /* tp_mro */ - NULL, /* tp_cache */ - NULL, /* tp_subclasses */ - NULL, /* tp_weaklist */ - (destructor) NULL /* tp_del */ -}; - - - -PyMODINIT_FUNC -initABRTUtils(void) -{ - PyObject *m; - m = Py_InitModule3((char *) "ABRTUtils", ABRTUtils_functions, NULL); - if (m == NULL) { - return; - } - /* Register the 'CDebugDump' class */ - if (PyType_Ready(&PyCDebugDump_Type)) { - return; - } - PyModule_AddObject(m, (char *) "CDebugDump", (PyObject *) &PyCDebugDump_Type); -} diff --git a/lib/Python/PyBindingGenerator.py b/lib/Python/PyBindingGenerator.py deleted file mode 100644 index a2d62d5..0000000 --- a/lib/Python/PyBindingGenerator.py +++ /dev/null @@ -1,27 +0,0 @@ -from pybindgen import * -import sys -""" - void Open(const std::string& pDir); - void Create(const std::string& pDir); - void Delete(); - void Close(); - - bool Exist(const std::string& pFileName); - - void LoadText(const std::string& pName, std::string& pData); - void LoadBinary(const std::string& pName, char** pData, unsigned int* pSize); - - void SaveText(const std::string& pName, const std::string& pData); - void SaveBinary(const std::string& pName, const char* pData, const unsigned int pSize); - - void InitGetNextFile(); - bool GetNextFile(std::string& pFileName, std::string& pContent, bool& pIsTextFile); -""" -mod = Module('ABRTUtils') -mod.add_include('"../Utils/DebugDump.h"') -klass = mod.add_class('CDebugDump') -klass.add_constructor([]) -klass.add_method('Create', None, [param('char*', 'pFilename')]) -klass.add_method('Close', None, []) -klass.add_method('SaveText', None, [param('char*', 'pName'), param('char*', 'pData')]) -mod.generate(sys.stdout) diff --git a/lib/Python/PyDebugDump.cpp b/lib/Python/PyDebugDump.cpp deleted file mode 100644 index 0f6de47..0000000 --- a/lib/Python/PyDebugDump.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* This file was generated by PyBindGen 0.10.0 */ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <stddef.h> - - -#if PY_VERSION_HEX < 0x020400F0 - -#define PyEval_ThreadsInitialized() 1 - -#define Py_CLEAR(op) \ - do { \ - if (op) { \ - PyObject *tmp = (PyObject *)(op); \ - (op) = NULL; \ - Py_DECREF(tmp); \ - } \ - } while (0) - - -#define Py_VISIT(op) \ - do { \ - if (op) { \ - int vret = visit((PyObject *)(op), arg); \ - if (vret) \ - return vret; \ - } \ - } while (0) - -#endif - - - -#if PY_VERSION_HEX < 0x020500F0 - -typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -typedef inquiry lenfunc; -typedef intargfunc ssizeargfunc; -typedef intobjargproc ssizeobjargproc; - -#endif - - -#if __GNUC__ > 2 -# define PYBINDGEN_UNUSED(param) param __attribute__((__unused__)) -#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) -# define PYBINDGEN_UNUSED(param) __attribute__((__unused__)) param -#else -# define PYBINDGEN_UNUSED(param) -#endif /* !__GNUC__ */ - -#include "../Utils/DebugDump.h" -/* --- forward declarations --- */ - - -typedef struct { - PyObject_HEAD - CDebugDump *obj; -} PyCDebugDump; - - -extern PyTypeObject PyCDebugDump_Type; - -static PyMethodDef ABRTUtils_functions[] = { - {NULL, NULL, 0, NULL} -}; -/* --- classes --- */ - - - -static int -_wrap_PyCDebugDump__tp_init(PyCDebugDump *self, PyObject *args, PyObject *kwargs) -{ - static const char *const keywords[] = {NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "", (char **) keywords)) { - return -1; - } - self->obj = new CDebugDump(); - return 0; -} - - -PyObject * -_wrap_PyCDebugDump_Close(PyCDebugDump *self) -{ - PyObject *py_retval; - - self->obj->Close(); - Py_INCREF(Py_None); - py_retval = Py_None; - return py_retval; -} - - -PyObject * -_wrap_PyCDebugDump_Create(PyCDebugDump *self, PyObject *args, PyObject *kwargs) -{ - PyObject *py_retval; - char *pFilename2; - int pUID2; - static const char *const keywords[] = {"pFilename", "pUID", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "si", (char **) keywords, &pFilename2, &pUID2)) { - return NULL; - } - self->obj->Create(pFilename2, pUID2); - Py_INCREF(Py_None); - py_retval = Py_None; - return py_retval; -} - - -PyObject * -_wrap_PyCDebugDump_SaveText(PyCDebugDump *self, PyObject *args, PyObject *kwargs) -{ - PyObject *py_retval; - char *pName2; - char *pData2; - static const char *const keywords[] = {"pName", "pData", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *) "ss", (char **) keywords, &pName2, &pData2)) { - return NULL; - } - self->obj->SaveText(pName2, pData2); - Py_INCREF(Py_None); - py_retval = Py_None; - return py_retval; -} - -static PyMethodDef PyCDebugDump_methods[] = { - {(char *) "Close", (PyCFunction) _wrap_PyCDebugDump_Close, METH_NOARGS, NULL }, - {(char *) "Create", (PyCFunction) _wrap_PyCDebugDump_Create, METH_KEYWORDS|METH_VARARGS, NULL }, - {(char *) "SaveText", (PyCFunction) _wrap_PyCDebugDump_SaveText, METH_KEYWORDS|METH_VARARGS, NULL }, - {NULL, NULL, 0, NULL} -}; - -static void -_wrap_PyCDebugDump__tp_dealloc(PyCDebugDump *self) -{ - CDebugDump *tmp = self->obj; - self->obj = NULL; - delete tmp; - self->ob_type->tp_free((PyObject*)self); -} - -static PyObject* -_wrap_PyCDebugDump__tp_richcompare (PyCDebugDump *self, PyCDebugDump *other, int opid) -{ - - if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &PyCDebugDump_Type)) { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - switch (opid) - { - case Py_LT: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_LE: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_EQ: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_NE: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_GE: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - case Py_GT: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } /* closes switch (opid) */ - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -PyTypeObject PyCDebugDump_Type = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - (char *) "ABRTUtils.CDebugDump", /* tp_name */ - sizeof(PyCDebugDump), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)_wrap_PyCDebugDump__tp_dealloc, /* tp_dealloc */ - (printfunc)0, /* tp_print */ - (getattrfunc)NULL, /* tp_getattr */ - (setattrfunc)NULL, /* tp_setattr */ - (cmpfunc)NULL, /* tp_compare */ - (reprfunc)NULL, /* tp_repr */ - (PyNumberMethods*)NULL, /* tp_as_number */ - (PySequenceMethods*)NULL, /* tp_as_sequence */ - (PyMappingMethods*)NULL, /* tp_as_mapping */ - (hashfunc)NULL, /* tp_hash */ - (ternaryfunc)NULL, /* tp_call */ - (reprfunc)NULL, /* tp_str */ - (getattrofunc)NULL, /* tp_getattro */ - (setattrofunc)NULL, /* tp_setattro */ - (PyBufferProcs*)NULL, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - NULL, /* Documentation string */ - (traverseproc)NULL, /* tp_traverse */ - (inquiry)NULL, /* tp_clear */ - (richcmpfunc)_wrap_PyCDebugDump__tp_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)NULL, /* tp_iter */ - (iternextfunc)NULL, /* tp_iternext */ - (struct PyMethodDef*)PyCDebugDump_methods, /* tp_methods */ - (struct PyMemberDef*)0, /* tp_members */ - 0, /* tp_getset */ - NULL, /* tp_base */ - NULL, /* tp_dict */ - (descrgetfunc)NULL, /* tp_descr_get */ - (descrsetfunc)NULL, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)_wrap_PyCDebugDump__tp_init, /* tp_init */ - (allocfunc)PyType_GenericAlloc, /* tp_alloc */ - (newfunc)PyType_GenericNew, /* tp_new */ - (freefunc)0, /* tp_free */ - (inquiry)NULL, /* tp_is_gc */ - NULL, /* tp_bases */ - NULL, /* tp_mro */ - NULL, /* tp_cache */ - NULL, /* tp_subclasses */ - NULL, /* tp_weaklist */ - (destructor) NULL /* tp_del */ -}; - - - -PyMODINIT_FUNC -initABRTUtils(void) -{ - PyObject *m; - m = Py_InitModule3((char *) "ABRTUtils", ABRTUtils_functions, NULL); - if (m == NULL) { - return; - } - /* Register the 'CDebugDump' class */ - if (PyType_Ready(&PyCDebugDump_Type)) { - return; - } - PyModule_AddObject(m, (char *) "CDebugDump", (PyObject *) &PyCDebugDump_Type); -} diff --git a/lib/Utils/CommLayerInner.cpp b/lib/Utils/CommLayerInner.cpp index 307fe66..133e97d 100644 --- a/lib/Utils/CommLayerInner.cpp +++ b/lib/Utils/CommLayerInner.cpp @@ -72,7 +72,7 @@ void update_client(const char *fmt, ...) int used = vasprintf(&msg, fmt, p); va_end(p); if (used < 0) - return; + return; s_pObs->Status(msg, peer, key); } diff --git a/lib/Utils/DebugDump.cpp b/lib/Utils/DebugDump.cpp index ba11d96..2883d01 100644 --- a/lib/Utils/DebugDump.cpp +++ b/lib/Utils/DebugDump.cpp @@ -74,7 +74,7 @@ void CDebugDump::Open(const char *pDir) bool CDebugDump::Exist(const char* pPath) { - std::string fullPath = m_sDebugDumpDir + "/" + pPath; + std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pPath); return ExistFileDir(fullPath.c_str()); } @@ -433,7 +433,7 @@ void CDebugDump::LoadText(const char* pName, std::string& pData) { throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::LoadText(): DebugDump is not opened."); } - std::string fullPath = m_sDebugDumpDir + '/' + pName; + std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); LoadTextFile(fullPath.c_str(), pData); } @@ -443,7 +443,7 @@ void CDebugDump::SaveText(const char* pName, const char* pData) { throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::SaveText(): DebugDump is not opened."); } - std::string fullPath = m_sDebugDumpDir + "/" + pName; + std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); SaveBinaryFile(fullPath.c_str(), pData, strlen(pData)); } void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize) @@ -452,7 +452,7 @@ void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize { throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::SaveBinary(): DebugDump is not opened."); } - std::string fullPath = m_sDebugDumpDir + "/" + pName; + std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); SaveBinaryFile(fullPath.c_str(), pData, pSize); } diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am index f752992..eae4148 100644 --- a/lib/Utils/Makefile.am +++ b/lib/Utils/Makefile.am @@ -4,6 +4,7 @@ lib_LTLIBRARIES = libABRTUtils.la # time.cpp # xconnect.cpp +# removed: CrashTypesSocket.cpp libABRTUtils_la_SOURCES = \ stringops.cpp \ xfuncs.cpp \ @@ -14,7 +15,6 @@ libABRTUtils_la_SOURCES = \ skip_whitespace.cpp \ popen_and_save_output.cpp \ parse_release.cpp \ - CrashTypesSocket.cpp \ DebugDump.h DebugDump.cpp \ CommLayerInner.h CommLayerInner.cpp \ abrt_dbus.h abrt_dbus.cpp \ diff --git a/lib/Utils/make_descr.cpp b/lib/Utils/make_descr.cpp index 1352149..0c09614 100644 --- a/lib/Utils/make_descr.cpp +++ b/lib/Utils/make_descr.cpp @@ -75,7 +75,7 @@ string make_description_bz(const map_crash_report_t& pCrashReport) && filename != FILENAME_RELEASE && filename != CD_REPRODUCE && filename != CD_COMMENT - ) { + ) { add_content(was_multiline, description, filename.c_str(), content.c_str()); } } diff --git a/lib/Utils/stringops.cpp b/lib/Utils/stringops.cpp index 1b3793f..dc71b5b 100644 --- a/lib/Utils/stringops.cpp +++ b/lib/Utils/stringops.cpp @@ -3,24 +3,33 @@ void parse_args(const char *psArgs, vector_string_t& pArgs, int quote) { unsigned ii; - bool is_quote = false; + bool inside_quotes = false; std::string item; for (ii = 0; psArgs[ii]; ii++) { - if (quote != -1 && psArgs[ii] == quote) + if (quote != -1) { - is_quote = !is_quote; + if (psArgs[ii] == quote) + { + inside_quotes = !inside_quotes; + continue; + } + /* inside quotes we support escaping with \x */ + if (inside_quotes && psArgs[ii] == '\\' && psArgs[ii+1]) + { + ii++; + item += psArgs[ii]; + continue; + } } - else if (psArgs[ii] == ',' && !is_quote) + if (psArgs[ii] == ',' && !inside_quotes) { pArgs.push_back(item); item.clear(); + continue; } - else - { - item += psArgs[ii]; - } + item += psArgs[ii]; } if (item.size() != 0) |
