summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2009-11-09 13:55:20 +0100
committerKarel Klic <kklic@redhat.com>2009-11-09 13:55:20 +0100
commit19f406b4930c931a932dc6930762e8e12e29ce8b (patch)
treeb08468bf9a010cbce0ecd000a0279222f0d4b4e7 /lib
parent801ab58f32f2cb7dca3352b721a07c83705a0287 (diff)
parent8fa9a6ecd247454ab758efecf818d8067455c778 (diff)
downloadabrt-19f406b4930c931a932dc6930762e8e12e29ce8b.tar.gz
abrt-19f406b4930c931a932dc6930762e8e12e29ce8b.tar.xz
abrt-19f406b4930c931a932dc6930762e8e12e29ce8b.zip
merge
Diffstat (limited to 'lib')
-rw-r--r--lib/Plugins/Bugzilla.cpp839
-rw-r--r--lib/Plugins/Bugzilla.h32
-rw-r--r--lib/Plugins/CCpp.conf13
-rw-r--r--lib/Plugins/CCpp.cpp298
-rw-r--r--lib/Plugins/CCpp.h12
-rw-r--r--lib/Plugins/Catcut.GTKBuilder184
-rw-r--r--lib/Plugins/Catcut.conf8
-rw-r--r--lib/Plugins/Catcut.cpp368
-rw-r--r--lib/Plugins/Catcut.h27
-rw-r--r--lib/Plugins/FileTransfer.cpp157
-rw-r--r--lib/Plugins/FileTransfer.h12
-rw-r--r--lib/Plugins/Kerneloops.conf2
-rw-r--r--lib/Plugins/Kerneloops.cpp4
-rw-r--r--lib/Plugins/Kerneloops.h9
-rw-r--r--lib/Plugins/KerneloopsReporter.cpp29
-rw-r--r--lib/Plugins/KerneloopsReporter.h3
-rw-r--r--lib/Plugins/KerneloopsScanner.cpp72
-rw-r--r--lib/Plugins/KerneloopsScanner.h18
-rw-r--r--lib/Plugins/KerneloopsSysLog.cpp247
-rw-r--r--lib/Plugins/KerneloopsSysLog.h26
-rw-r--r--lib/Plugins/Logger.cpp93
-rw-r--r--lib/Plugins/Logger.h3
-rw-r--r--lib/Plugins/Mailx.cpp17
-rw-r--r--lib/Plugins/Mailx.h3
-rw-r--r--lib/Plugins/Makefile.am78
-rw-r--r--lib/Plugins/Python.cpp6
-rw-r--r--lib/Plugins/Python.h7
-rw-r--r--lib/Plugins/RunApp.cpp31
-rw-r--r--lib/Plugins/RunApp.h6
-rw-r--r--lib/Plugins/SOSreport.cpp91
-rw-r--r--lib/Plugins/SOSreport.h15
-rw-r--r--lib/Plugins/SQLite3.cpp36
-rw-r--r--lib/Plugins/SQLite3.h2
-rw-r--r--lib/Plugins/TicketUploader.cpp388
-rw-r--r--lib/Plugins/TicketUploader.h41
-rw-r--r--lib/Utils/Action.h6
-rw-r--r--lib/Utils/Analyzer.h6
-rw-r--r--lib/Utils/CommLayerInner.cpp57
-rw-r--r--lib/Utils/CommLayerInner.h16
-rw-r--r--lib/Utils/DBusCommon.h6
-rw-r--r--lib/Utils/DebugDump.cpp280
-rw-r--r--lib/Utils/DebugDump.h16
-rw-r--r--lib/Utils/Makefile.am9
-rw-r--r--lib/Utils/Observer.h4
-rw-r--r--lib/Utils/Plugin.cpp13
-rw-r--r--lib/Utils/Plugin.h27
-rw-r--r--lib/Utils/Reporter.h1
-rw-r--r--lib/Utils/copyfd.cpp22
-rw-r--r--lib/Utils/encbase64.cpp78
-rw-r--r--lib/Utils/logging.cpp46
-rw-r--r--lib/Utils/make_descr.cpp133
-rw-r--r--lib/Utils/skip_whitespace.cpp22
-rw-r--r--lib/Utils/time.cpp65
-rw-r--r--lib/Utils/xconnect.cpp416
-rw-r--r--lib/Utils/xfuncs.cpp63
55 files changed, 2943 insertions, 1520 deletions
diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp
index 48c5eb5..ecd4dd6 100644
--- a/lib/Plugins/Bugzilla.cpp
+++ b/lib/Plugins/Bugzilla.cpp
@@ -1,456 +1,590 @@
-
-#include <xmlrpc-c/base.hpp>
+#include <xmlrpc-c/base.h>
+#include <xmlrpc-c/client.h>
#include "abrtlib.h"
#include "Bugzilla.h"
#include "CrashTypes.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
+#ifdef HAVE_CONFIG_H
+ #include <config.h>
+#endif
#define XML_RPC_SUFFIX "/xmlrpc.cgi"
-CReporterBugzilla::CReporterBugzilla() :
- m_pXmlrpcTransport(NULL),
- m_pXmlrpcClient(NULL),
- m_pCarriageParm(NULL),
- m_sBugzillaURL("https://bugzilla.redhat.com"),
- m_sBugzillaXMLRPC("https://bugzilla.redhat.com" + std::string(XML_RPC_SUFFIX)),
- m_bNoSSLVerify(false),
- m_bLoggedIn(false)
-{}
-CReporterBugzilla::~CReporterBugzilla()
-{}
-
-void CReporterBugzilla::NewXMLRPCClient()
-{
- m_pXmlrpcTransport = new xmlrpc_c::clientXmlTransport_curl(
- xmlrpc_c::clientXmlTransport_curl::constrOpt()
- .no_ssl_verifyhost(m_bNoSSLVerify)
- .no_ssl_verifypeer(m_bNoSSLVerify)
- );
- m_pXmlrpcClient = new xmlrpc_c::client_xml(m_pXmlrpcTransport);
- m_pCarriageParm = new xmlrpc_c::carriageParm_curl0(m_sBugzillaXMLRPC);
-}
-
-void CReporterBugzilla::DeleteXMLRPCClient()
+static void get_product_and_version(const std::string& pRelease,
+ std::string& pProduct,
+ std::string& pVersion)
{
- if (m_pCarriageParm != NULL)
+ if (pRelease.find("Rawhide") != std::string::npos)
{
- delete m_pCarriageParm;
- m_pCarriageParm = NULL;
+ pProduct = "Fedora";
+ pVersion = "rawhide";
+ return;
}
- if (m_pXmlrpcClient != NULL)
+ if (pRelease.find("Fedora") != std::string::npos)
{
- delete m_pXmlrpcClient;
- m_pXmlrpcClient = NULL;
+ pProduct = "Fedora";
}
- if (m_pXmlrpcTransport != NULL)
+ else if (pRelease.find("Red Hat Enterprise Linux") != std::string::npos)
{
- delete m_pXmlrpcTransport;
- m_pXmlrpcTransport = NULL;
+ pProduct = "Red Hat Enterprise Linux ";
}
-}
-
-PRInt32 CReporterBugzilla::Base64Encode_cb(void *arg, const char *obuf, PRInt32 size)
-{
- CReporterBugzilla* bz = static_cast<CReporterBugzilla*>(arg);
- int ii;
- for (ii = 0; ii < size; ii++)
+ std::string::size_type pos = pRelease.find("release");
+ pos = pRelease.find(" ", pos) + 1;
+ while (pRelease[pos] != ' ')
{
- if (isprint(obuf[ii]))
+ pVersion += pRelease[pos];
+ if (pProduct == "Red Hat Enterprise Linux ")
{
- bz->m_sAttchmentInBase64 += obuf[ii];
+ pProduct += pRelease[pos];
}
+ pos++;
}
- return 1;
}
-void CReporterBugzilla::Login()
+static void create_new_bug_description(const map_crash_report_t& pCrashReport, std::string& pDescription)
{
- xmlrpc_c::paramList paramList;
- map_xmlrpc_params_t loginParams;
- map_xmlrpc_params_t ret;
- loginParams["login"] = xmlrpc_c::value_string(m_sLogin);
- loginParams["password"] = xmlrpc_c::value_string(m_sPassword);
- paramList.add(xmlrpc_c::value_struct(loginParams));
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("User.login", paramList));
- try
- {
- if( (m_sLogin == "") && (m_sPassword=="") )
- {
- log("Empty login and password");
- throw std::string(_("Empty login and password. Please check Bugzilla.conf"));
- }
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- ret = xmlrpc_c::value_struct(rpc->getResult());
- std::stringstream ss;
- ss << xmlrpc_c::value_int(ret["id"]);
- log("Login id: %s", ss.str().c_str());
- }
- catch (std::exception& e)
- {
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::Login(): ") + e.what());
- }
- catch (std::string& s)
- {
- throw CABRTException(EXCEP_PLUGIN, s);
- }
+ pDescription = "abrt detected a crash.\n\n";
+ pDescription += make_description_bz(pCrashReport);
}
-void CReporterBugzilla::Logout()
+// FIXME: we still leak memory if this function detects a fault:
+// many instances when we leave non-freed or non-xmlrpc_DECREF'ed data behind.
+static void throw_if_xml_fault_occurred(xmlrpc_env *env)
{
- xmlrpc_c::paramList paramList;
- paramList.add(xmlrpc_c::value_string(""));
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("User.logout", paramList));
- try
- {
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- }
- catch (std::exception& e)
+ if (env->fault_occurred)
{
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::Logout(): ") + e.what());
+ std::string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env->fault_string, env->fault_code);
+ xmlrpc_env_clean(env); // this is needed ONLY if fault_occurred
+ xmlrpc_env_init(env); // just in case user catches ex and _continues_ to use env
+ error_msg("%s", errmsg.c_str()); // show error in daemon log
+ throw CABRTException(EXCEP_PLUGIN, errmsg);
}
}
-bool CReporterBugzilla::CheckCCAndReporter(const std::string& pBugId)
+
+/*
+ * Static namespace for xmlrpc stuff.
+ * Used mainly to ensure we always destroy xmlrpc client and server_info.
+ */
+
+namespace {
+
+struct ctx {
+ xmlrpc_client* client;
+ xmlrpc_server_info* server_info;
+
+ ctx(const char* url, bool no_ssl_verify) { new_xmlrpc_client(url, no_ssl_verify); }
+ ~ctx() { destroy_xmlrpc_client(); }
+
+ void new_xmlrpc_client(const char* url, bool no_ssl_verify);
+ void destroy_xmlrpc_client();
+
+ void login(const char* login, const char* passwd);
+ void logout();
+ int32_t check_uuid_in_bugzilla(const char* component, const char* UUID);
+ bool check_cc_and_reporter(uint32_t bug_id, const char* login);
+ void add_plus_one_cc(uint32_t bug_id, const char* login);
+ uint32_t new_bug(const map_crash_report_t& pCrashReport);
+ void add_attachments(const char* bug_id_str, const map_crash_report_t& pCrashReport);
+};
+
+void ctx::new_xmlrpc_client(const char* url, bool no_ssl_verify)
{
- xmlrpc_c::paramList paramList;
- map_xmlrpc_params_t ret;
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ /* This should be done at program startup, once.
+ * We do it in abrtd's main */
+ /* xmlrpc_client_setup_global_const(&env); */
+
+ struct xmlrpc_curl_xportparms curlParms;
+ memset(&curlParms, 0, sizeof(curlParms));
+ /* curlParms.network_interface = NULL; - done by memset */
+ curlParms.no_ssl_verifypeer = no_ssl_verify;
+ curlParms.no_ssl_verifyhost = no_ssl_verify;
+#ifdef VERSION
+ curlParms.user_agent = PACKAGE_NAME"/"VERSION;
+#else
+ curlParms.user_agent = "abrt";
+#endif
+
+ struct xmlrpc_clientparms clientParms;
+ memset(&clientParms, 0, sizeof(clientParms));
+ clientParms.transport = "curl";
+ clientParms.transportparmsP = &curlParms;
+ clientParms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
+
+ client = NULL;
+ xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS,
+ PACKAGE_NAME, VERSION,
+ &clientParms, XMLRPC_CPSIZE(transportparm_size),
+ &client);
+ throw_if_xml_fault_occurred(&env);
+
+ server_info = xmlrpc_server_info_new(&env, url);
+ if (env.fault_occurred)
+ {
+ xmlrpc_client_destroy(client);
+ client = NULL;
+ }
+ throw_if_xml_fault_occurred(&env);
+}
- paramList.add(xmlrpc_c::value_string(pBugId));
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("bugzilla.getBug", paramList));
- try
- {
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- ret = xmlrpc_c::value_struct(rpc->getResult());
- }
- catch (std::exception& e)
+void ctx::destroy_xmlrpc_client()
+{
+ if (server_info)
{
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::CheckCCAndReporter(): ") + e.what());
+ xmlrpc_server_info_free(server_info);
+ server_info = NULL;
}
- std::string reporter = xmlrpc_c::value_string(ret["reporter"]);
- if (reporter == m_sLogin)
+ if (client)
{
- return true;
+ xmlrpc_client_destroy(client);
+ client = NULL;
}
- std::vector<xmlrpc_c::value> ccs = xmlrpc_c::value_array(ret["cc"]).vectorValueValue();
- int ii;
- for (ii = 0; ii < ccs.size(); ii++)
- {
- std::string cc = xmlrpc_c::value_string(ccs[ii]);
- if (cc == m_sLogin)
- {
- return true;
- }
- }
- return false;
}
-void CReporterBugzilla::AddPlusOneCC(const std::string& pBugId)
+void ctx::login(const char* login, const char* passwd)
{
- xmlrpc_c::paramList paramList;
- map_xmlrpc_params_t addCCParams;
- map_xmlrpc_params_t ret;
- map_xmlrpc_params_t updates;
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
- std::vector<xmlrpc_c::value> CCList;
- CCList.push_back(xmlrpc_c::value_string(m_sLogin));
- updates["add_cc"] = xmlrpc_c::value_array(CCList);
+ xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s,s:s})", "login", login, "password", passwd);
+ throw_if_xml_fault_occurred(&env);
- addCCParams["ids"] = xmlrpc_c::value_int(atoi(pBugId.c_str()));
- addCCParams["updates"] = xmlrpc_c::value_struct(updates);
+ xmlrpc_value* result = NULL;
+ xmlrpc_client_call2(&env, client, server_info, "User.login", param, &result);
+ xmlrpc_DECREF(param);
+ if (result)
+ xmlrpc_DECREF(result);
- paramList.add(xmlrpc_c::value_struct(addCCParams));
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("Bug.update", paramList));
- try
- {
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- }
- catch (std::exception& e)
+ if (env.fault_occurred)
{
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::AddPlusOneComment(): ") + e.what());
+ std::string errmsg = ssprintf("Can't login. Check Edit->Plugins->Bugzilla and /etc/abrt/plugins/Bugzilla.conf. Server said: %s", env.fault_string);
+ xmlrpc_env_clean(&env);
+ error_msg("%s", errmsg.c_str()); // show error in daemon log
+ throw CABRTException(EXCEP_PLUGIN, errmsg);
}
- ret = xmlrpc_c::value_struct(rpc->getResult());
}
-std::string CReporterBugzilla::CheckUUIDInBugzilla(const std::string& pComponent, const std::string& pUUID)
+void ctx::logout()
{
- xmlrpc_c::paramList paramList;
- map_xmlrpc_params_t searchParams;
- map_xmlrpc_params_t ret;
- std::string quicksearch = "ALL component:\""+ pComponent +"\" statuswhiteboard:\""+ pUUID + "\"";
- searchParams["quicksearch"] = xmlrpc_c::value_string(quicksearch.c_str());
- paramList.add(xmlrpc_c::value_struct(searchParams));
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("Bug.search", paramList));
- try
- {
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- }
- catch (std::exception& e)
- {
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::CheckUUIDInBugzilla(): ") + e.what());
- }
- ret = xmlrpc_c::value_struct(rpc->getResult());
- std::vector<xmlrpc_c::value> bugs = xmlrpc_c::value_array(ret["bugs"]).vectorValueValue();
- if (bugs.size() > 0)
- {
- map_xmlrpc_params_t bug;
- std::stringstream ss;
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", "");
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* result = NULL;
+ xmlrpc_client_call2(&env, client, server_info, "User.logout", param, &result);
+ xmlrpc_DECREF(param);
+ if (result)
+ xmlrpc_DECREF(result);
+ throw_if_xml_fault_occurred(&env);
+}
- bug = xmlrpc_c::value_struct(bugs[0]);
- ss << xmlrpc_c::value_int(bug["bug_id"]);
+bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
- log("Bug is already reported: %s", ss.str().c_str());
- update_client(_("Bug is already reported: ") + ss.str());
+ xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", to_string(bug_id).c_str());
+ throw_if_xml_fault_occurred(&env);
- return ss.str();
- }
- return "";
-}
+ xmlrpc_value* result = NULL;
+ xmlrpc_client_call2(&env, client, server_info, "bugzilla.getBug", param, &result);
+ throw_if_xml_fault_occurred(&env);
+ xmlrpc_DECREF(param);
-void CReporterBugzilla::CreateNewBugDescription(const map_crash_report_t& pCrashReport, std::string& pDescription)
-{
- std::string howToReproduce;
- std::string comment;
+ xmlrpc_value* reporter_member = NULL;
+ xmlrpc_struct_find_value(&env, result, "reporter", &reporter_member);
+ throw_if_xml_fault_occurred(&env);
- if (pCrashReport.find(CD_REPRODUCE) != pCrashReport.end())
+ if (reporter_member)
{
- howToReproduce = "\n\nHow to reproduce\n"
- "-----\n" +
- pCrashReport.find(CD_REPRODUCE)->second[CD_CONTENT];
- }
- if (pCrashReport.find(CD_COMMENT) != pCrashReport.end())
- {
- comment = "\n\nComment\n"
- "-----\n" +
- pCrashReport.find(CD_COMMENT)->second[CD_CONTENT];
+ const char* reporter = NULL;
+ xmlrpc_read_string(&env, reporter_member, &reporter);
+ throw_if_xml_fault_occurred(&env);
+
+ bool eq = (strcmp(reporter, login) == 0);
+ free((void*)reporter);
+ xmlrpc_DECREF(reporter_member);
+ if (eq)
+ {
+ xmlrpc_DECREF(result);
+ return true;
+ }
}
- pDescription = "\nabrt detected a crash.\n" +
- howToReproduce +
- comment +
- "\n\nAdditional information\n"
- "======\n";
-
- map_crash_report_t::const_iterator it;
- for (it = pCrashReport.begin(); it != pCrashReport.end(); it++)
+
+ xmlrpc_value* cc_member = NULL;
+ xmlrpc_struct_find_value(&env, result, "cc", &cc_member);
+ throw_if_xml_fault_occurred(&env);
+
+ if (cc_member)
{
- if (it->second[CD_TYPE] == CD_TXT)
+ uint32_t array_size = xmlrpc_array_size(&env, cc_member);
+
+ for (uint32_t i = 0; i < array_size; i++)
{
- if (it->first != CD_UUID &&
- it->first != FILENAME_ARCHITECTURE &&
- it->first != FILENAME_RELEASE &&
- it->first != CD_REPRODUCE &&
- it->first != CD_COMMENT)
+ xmlrpc_value* item = NULL;
+ xmlrpc_array_read_item(&env, cc_member, i, &item); // Correct
+ throw_if_xml_fault_occurred(&env);
+
+ const char* cc = NULL;
+ xmlrpc_read_string(&env, item, &cc);
+ throw_if_xml_fault_occurred(&env);
+
+ bool eq = (strcmp(cc, login) == 0);
+ free((void*)cc);
+ xmlrpc_DECREF(item);
+ if (eq)
{
- pDescription += "\n" + it->first + "\n";
- pDescription += "-----\n";
- pDescription += it->second[CD_CONTENT] + "\n\n";
+ xmlrpc_DECREF(cc_member);
+ xmlrpc_DECREF(result);
+ return true;
}
}
- else if (it->second[CD_TYPE] == CD_ATT)
- {
- pDescription += "\n\nAttached files\n"
- "----\n";
- pDescription += it->first + "\n";
- }
- else if (it->second[CD_TYPE] == CD_BIN)
- {
- char buffer[1024];
- snprintf(buffer, 1024, _("Binary file %s will not be reported."), it->first.c_str());
- warn_client(std::string(buffer));
- //update_client(_("Binary file ")+it->first+_(" will not be reported."));
- }
+ xmlrpc_DECREF(cc_member);
}
+
+ xmlrpc_DECREF(result);
+ return false;
}
-void CReporterBugzilla::GetProductAndVersion(const std::string& pRelease,
- std::string& pProduct,
- std::string& pVersion)
+void ctx::add_plus_one_cc(uint32_t bug_id, const char* login)
{
- if (pRelease.find("Rawhide") != std::string::npos)
- {
- pProduct = "Fedora";
- pVersion = "rawhide";
- return;
- }
- if (pRelease.find("Fedora") != std::string::npos)
- {
- pProduct = "Fedora";
- }
- else if (pRelease.find("Red Hat Enterprise Linux") != std::string::npos)
- {
- pProduct = "Red Hat Enterprise Linux ";
- }
- std::string::size_type pos = pRelease.find("release");
- pos = pRelease.find(" ", pos) + 1;
- while (pRelease[pos] != ' ')
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value* param = xmlrpc_build_value(&env, "({s:i,s:{s:(s)}})", "ids", bug_id, "updates", "add_cc", login);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* result = NULL;
+ xmlrpc_client_call2(&env, client, server_info, "Bug.update", param, &result);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_DECREF(result);
+ xmlrpc_DECREF(param);
+}
+
+int32_t ctx::check_uuid_in_bugzilla(const char* component, const char* UUID)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ std::string query = ssprintf("ALL component:\"%s\" statuswhiteboard:\"%s\"", component, UUID);
+
+ xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s})", "quicksearch", query.c_str());
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* result = NULL;
+ xmlrpc_client_call2(&env, client, server_info, "Bug.search", param, &result);
+ throw_if_xml_fault_occurred(&env);
+ xmlrpc_DECREF(param);
+
+ xmlrpc_value* bugs_member = NULL;
+ xmlrpc_struct_find_value(&env, result, "bugs", &bugs_member);
+ throw_if_xml_fault_occurred(&env);
+
+ if (bugs_member)
{
- pVersion += pRelease[pos];
- if (pProduct == "Red Hat Enterprise Linux ")
+ // when array size is equal 0 that means no bug reported
+ uint32_t array_size = xmlrpc_array_size(&env, bugs_member);
+ throw_if_xml_fault_occurred(&env);
+ if (array_size == 0)
{
- pProduct += pRelease[pos];
+ xmlrpc_DECREF(bugs_member);
+ xmlrpc_DECREF(result);
+ return -1;
}
- pos++;
+
+ xmlrpc_value* item = NULL;
+ xmlrpc_array_read_item(&env, bugs_member, 0, &item); // Correct
+ throw_if_xml_fault_occurred(&env);
+ xmlrpc_value* bug = NULL;
+ xmlrpc_struct_find_value(&env, item, "bug_id", &bug);
+ throw_if_xml_fault_occurred(&env);
+
+ if (bug)
+ {
+ xmlrpc_int bug_id;
+ xmlrpc_read_int(&env, bug, &bug_id);
+ log("Bug is already reported: %i", (int)bug_id);
+ update_client(_("Bug is already reported: %i"), (int)bug_id);
+
+ xmlrpc_DECREF(bug);
+ xmlrpc_DECREF(item);
+ xmlrpc_DECREF(bugs_member);
+ xmlrpc_DECREF(result);
+ return bug_id;
+ }
+ xmlrpc_DECREF(item);
+ xmlrpc_DECREF(bugs_member);
}
+
+ xmlrpc_DECREF(result);
+ return -1;
}
-std::string CReporterBugzilla::NewBug(const map_crash_report_t& pCrashReport)
+uint32_t ctx::new_bug(const map_crash_report_t& pCrashReport)
{
- xmlrpc_c::paramList paramList;
- map_xmlrpc_params_t bugParams;
- map_xmlrpc_params_t ret;
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
std::string package = pCrashReport.find(FILENAME_PACKAGE)->second[CD_CONTENT];
std::string component = pCrashReport.find(FILENAME_COMPONENT)->second[CD_CONTENT];
+ std::string release = pCrashReport.find(FILENAME_RELEASE)->second[CD_CONTENT];
+ std::string arch = pCrashReport.find(FILENAME_ARCHITECTURE)->second[CD_CONTENT];
+ std::string uuid = pCrashReport.find(CD_UUID)->second[CD_CONTENT];
+
+ std::string summary = "[abrt] crash detected in " + package;
+ std::string status_whiteboard = "abrt_hash:" + uuid;
+
std::string description;
- std::string release = pCrashReport.find(FILENAME_RELEASE)->second[CD_CONTENT];;
+ create_new_bug_description(pCrashReport, description);
+
std::string product;
std::string version;
- std::stringstream bugId;
- CreateNewBugDescription(pCrashReport, description);
- GetProductAndVersion(release, product, version);
-
- bugParams["product"] = xmlrpc_c::value_string(product);
- bugParams["component"] = xmlrpc_c::value_string(component);
- bugParams["version"] = xmlrpc_c::value_string(version);
- //bugParams["op_sys"] = xmlrpc_c::value_string("Linux");
- bugParams["summary"] = xmlrpc_c::value_string("[abrt] crash detected in " + package);
- bugParams["description"] = xmlrpc_c::value_string(description);
- bugParams["status_whiteboard"] = xmlrpc_c::value_string("abrt_hash:" + pCrashReport.find(CD_UUID)->second[CD_CONTENT]);
- bugParams["platform"] = xmlrpc_c::value_string(pCrashReport.find(FILENAME_ARCHITECTURE)->second[CD_CONTENT]);
- paramList.add(xmlrpc_c::value_struct(bugParams));
-
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("Bug.create", paramList));
- try
- {
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- ret = xmlrpc_c::value_struct(rpc->getResult());
- bugId << xmlrpc_c::value_int(ret["id"]);
- log("New bug id: %s", bugId.str().c_str());
- update_client(_("New bug id: ") + bugId.str());
- }
- catch (std::exception& e)
- {
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::NewBug(): ") + e.what());
- }
- return bugId.str();
+ get_product_and_version(release, product, version);
+
+ xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
+ "product", product.c_str(),
+ "component", component.c_str(),
+ "version", version.c_str(),
+ "summary", summary.c_str(),
+ "description", description.c_str(),
+ "status_whiteboard", status_whiteboard.c_str(),
+ "platform", arch.c_str()
+ );
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* result;
+ xmlrpc_client_call2(&env, client, server_info, "Bug.create", param, &result);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* id;
+ xmlrpc_struct_find_value(&env, result, "id", &id);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_int bug_id = -1;
+ if (id)
+ {
+ xmlrpc_read_int(&env, id, &bug_id);
+ throw_if_xml_fault_occurred(&env);
+ log("New bug id: %i", bug_id);
+ update_client(_("New bug id: %i"), bug_id);
+ }
+
+ xmlrpc_DECREF(result);
+ xmlrpc_DECREF(param);
+ xmlrpc_DECREF(id);
+ return bug_id;
}
-void CReporterBugzilla::AddAttachments(const std::string& pBugId, const map_crash_report_t& pCrashReport)
+void ctx::add_attachments(const char* bug_id_str, const map_crash_report_t& pCrashReport)
{
- xmlrpc_c::paramList paramList;
- map_xmlrpc_params_t attachmentParams;
- std::vector<xmlrpc_c::value> ret;
- NSSBase64Encoder* base64;
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
- map_crash_report_t::const_iterator it;
- for (it = pCrashReport.begin(); it != pCrashReport.end(); it++)
+ xmlrpc_value* result = NULL;
+
+ map_crash_report_t::const_iterator it = pCrashReport.begin();
+ for (; it != pCrashReport.end(); it++)
{
if (it->second[CD_TYPE] == CD_ATT)
{
- m_sAttchmentInBase64 = "";
- base64 = NSSBase64Encoder_Create(Base64Encode_cb, this);
- if (!base64)
- {
- throw CABRTException(EXCEP_PLUGIN, "CReporterBugzilla::AddAttachemnt(): cannot initialize base64.");
- }
-
- NSSBase64Encoder_Update(base64,
- reinterpret_cast<const unsigned char*>(it->second[CD_CONTENT].c_str()),
- it->second[CD_CONTENT].length());
- NSSBase64Encoder_Destroy(base64, PR_FALSE);
-
- paramList.add(xmlrpc_c::value_string(pBugId));
- attachmentParams["description"] = xmlrpc_c::value_string("File: " + it->first);
- attachmentParams["filename"] = xmlrpc_c::value_string(it->first);
- attachmentParams["contenttype"] = xmlrpc_c::value_string("text/plain");
- attachmentParams["data"] = xmlrpc_c::value_string(m_sAttchmentInBase64);
- paramList.add(xmlrpc_c::value_struct(attachmentParams));
- xmlrpc_c::rpcPtr rpc(new xmlrpc_c::rpc("bugzilla.addAttachment", paramList));
- try
- {
- rpc->call(m_pXmlrpcClient, m_pCarriageParm);
- ret = xmlrpc_c::value_array(rpc->getResult()).vectorValueValue();
- std::stringstream ss;
- ss << xmlrpc_c::value_int(ret[0]);
- log("New attachment id: %s", ss.str().c_str());
- }
- catch (std::exception& e)
- {
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::AddAttachemnt(): ") + e.what());
- }
+ std::string description = "File: " + it->first;
+ const std::string& to_encode = it->second[CD_CONTENT];
+ char *encoded64 = encode_base64(to_encode.c_str(), to_encode.length());
+ xmlrpc_value* param = xmlrpc_build_value(&env,"(s{s:s,s:s,s:s,s:s})",
+ bug_id_str,
+ "description", description.c_str(),
+ "filename", it->first.c_str(),
+ "contenttype", "text/plain",
+ "data", encoded64
+ );
+ free(encoded64);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_client_call2(&env, client, server_info, "bugzilla.addAttachment", param, &result);
+ throw_if_xml_fault_occurred(&env);
+ xmlrpc_DECREF(result);
+ xmlrpc_DECREF(param);
}
}
}
-std::string CReporterBugzilla::Report(const map_crash_report_t& pCrashReport, const std::string& pArgs)
-{
- std::string package = pCrashReport.find(FILENAME_PACKAGE)->second[CD_CONTENT];
- std::string component = pCrashReport.find(FILENAME_COMPONENT)->second[CD_CONTENT];
- std::string uuid = pCrashReport.find(CD_UUID)->second[CD_CONTENT];
- std::string bugId;
+} /* namespace */
- NewXMLRPCClient();
+/*
+ * CReporterBugzilla
+ */
- m_bLoggedIn = false;
+CReporterBugzilla::CReporterBugzilla() :
+ m_bNoSSLVerify(false),
+ m_sBugzillaURL("https://bugzilla.redhat.com"),
+ m_sBugzillaXMLRPC("https://bugzilla.redhat.com"XML_RPC_SUFFIX)
+{}
+
+CReporterBugzilla::~CReporterBugzilla()
+{}
+
+std::string CReporterBugzilla::Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
+ const std::string& pArgs)
+{
+ int32_t bug_id = -1;
+ std::string Login;
+ std::string Password;
+ std::string BugzillaXMLRPC;
+ std::string BugzillaURL;
+ bool NoSSLVerify;
+ map_plugin_settings_t settings = parse_settings(pSettings);
+ /* if parse_settings fails it returns an empty map so we need to use defaults*/
+ if(!settings.empty())
+ {
+ Login = settings["Login"];
+ Password = settings["Password"];
+ BugzillaXMLRPC = settings["BugzillaXMLRPC"];
+ BugzillaURL = settings["BugzillaURL"];
+ NoSSLVerify = settings["NoSSLVerify"] == "yes";
+ }
+ else
+ {
+ Login = m_sLogin;
+ Password = m_sPassword;
+ BugzillaXMLRPC = m_sBugzillaXMLRPC;
+ BugzillaURL = m_sBugzillaURL;
+ NoSSLVerify = m_bNoSSLVerify;
+ }
+
+ std::string component = pCrashReport.find(FILENAME_COMPONENT)->second[CD_CONTENT];
+ std::string uuid = pCrashReport.find(CD_UUID)->second[CD_CONTENT];
try
{
+ ctx bz_server(BugzillaXMLRPC.c_str(), NoSSLVerify);
+
update_client(_("Checking for duplicates..."));
- bugId = CheckUUIDInBugzilla(component, uuid);
- if ( bugId != "" ) {
- update_client(_("Logging into bugzilla..."));
- Login();
- m_bLoggedIn = true;
+ bug_id = bz_server.check_uuid_in_bugzilla(component.c_str(), uuid.c_str());
+
+ update_client(_("Logging into bugzilla..."));
+ if ((Login == "") && (Password == ""))
+ {
+ VERB3 log("Empty login and password");
+ throw CABRTException(EXCEP_PLUGIN, std::string(_("Empty login and password. Please check Bugzilla.conf")));
+ }
+ bz_server.login(Login.c_str(), Password.c_str());
+
+ if (bug_id > 0)
+ {
update_client(_("Checking CC..."));
- if (!CheckCCAndReporter(bugId) && m_bLoggedIn)
+ if (!bz_server.check_cc_and_reporter(bug_id, Login.c_str()))
{
- AddPlusOneCC(bugId);
+ bz_server.add_plus_one_cc(bug_id, Login.c_str());
}
- DeleteXMLRPCClient();
- return m_sBugzillaURL + "/show_bug.cgi?id=" + bugId;
+ bz_server.logout();
+ return BugzillaURL + "/show_bug.cgi?id=" + to_string(bug_id);
}
- update_client(_("Logging into bugzilla..."));
- Login();
- m_bLoggedIn = true;
+
+ update_client(_("Creating new bug..."));
+ bug_id = bz_server.new_bug(pCrashReport);
+ bz_server.add_attachments(to_string(bug_id).c_str(), pCrashReport);
+
+ update_client(_("Logging out..."));
+ bz_server.logout();
}
catch (CABRTException& e)
{
- DeleteXMLRPCClient();
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::Report(): ") + e.what());
- return "";
+ throw CABRTException(EXCEP_PLUGIN, e.what());
}
+ if (bug_id > 0)
+ {
+ return BugzillaURL + "/show_bug.cgi?id=" + to_string(bug_id);
+ }
- update_client(_("Creating new bug..."));
- try
+ return BugzillaURL + "/show_bug.cgi?id=";
+}
+
+map_plugin_settings_t CReporterBugzilla::parse_settings(const map_plugin_settings_t& pSettings)
+{
+ map_plugin_settings_t plugin_settings;
+ map_plugin_settings_t::const_iterator it;
+ map_plugin_settings_t::const_iterator end = pSettings.end();
+
+ it = pSettings.find("BugzillaURL");
+ if (it != end)
{
- bugId = NewBug(pCrashReport);
- AddAttachments(bugId, pCrashReport);
- update_client(_("Logging out..."));
- Logout();
+ std::string BugzillaURL = it->second;
+ //remove the /xmlrpc.cgi part from old settings
+ //FIXME: can be removed after users are informed about new config format
+ std::string::size_type pos = BugzillaURL.find(XML_RPC_SUFFIX);
+ if (pos != std::string::npos)
+ {
+ BugzillaURL.erase(pos);
+ }
+ //remove the trailing '/'
+ while (BugzillaURL[BugzillaURL.length() - 1] == '/')
+ {
+ BugzillaURL.erase(BugzillaURL.length() - 1);
+ }
+ plugin_settings["BugzillaXMLRPC"] = BugzillaURL + XML_RPC_SUFFIX;
+ plugin_settings["BugzillaURL"] = BugzillaURL;
}
- catch (CABRTException& e)
+
+ it = pSettings.find("Login");
+ if (it == end)
{
- DeleteXMLRPCClient();
- throw CABRTException(EXCEP_PLUGIN, std::string("CReporterBugzilla::Report(): ") + e.what());
+ /* if any of the option is not set we use the defaults for everything */
+ plugin_settings.clear();
+ return plugin_settings;
}
+ plugin_settings["Login"] = it->second;
+ it = pSettings.find("Password");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["Password"] = it->second;
- DeleteXMLRPCClient();
- return m_sBugzillaURL + "/show_bug.cgi?id=" + bugId;
+ it = pSettings.find("NoSSLVerify");
+ if (it == end)
+ {
+ plugin_settings.clear();
+ return plugin_settings;
+ }
+ plugin_settings["NoSSLVerify"] = it->second;
+ VERB1 log("User settings ok, using them instead of defaults");
+ return plugin_settings;
}
void CReporterBugzilla::SetSettings(const map_plugin_settings_t& pSettings)
{
- if (pSettings.find("BugzillaURL") != pSettings.end())
+//BUG! This gets called when user's keyring contains login data,
+//then it takes precedence over /etc/abrt/plugins/Bugzilla.conf.
+//I got a case when keyring had a STALE password, and there was no way
+//for me to know that it is being used. Moreover, when I discovered it
+//(by hacking abrt source!), I don't know how to purge it from the keyring.
+//At the very least, log("SOMETHING") here.
+
+ map_plugin_settings_t::const_iterator it;
+ map_plugin_settings_t::const_iterator end = pSettings.end();
+
+ it = pSettings.find("BugzillaURL");
+ if (it != end)
{
- m_sBugzillaURL = pSettings.find("BugzillaURL")->second;
+ m_sBugzillaURL = it->second;
//remove the /xmlrpc.cgi part from old settings
//FIXME: can be removed after users are informed about new config format
std::string::size_type pos = m_sBugzillaURL.find(XML_RPC_SUFFIX);
- if(pos != std::string::npos)
+ if (pos != std::string::npos)
{
m_sBugzillaURL.erase(pos);
}
@@ -465,40 +599,41 @@ void CReporterBugzilla::SetSettings(const map_plugin_settings_t& pSettings)
m_sBugzillaURL.erase(--m_sBugzillaURL.end());
}
*/
- m_sBugzillaXMLRPC = m_sBugzillaURL + std::string(XML_RPC_SUFFIX);
+ m_sBugzillaXMLRPC = m_sBugzillaURL + XML_RPC_SUFFIX;
}
- if (pSettings.find("Login") != pSettings.end())
+ it = pSettings.find("Login");
+ if (it != end)
{
- m_sLogin = pSettings.find("Login")->second;
+ m_sLogin = it->second;
}
- if (pSettings.find("Password") != pSettings.end())
+ it = pSettings.find("Password");
+ if (it != end)
{
- m_sPassword = pSettings.find("Password")->second;
+ m_sPassword = it->second;
}
- if (pSettings.find("NoSSLVerify") != pSettings.end())
+ it = pSettings.find("NoSSLVerify");
+ if (it != end)
{
- m_bNoSSLVerify = pSettings.find("NoSSLVerify")->second == "yes";
+ m_bNoSSLVerify = (it->second == "yes");
}
}
-map_plugin_settings_t CReporterBugzilla::GetSettings()
+const map_plugin_settings_t& CReporterBugzilla::GetSettings()
{
- map_plugin_settings_t ret;
-
- ret["BugzillaURL"] = m_sBugzillaURL;
- ret["Login"] = m_sLogin;
- ret["Password"] = m_sPassword;
- ret["NoSSLVerify"] = m_bNoSSLVerify ? "yes" : "no";
+ m_pSettings["BugzillaURL"] = m_sBugzillaURL;
+ m_pSettings["Login"] = m_sLogin;
+ m_pSettings["Password"] = m_sPassword;
+ m_pSettings["NoSSLVerify"] = m_bNoSSLVerify ? "yes" : "no";
- return ret;
+ return m_pSettings;
}
PLUGIN_INFO(REPORTER,
CReporterBugzilla,
"Bugzilla",
- "0.0.3",
+ "0.0.4",
"Check if a bug isn't already reported in a bugzilla "
"and if not, report it.",
- "zprikryl@redhat.com",
+ "npajkovs@redhat.com",
"https://fedorahosted.org/abrt/wiki",
PLUGINS_LIB_DIR"/Bugzilla.GTKBuilder");
diff --git a/lib/Plugins/Bugzilla.h b/lib/Plugins/Bugzilla.h
index f6a8976..55a5f5f 100644
--- a/lib/Plugins/Bugzilla.h
+++ b/lib/Plugins/Bugzilla.h
@@ -3,48 +3,26 @@
#include "Plugin.h"
#include "Reporter.h"
-#include <xmlrpc-c/client.hpp>
-
-#include <nssb64.h>
class CReporterBugzilla : public CReporter
{
private:
- typedef std::map<std::string, xmlrpc_c::value> map_xmlrpc_params_t;
-
- void NewXMLRPCClient();
- void DeleteXMLRPCClient();
- static PRInt32 Base64Encode_cb(void *arg, const char *obuf, PRInt32 size);
- void Login();
- void Logout();
- bool CheckCCAndReporter(const std::string& pBugId);
- void AddPlusOneCC(const std::string& pBugId);
- std::string CheckUUIDInBugzilla(const std::string& pComponent, const std::string& pUUID);
- std::string NewBug(const map_crash_report_t& pCrashReport);
- void AddAttachments(const std::string& pBugId, const map_crash_report_t& pCrashReport);
- void CreateNewBugDescription(const map_crash_report_t& pCrashReport,
- std::string& pDescription);
- void GetProductAndVersion(const std::string& pRelease,
- std::string& pProduct,
- std::string& pVersion);
-
- xmlrpc_c::clientXmlTransport_curl* m_pXmlrpcTransport;
- xmlrpc_c::client_xml* m_pXmlrpcClient;
- xmlrpc_c::carriageParm_curl0 *m_pCarriageParm;
+ bool m_bNoSSLVerify;
std::string m_sBugzillaURL;
std::string m_sBugzillaXMLRPC;
std::string m_sLogin;
std::string m_sPassword;
std::string m_sAttchmentInBase64;
- bool m_bNoSSLVerify;
- bool m_bLoggedIn;
+
+ map_plugin_settings_t parse_settings(const map_plugin_settings_t& pSettings);
public:
CReporterBugzilla();
virtual ~CReporterBugzilla();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
const std::string& pArgs);
};
diff --git a/lib/Plugins/CCpp.conf b/lib/Plugins/CCpp.conf
index 02c6c1a..988ddf3 100644
--- a/lib/Plugins/CCpp.conf
+++ b/lib/Plugins/CCpp.conf
@@ -1,14 +1,17 @@
# Configuration file for CCpp add-on
-# NONE OF THESE OPTIONS IS SUPPORTED
-# generate memory map too
+# generate memory map too (IGNORED FOR NOW)
MemoryMap = no
# how to get debug-info: install, mount
## install - download and install debug-info packages
## mount - mount fedora NFS with debug info
+## (IGNORED FOR NOW)
DebugInfo = install
-# With this option set to "yes"
-# will be installed debuginfo
-InstallDebuginfo = yes
+# If this option is set to "yes",
+# debuginfos will be installed to @@LOCALSTATEDIR@@/cache/abrt-di
+InstallDebugInfo = yes
+# 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 0e0eb3b..6d6edd5 100644
--- a/lib/Plugins/CCpp.cpp
+++ b/lib/Plugins/CCpp.cpp
@@ -33,28 +33,21 @@
#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 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"
+
CAnalyzerCCpp::CAnalyzerCCpp() :
- m_bMemoryMap(false), m_bInstallDebuginfo(true)
+ m_bMemoryMap(false),
+ m_bInstallDebugInfo(true),
+ m_nDebugInfoCacheMB(4000)
{}
-static bool is_hexstr(const char* str)
-{
- while (*str)
- {
- if (!isxdigit(*str))
- return false;
- str++;
- }
- return true;
-}
-
static std::string CreateHash(const std::string& pInput)
{
std::string ret = "";
@@ -102,7 +95,6 @@ static std::string concat_str_vector(char **strings)
static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput)
{
int pipeout[2];
- char buff[1024];
pid_t child;
struct passwd* pw = getpwuid(uid);
@@ -144,6 +136,7 @@ static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput)
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';
@@ -156,7 +149,96 @@ static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput)
return 0;
}
-static void GetBacktrace(const std::string& pDebugDumpDir, std::string& pBacktrace)
+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 */
+ const char *function = strstr(line, " in ");
+ if (function)
+ {
+ if (function[4] == '?') /* " in ??" does not count */
+ {
+ function = NULL;
+ }
+ else
+ {
+ bool source_file = FOUND(" at ");
+ if (source_file)
+ return Good;
+ }
+ }
+ 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, 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);
+ 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..."));
@@ -174,13 +256,13 @@ static void GetBacktrace(const std::string& pDebugDumpDir, std::string& pBacktra
unsetenv("TERM");
putenv((char*)"TERM=dumb");
- char* args[9];
+ 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] = "set debug-file-directory /usr/lib/debug/.build-id:/var/cache/abrt-di/usr/lib/debug/.build-id";
+ 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):
@@ -188,18 +270,18 @@ static void GetBacktrace(const std::string& pDebugDumpDir, std::string& pBacktra
* even if it is completely unrelated to the coredump
* See https://bugzilla.redhat.com/show_bug.cgi?id=525721
*/
- args[2] = (char*)"-ex";
- args[3] = xasprintf("file %s", executable.c_str());
args[4] = (char*)"-ex";
- args[5] = xasprintf("core-file %s/"FILENAME_COREDUMP, pDebugDumpDir.c_str());
+ args[5] = xasprintf("file %s", executable.c_str());
args[6] = (char*)"-ex";
- args[7] = (char*)"thread apply all backtrace full";
- args[8] = NULL;
+ 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[3]);
free(args[5]);
+ free(args[7]);
}
static std::string GetIndependentBacktrace(const std::string& pBacktrace)
@@ -353,7 +435,7 @@ static void GetIndependentBuildIdPC(const std::string& pBuildIdPC, std::string&
}
}
-static std::string run_unstrip_n(const std::string& pDebugDumpDir)
+static std::string run_unstrip_n(const char *pDebugDumpDir)
{
std::string UID;
{
@@ -364,7 +446,7 @@ static std::string run_unstrip_n(const std::string& pDebugDumpDir)
char* args[4];
args[0] = (char*)"eu-unstrip";
- args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, pDebugDumpDir.c_str());
+ args[1] = xasprintf("--core=%s/"FILENAME_COREDUMP, pDebugDumpDir);
args[2] = (char*)"-n";
args[3] = NULL;
@@ -376,7 +458,19 @@ static std::string run_unstrip_n(const std::string& pDebugDumpDir)
return output;
}
-static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& build_ids)
+#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);
@@ -531,8 +625,8 @@ Another application is holding the yum lock, cannot continue
if (last >= 0 && buff[last] == '\n')
buff[last] = '\0';
- /* log(buff); - update_client logs it too */
- update_client(buff); /* maybe only if buff != ""? */
+ log("%s", buff);
+ update_client("%s", buff); /* maybe only if buff != ""? */
#ifdef COMPLAIN_IF_NO_DEBUGINFO
if (already_installed == false)
@@ -565,43 +659,44 @@ Another application is holding the yum lock, cannot continue
fclose(pipeout_fp);
wait(NULL);
}
-#if 0
-/* Needs gdb feature from here: https://bugzilla.redhat.com/show_bug.cgi?id=528668 */
-static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& build_ids)
+#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 pipein[2], pipeout[2]; //TODO: get rid of pipein. Can we use ExecVP?
- xpipe(pipein);
+ int pipeout[2]; //TODO: can we use ExecVP?
xpipe(pipeout);
pid_t child = fork();
if (child < 0)
{
- /*close(pipein[0]); close(pipeout[0]); - why bother */
- /*close(pipein[1]); close(pipeout[1]); */
+ /*close(pipeout[0]); - why bother */
+ /*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);
+ 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.c_str());
- char *tempdir = xasprintf("/tmp/abrt-%u-%lu", (int)getpid(), (long)time(NULL));
+ 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, "/var/cache/abrt-di");
- execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, "/var/cache/abrt-di", NULL);
+ 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(pipein[0]);
close(pipeout[1]);
update_client(_("Downloading and installing debug-info packages..."));
@@ -635,17 +730,79 @@ static void InstallDebugInfos(const std::string& pDebugDumpDir, std::string& bui
}
if (*p)
{
- /* log(buff); - update_client logs it too */
- update_client(buff);
+ log("%s", buff);
+ update_client("%s", buff);
}
}
fclose(pipeout_fp);
wait(NULL);
}
-#endif
-std::string CAnalyzerCCpp::GetLocalUUID(const std::string& pDebugDumpDir)
+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 CAnalyzerCCpp::GetLocalUUID(const char *pDebugDumpDir)
{
log(_("Getting local universal unique identification..."));
@@ -664,7 +821,7 @@ std::string CAnalyzerCCpp::GetLocalUUID(const std::string& pDebugDumpDir)
return CreateHash(package + executable + independentBuildIdPC);
}
-std::string CAnalyzerCCpp::GetGlobalUUID(const std::string& pDebugDumpDir)
+std::string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir)
{
log(_("Getting global universal unique identification..."));
@@ -709,7 +866,7 @@ static bool DebuginfoCheckPolkit(int uid)
return false;
}
-void CAnalyzerCCpp::CreateReport(const std::string& pDebugDumpDir, int force)
+void CAnalyzerCCpp::CreateReport(const char *pDebugDumpDir, int force)
{
update_client(_("Starting report creation..."));
@@ -734,10 +891,9 @@ void CAnalyzerCCpp::CreateReport(const std::string& pDebugDumpDir, int force)
dd.Close(); /* do not keep dir locked longer than needed */
std::string build_ids;
- map_plugin_settings_t settings = GetSettings();
- if (settings["InstallDebuginfo"] == "yes" &&
- DebuginfoCheckPolkit(atoi(UID.c_str())) )
- {
+ if (m_bInstallDebugInfo && DebuginfoCheckPolkit(atoi(UID.c_str()))) {
+ if (m_nDebugInfoCacheMB > 0)
+ trim_debuginfo_cache(m_nDebugInfoCacheMB);
InstallDebugInfos(pDebugDumpDir, build_ids);
}
else
@@ -748,12 +904,13 @@ void CAnalyzerCCpp::CreateReport(const std::string& pDebugDumpDir, int force)
GetBacktrace(pDebugDumpDir, backtrace);
dd.Open(pDebugDumpDir);
- dd.SaveText(FILENAME_BACKTRACE, build_ids + backtrace);
-log("BACKTRACE:'%s'", (build_ids + backtrace).c_str());
+ 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 CAnalyzerCCpp::Init()
@@ -805,8 +962,11 @@ void CAnalyzerCCpp::DeInit()
void CAnalyzerCCpp::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 = pSettings.find("MemoryMap");
+ map_plugin_settings_t::const_iterator it;
+ it = pSettings.find("MemoryMap");
if (it != end)
{
m_bMemoryMap = it->second == "yes";
@@ -816,22 +976,28 @@ void CAnalyzerCCpp::SetSettings(const map_plugin_settings_t& pSettings)
{
m_sDebugInfo = it->second;
}
- it = pSettings.find("InstallDebuginfo");
+ it = pSettings.find("DebugInfoCacheMB");
if (it != end)
{
- m_bInstallDebuginfo = it->second == "yes";
+ 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 = it->second == "yes";
}
}
-map_plugin_settings_t CAnalyzerCCpp::GetSettings()
+const map_plugin_settings_t& CAnalyzerCCpp::GetSettings()
{
- map_plugin_settings_t ret;
-
- ret["MemoryMap"] = m_bMemoryMap ? "yes" : "no";
- ret["DebugInfo"] = m_sDebugInfo;
- ret["InstallDebuginfo"] = m_bInstallDebuginfo ? "yes" : "no";
+ 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 ret;
+ return m_pSettings;
}
PLUGIN_INFO(ANALYZER,
diff --git a/lib/Plugins/CCpp.h b/lib/Plugins/CCpp.h
index 3fbe0b9..e2abdec 100644
--- a/lib/Plugins/CCpp.h
+++ b/lib/Plugins/CCpp.h
@@ -31,18 +31,20 @@ class CAnalyzerCCpp : public CAnalyzer
{
private:
bool m_bMemoryMap;
- bool m_bInstallDebuginfo;
+ bool m_bInstallDebugInfo;
+ unsigned m_nDebugInfoCacheMB;
std::string m_sOldCorePattern;
std::string m_sDebugInfo;
+
public:
CAnalyzerCCpp();
- virtual std::string GetLocalUUID(const std::string& pDebugDumpDir);
- virtual std::string GetGlobalUUID(const std::string& pDebugDumpDir);
- virtual void CreateReport(const std::string& pDebugDumpDir, int force);
+ 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);
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
};
#endif /* CCPP */
diff --git a/lib/Plugins/Catcut.GTKBuilder b/lib/Plugins/Catcut.GTKBuilder
new file mode 100644
index 0000000..b8c7c31
--- /dev/null
+++ b/lib/Plugins/Catcut.GTKBuilder
@@ -0,0 +1,184 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkDialog" id="PluginDialog">
+ <property name="border_width">5</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="type_hint">normal</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Catcut plugin configuration</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <child>
+ <object class="GtkLabel" id="lCatcutURL">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Catcut URL</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lLogin">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="lPassword">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Password</property>
+ </object>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_CatcutURL">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Login">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="conf_Password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">&#x25CF;</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="cb_Password">
+ <property name="label" translatable="yes">Show password</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="conf_NoSSLVerify">
+ <property name="label" translatable="yes">No SSL verify</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="bApply">
+ <property name="label">gtk-apply</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-10">bApply</action-widget>
+ <action-widget response="-6">button2</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/lib/Plugins/Catcut.conf b/lib/Plugins/Catcut.conf
new file mode 100644
index 0000000..456d7f8
--- /dev/null
+++ b/lib/Plugins/Catcut.conf
@@ -0,0 +1,8 @@
+# Catcut URL
+CatcutURL = http://127.0.0.1:8080/catcut/xmlrpc
+# yes means that ssl certificates will not be checked
+NoSSLVerify = no
+# your login has to exist, if you don have any, please create one
+Login = gavin
+# your password
+Password = junk
diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp
new file mode 100644
index 0000000..13fa8a4
--- /dev/null
+++ b/lib/Plugins/Catcut.cpp
@@ -0,0 +1,368 @@
+#include <xmlrpc-c/base.h>
+#include <xmlrpc-c/client.h>
+
+#include "abrtlib.h"
+#include "Catcut.h"
+#include "CrashTypes.h"
+#include "DebugDump.h"
+#include "ABRTException.h"
+#include "CommLayerInner.h"
+#ifdef HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+using namespace std;
+
+static xmlrpc_env env;
+static xmlrpc_client* client = NULL;
+static struct xmlrpc_clientparms clientParms;
+static struct xmlrpc_curl_xportparms curlParms;
+static xmlrpc_server_info* server_info = NULL;
+
+
+static string login(const char* login, const char* passwd);
+//static void logout();
+static void new_xmlrpc_client(const char* url, bool no_ssl_verify);
+static void destroy_xmlrpc_client();
+static void create_new_bug_description(const map_crash_report_t& pCrashReport, string& pDescription);
+static void get_product_and_version(const string& pRelease,
+ string& pProduct,
+ string& pVersion);
+
+
+static void throw_if_xml_fault_occurred()
+{
+ if (env.fault_occurred)
+ {
+ string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
+ error_msg("%s", errmsg.c_str()); // show error in daemon log
+ throw CABRTException(EXCEP_PLUGIN, errmsg);
+ }
+}
+
+static void new_xmlrpc_client(const char* url, bool no_ssl_verify)
+{
+ xmlrpc_env_init(&env);
+
+ /* This should be done at program startup, once.
+ * We do it in abrtd's main */
+ /* xmlrpc_client_setup_global_const(&env); */
+
+ curlParms.network_interface = NULL;
+ curlParms.no_ssl_verifypeer = no_ssl_verify;
+ curlParms.no_ssl_verifyhost = no_ssl_verify;
+#ifdef VERSION
+ curlParms.user_agent = PACKAGE_NAME"/"VERSION;
+#else
+ curlParms.user_agent = "abrt";
+#endif
+
+ clientParms.transport = "curl";
+ clientParms.transportparmsP = &curlParms;
+ clientParms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
+
+ xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE_NAME, VERSION, &clientParms, XMLRPC_CPSIZE(transportparm_size),
+ &client);
+ throw_if_xml_fault_occurred();
+
+ server_info = xmlrpc_server_info_new(&env, url);
+ throw_if_xml_fault_occurred();
+}
+
+static void destroy_xmlrpc_client()
+{
+ xmlrpc_server_info_free(server_info);
+ xmlrpc_env_clean(&env);
+ xmlrpc_client_destroy(client);
+}
+
+static string login(const char* login, const char* passwd)
+{
+ xmlrpc_value* param = xmlrpc_build_value(&env, "(ss)", login, passwd);
+ throw_if_xml_fault_occurred();
+
+ xmlrpc_value* result;
+ xmlrpc_client_call2(&env, client, server_info, "Catcut.auth", param, &result);
+ throw_if_xml_fault_occurred();
+ xmlrpc_DECREF(param);
+
+ xmlrpc_value *cookie_xml;
+ const char *cookie;
+ string cookie_str;
+ xmlrpc_struct_find_value(&env, result, "cookie", &cookie_xml);
+ throw_if_xml_fault_occurred();
+ xmlrpc_read_string(&env, cookie_xml, &cookie);
+ throw_if_xml_fault_occurred();
+ cookie_str = cookie;
+ /* xmlrpc_read_string returns *malloc'ed ptr*.
+ * doc is not very clear on it, but I looked in xmlrpc sources. */
+ free((void*)cookie);
+ xmlrpc_DECREF(cookie_xml);
+
+ xmlrpc_DECREF(result);
+
+ return cookie_str;
+}
+
+// catcut does not have it (yet?)
+//static void logout()
+//{
+// xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", "");
+// throw_if_xml_fault_occurred();
+//
+// xmlrpc_value* result = NULL; /* paranoia */
+// xmlrpc_client_call2(&env, client, server_info, "User.logout", param, &result);
+// throw_if_xml_fault_occurred();
+//}
+
+static void create_new_bug_description(const map_crash_report_t& pCrashReport, string& pDescription)
+{
+ string howToReproduce;
+ string comment;
+
+ if (pCrashReport.find(CD_REPRODUCE) != pCrashReport.end())
+ {
+ howToReproduce = "\n\nHow to reproduce\n"
+ "-----\n" +
+ pCrashReport.find(CD_REPRODUCE)->second[CD_CONTENT];
+ }
+ if (pCrashReport.find(CD_COMMENT) != pCrashReport.end())
+ {
+ comment = "\n\nComment\n"
+ "-----\n" +
+ pCrashReport.find(CD_COMMENT)->second[CD_CONTENT];
+ }
+ pDescription = "\nabrt detected a crash.\n" +
+ howToReproduce +
+ comment +
+ "\n\nAdditional information\n"
+ "======\n";
+
+ 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_RELEASE &&
+ it->first != CD_REPRODUCE &&
+ it->first != CD_COMMENT)
+ {
+ pDescription += "\n" + it->first + "\n";
+ pDescription += "-----\n";
+ pDescription += it->second[CD_CONTENT] + "\n\n";
+ }
+ }
+ else if (it->second[CD_TYPE] == CD_ATT)
+ {
+ pDescription += "\n\nAttached files\n"
+ "----\n";
+ pDescription += it->first + "\n";
+ }
+ else if (it->second[CD_TYPE] == CD_BIN)
+ {
+ error_msg(_("Binary file %s will not be reported"), it->first.c_str());
+ }
+ }
+}
+
+static void get_product_and_version(const string& pRelease,
+ string& pProduct,
+ string& pVersion)
+{
+ if (pRelease.find("Rawhide") != string::npos)
+ {
+ pProduct = "Fedora";
+ pVersion = "rawhide";
+ return;
+ }
+ if (pRelease.find("Fedora") != string::npos)
+ {
+ pProduct = "Fedora";
+ }
+ else if (pRelease.find("Red Hat Enterprise Linux") != string::npos)
+ {
+ pProduct = "Red Hat Enterprise Linux ";
+ }
+ string::size_type pos = pRelease.find("release");
+ pos = pRelease.find(" ", pos) + 1;
+ while (pRelease[pos] != ' ')
+ {
+ pVersion += pRelease[pos];
+ if (pProduct == "Red Hat Enterprise Linux ")
+ {
+ pProduct += pRelease[pos];
+ }
+ pos++;
+ }
+}
+
+static string new_bug(const char *auth_cookie, const map_crash_report_t& pCrashReport)
+{
+ string package = pCrashReport.find(FILENAME_PACKAGE)->second[CD_CONTENT];
+ string component = pCrashReport.find(FILENAME_COMPONENT)->second[CD_CONTENT];
+ string release = pCrashReport.find(FILENAME_RELEASE)->second[CD_CONTENT];
+ string arch = pCrashReport.find(FILENAME_ARCHITECTURE)->second[CD_CONTENT];
+ string uuid = pCrashReport.find(CD_UUID)->second[CD_CONTENT];
+
+ string summary = "[abrt] crash detected in " + package;
+ string status_whiteboard = "abrt_hash:" + uuid;
+
+ string description;
+ create_new_bug_description(pCrashReport, description);
+
+ string product;
+ string version;
+ get_product_and_version(release, product, version);
+
+ xmlrpc_value *param = xmlrpc_build_value(&env, "(s{s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
+ auth_cookie,
+ "product", product.c_str(),
+ "component", component.c_str(),
+ "version", version.c_str(),
+ "summary", summary.c_str(),
+ "description", description.c_str(),
+ "status_whiteboard", status_whiteboard.c_str(),
+ "platform", arch.c_str()
+ );
+ throw_if_xml_fault_occurred();
+
+ xmlrpc_value *result;
+ xmlrpc_client_call2(&env, client, server_info, "Catcut.createTicket", param, &result);
+ throw_if_xml_fault_occurred();
+ xmlrpc_DECREF(param);
+
+ xmlrpc_value *bug_id_xml;
+ const char *bug_id;
+ string bug_id_str;
+ xmlrpc_struct_find_value(&env, result, "ticket", &bug_id_xml);
+ throw_if_xml_fault_occurred();
+ xmlrpc_read_string(&env, bug_id_xml, &bug_id);
+ throw_if_xml_fault_occurred();
+ bug_id_str = bug_id;
+ log("New bug id: %s", bug_id);
+ update_client(_("New bug id: %s"), bug_id);
+ free((void*)bug_id);
+ xmlrpc_DECREF(bug_id_xml);
+
+ xmlrpc_DECREF(result);
+
+ return bug_id_str;
+}
+
+//static
+//void add_attachments(const string& pBugId, const map_crash_report_t& pCrashReport)
+//{
+// xmlrpc_value* result = NULL;
+//
+// map_crash_report_t::const_iterator it = pCrashReport.begin();
+// for (; it != pCrashReport.end(); it++)
+// {
+// if (it->second[CD_TYPE] == CD_ATT)
+// {
+// string description = "File: " + it->first;
+// const string& to_encode = it->second[CD_CONTENT];
+// char *encoded64 = encode_base64(to_encode.c_str(), to_encode.length());
+// xmlrpc_value* param = xmlrpc_build_value(&env,"(s{s:s,s:s,s:s,s:s})",
+// pBugId.c_str(),
+// "description", description.c_str(),
+// "filename", it->first.c_str(),
+// "contenttype", "text/plain",
+// "data", encoded64
+// );
+// free(encoded64);
+// throw_if_xml_fault_occurred();
+//
+//// catcut has this API:
+//// struct response requestUpload(string cookie, string ticket, string filename, string description)
+////response MUST include "errno", "errmsg" members; if an upload is approved,
+////a "URL" MUST be returned in the response. The description string
+////should include a brief description of the file.
+////
+////The client should upload the file via HTTP PUT to the provided
+////URL. The provided URL may be absolute or relative, if relative it must
+////be combined with the base URL of the XML-RPC server using the usual
+////rules for relative URL's (RFC 3986).
+// xmlrpc_client_call2(&env, client, server_info, "catcut.addAttachment", param, &result);
+// throw_if_xml_fault_occurred();
+// }
+// }
+//}
+
+CReporterCatcut::CReporterCatcut() :
+ m_sCatcutURL("http://127.0.0.1:8080/catcut/xmlrpc"),
+ m_bNoSSLVerify(false)
+{}
+
+CReporterCatcut::~CReporterCatcut()
+{}
+
+string CReporterCatcut::Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings, const string& pArgs)
+{
+ update_client(_("Creating new bug..."));
+ try
+ {
+ new_xmlrpc_client(m_sCatcutURL.c_str(), m_bNoSSLVerify);
+ string auth_cookie = login(m_sLogin.c_str(), m_sPassword.c_str());
+ string bug_id = (auth_cookie != "") ? new_bug(auth_cookie.c_str(), pCrashReport) : "";
+// add_attachments(to_string(bug_id), pCrashReport);
+// update_client(_("Logging out..."));
+// logout();
+ destroy_xmlrpc_client();
+ return "New catcut bug ID: " + bug_id;
+
+ }
+ catch (CABRTException& e)
+ {
+ destroy_xmlrpc_client();
+ throw CABRTException(EXCEP_PLUGIN, string("CReporterCatcut::Report(): ") + e.what());
+ }
+}
+
+void CReporterCatcut::SetSettings(const map_plugin_settings_t& pSettings)
+{
+ map_plugin_settings_t::const_iterator it;
+ map_plugin_settings_t::const_iterator end = pSettings.end();
+
+ it = pSettings.find("CatcutURL");
+ if (it != end)
+ {
+ m_sCatcutURL = it->second;
+ }
+ it = pSettings.find("Login");
+ if (it != end)
+ {
+ m_sLogin = it->second;
+ }
+ it = pSettings.find("Password");
+ if (it != end)
+ {
+ m_sPassword = it->second;
+ }
+ it = pSettings.find("NoSSLVerify");
+ if (it != end)
+ {
+ m_bNoSSLVerify = it->second == "yes";
+ }
+}
+
+const map_plugin_settings_t& CReporterCatcut::GetSettings()
+{
+ m_pSettings["CatcutURL"] = m_sCatcutURL;
+ m_pSettings["Login"] = m_sLogin;
+ m_pSettings["Password"] = m_sPassword;
+ m_pSettings["NoSSLVerify"] = m_bNoSSLVerify ? "yes" : "no";
+
+ return m_pSettings;
+}
+
+PLUGIN_INFO(REPORTER,
+ CReporterCatcut,
+ "Catcut",
+ "0.0.1",
+ "Test plugin to report bugs to catcut and if not, report it.",
+ "dvlasenk@redhat.com",
+ "https://fedorahosted.org/abrt/wiki",
+ PLUGINS_LIB_DIR"/Catcut.GTKBuilder");
diff --git a/lib/Plugins/Catcut.h b/lib/Plugins/Catcut.h
new file mode 100644
index 0000000..15efdc1
--- /dev/null
+++ b/lib/Plugins/Catcut.h
@@ -0,0 +1,27 @@
+#ifndef CATCUT_H_
+#define CATCUT_H_
+
+#include "Plugin.h"
+#include "Reporter.h"
+
+class CReporterCatcut : public CReporter
+{
+ private:
+ std::string m_sCatcutURL;
+ std::string m_sLogin;
+ std::string m_sPassword;
+ bool m_bNoSSLVerify;
+
+ public:
+ CReporterCatcut();
+ virtual ~CReporterCatcut();
+
+ virtual void SetSettings(const map_plugin_settings_t& pSettings);
+ virtual const map_plugin_settings_t& GetSettings();
+
+ virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
+ const std::string& pArgs);
+};
+
+#endif /* CATCUT_H_ */
diff --git a/lib/Plugins/FileTransfer.cpp b/lib/Plugins/FileTransfer.cpp
index 3492156..72b3b16 100644
--- a/lib/Plugins/FileTransfer.cpp
+++ b/lib/Plugins/FileTransfer.cpp
@@ -42,8 +42,8 @@
#include "ABRTException.h"
#include "CommLayerInner.h"
-
using namespace std;
+
#define HBLEN 255
#define FILETRANSFER_DIRLIST DEBUG_DUMPS_DIR "/FileTransferDirlist.txt"
@@ -55,75 +55,51 @@ CFileTransfer::CFileTransfer()
{
}
-void CFileTransfer::SendFile(const std::string& pURL,
- const std::string& pFilename)
+void CFileTransfer::SendFile(const char *pURL, const char *pFilename)
{
- if (pURL == "")
+ int len = strlen(pURL);
+ if (len == 0)
{
- warn_client(_("FileTransfer: URL not specified"));
+ error_msg(_("FileTransfer: URL not specified"));
return;
}
- int len = pURL.length();
- int i = 0;
- std::string protocol;
- while (pURL[i] != ':')
- {
- protocol += pURL[i];
- i++;
- if (i == len)
- {
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): malformed URL, does not contain protocol");
- }
- }
+ update_client(_("Sending archive %s to %s"), pFilename, pURL);
- char buffer[1024];
- snprintf(buffer, 1024, _("Sending archive %s via %s"), pFilename.c_str(), protocol.c_str());
- update_client(buffer);
-
- std::string wholeURL;
- if (pURL[len-1] == '/')
- {
- wholeURL = pURL + pFilename;
- }
- else
- {
- wholeURL = pURL + "/" + pFilename;
- }
+ string wholeURL = concat_path_file(pURL, pFilename);
int result;
int count = m_nRetryCount;
do
{
- FILE * f;
+ FILE *f;
struct stat buf;
- CURL * curl;
+ CURL *curl;
- f = fopen(pFilename.c_str(), "r");
+ f = fopen(pFilename, "r");
if (!f)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): cannot open archive file "+pFilename);
+ throw CABRTException(EXCEP_PLUGIN, ssprintf("Can't open archive file '%s'", pFilename));
}
if (fstat(fileno(f), &buf) == -1)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): cannot stat archive file "+pFilename);
+ fclose(f);
+ throw CABRTException(EXCEP_PLUGIN, ssprintf("Can't stat archive file '%s'", pFilename));
}
curl = curl_easy_init();
if (!curl)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): Curl library error.");
+ throw CABRTException(EXCEP_PLUGIN, "Curl library init error");
}
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* specify target */
curl_easy_setopt(curl, CURLOPT_URL, wholeURL.c_str());
- /*file handle: passed to the default callback, it will fread() it*/
+ /* FILE handle: passed to the default callback, it will fread() it */
curl_easy_setopt(curl, CURLOPT_READDATA, f);
- /*get file size*/
curl_easy_setopt(curl, CURLOPT_INFILESIZE, buf.st_size);
- /*everything is done here; result 0 means success*/
+ /* everything is done here; result 0 means success */
result = curl_easy_perform(curl);
- /*goodbye*/
curl_easy_cleanup(curl);
fclose(f);
}
@@ -223,7 +199,7 @@ static void create_targz(const char * archive_name, const char * directory)
if (gz == NULL)
{
fclose(f);
- free(name_without_gz);
+ free(name_without_gz);
return;
}
@@ -286,84 +262,81 @@ static void create_tarbz2(const char * archive_name, const char * directory)
free(name_without_bz2);
}
-void CFileTransfer::CreateArchive(const std::string& pArchiveName,
- const std::string& pDir)
+void CFileTransfer::CreateArchive(const char *pArchiveName, const char *pDir)
{
if (m_sArchiveType == ".tar")
{
- create_tar(pArchiveName.c_str(), pDir.c_str());
+ create_tar(pArchiveName, pDir);
}
else if (m_sArchiveType == ".tar.gz")
{
- create_targz(pArchiveName.c_str(), pDir.c_str());
+ create_targz(pArchiveName, pDir);
}
else if (m_sArchiveType == ".tar.bz2")
{
- create_tarbz2(pArchiveName.c_str(), pDir.c_str());
+ create_tarbz2(pArchiveName, pDir);
}
else if (m_sArchiveType == ".zip")
{
- create_zip(pArchiveName.c_str(), pDir.c_str());
+ create_zip(pArchiveName, pDir);
}
else
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::CreateArchive(): unknown/unsupported archive type "+m_sArchiveType);
+ throw CABRTException(EXCEP_PLUGIN, "Unknown/unsupported archive type " + m_sArchiveType);
}
}
-/*returns the last component of the directory path*/
-static std::string DirBase(const std::string& pStr)
+/* Returns the last component of the directory path.
+ * Careful to not return "" on "/path/path2/", but "path2".
+ */
+static string DirBase(const char *pStr)
{
- int i = pStr.length() - 1;
- if (i > 0 && pStr[i] == '/')
+ int end = strlen(pStr);
+ if (end > 1 && pStr[end-1] == '/')
{
- i--;
+ end--;
}
- std::string result;
- for (; i >= 0 && pStr[i] != '/'; i--)
+ int beg = end;
+ while (beg > 0 && pStr[beg-1] != '/')
{
- result = pStr[i] + result;
+ beg--;
}
- return result;
+ return string(pStr + beg, end - beg);
}
-void CFileTransfer::Run(const std::string& pActiveDir, const std::string& pArgs)
+void CFileTransfer::Run(const char *pActionDir, const char *pArgs)
{
- fstream dirlist;
- std::string dirname, archivename;
- char hostname[HBLEN];
-
update_client(_("File Transfer: Creating a report..."));
- if (pArgs == "store")
+ char hostname[HBLEN];
+ gethostname(hostname, HBLEN-1);
+ hostname[HBLEN-1] = '\0';
+
+ fstream dirlist;
+ if (strcmp(pArgs, "store") == 0)
{
/* store pActiveDir for later sending */
- dirlist.open(FILETRANSFER_DIRLIST, fstream::out | fstream::app );
- dirlist << pActiveDir << endl;
+ dirlist.open(FILETRANSFER_DIRLIST, fstream::out | fstream::app);
+ dirlist << pActionDir << endl;
dirlist.close();
}
- else if (pArgs == "one")
+ else if (strcmp(pArgs, "one") == 0)
{
/* just send one archive */
- gethostname(hostname, HBLEN);
- archivename = std::string(hostname) + "-"
- + DirBase(pActiveDir) + m_sArchiveType;
+ string archivename = ssprintf("%s-%s%s", hostname, DirBase(pActionDir).c_str(), m_sArchiveType.c_str());
try
{
- CreateArchive(archivename, pActiveDir);
- SendFile(m_sURL, archivename);
+ CreateArchive(archivename.c_str(), pActionDir);
+ SendFile(m_sURL.c_str(), archivename.c_str());
}
catch (CABRTException& e)
{
- warn_client(_("CFileTransfer::Run(): Cannot create and send an archive: ") + e.what());
- //update_client("CFileTransfer::Run(): Cannot create and send an archive: " + e.what());
+ error_msg(_("Can't create and send an archive: %s"), e.what());
}
unlink(archivename.c_str());
}
else
{
- gethostname(hostname, HBLEN);
-
dirlist.open(FILETRANSFER_DIRLIST, fstream::in);
if (dirlist.fail())
{
@@ -372,19 +345,18 @@ void CFileTransfer::Run(const std::string& pActiveDir, const std::string& pArgs)
return;
}
+ string dirname;
while (getline(dirlist, dirname), dirlist.good())
{
- archivename = std::string(hostname) + "-"
- + DirBase(dirname) + m_sArchiveType;
+ string archivename = ssprintf("%s-%s%s", hostname, DirBase(dirname.c_str()).c_str(), m_sArchiveType.c_str());
try
{
- CreateArchive(archivename, dirname);
- SendFile(m_sURL, archivename);
+ CreateArchive(archivename.c_str(), dirname.c_str());
+ SendFile(m_sURL.c_str(), archivename.c_str());
}
catch (CABRTException& e)
{
- warn_client(_("CFileTransfer::Run(): Cannot create and send an archive: ") + e.what());
-// update_client("CFileTransfer::Run(): Cannot create and send an archive: " + e.what());
+ error_msg(_("Can't create and send an archive %s"), e.what());
}
unlink(archivename.c_str());
}
@@ -406,7 +378,7 @@ void CFileTransfer::SetSettings(const map_plugin_settings_t& pSettings)
}
else
{
- warn_client(_("FileTransfer: URL not specified"));
+ error_msg(_("FileTransfer: URL not specified"));
}
it = pSettings.find("RetryCount");
@@ -428,24 +400,19 @@ void CFileTransfer::SetSettings(const map_plugin_settings_t& pSettings)
m_sArchiveType = it->second;
if (m_sArchiveType[0] != '.')
{
- m_sArchiveType = "." + m_sArchiveType;
+ m_sArchiveType = "." + m_sArchiveType;
}
}
}
-map_plugin_settings_t CFileTransfer::GetSettings()
+const map_plugin_settings_t& CFileTransfer::GetSettings()
{
- map_plugin_settings_t ret;
- std::stringstream ss;
- ret["URL"] = m_sURL;
- ss << m_nRetryCount;
- ret["RetryCount"] = ss.str();
- ss.str("");
- ss << m_nRetryDelay;
- ret["RetryDelay"] = ss.str();
- ret["ArchiveType"] = m_sArchiveType;
-
- return ret;
+ m_pSettings["URL"] = m_sURL;
+ m_pSettings["RetryCount"] = to_string(m_nRetryCount);
+ m_pSettings["RetryDelay"] = to_string(m_nRetryDelay);
+ m_pSettings["ArchiveType"] = m_sArchiveType;
+
+ return m_pSettings;
}
PLUGIN_INFO(ACTION,
diff --git a/lib/Plugins/FileTransfer.h b/lib/Plugins/FileTransfer.h
index 2f230c6..9caa256 100644
--- a/lib/Plugins/FileTransfer.h
+++ b/lib/Plugins/FileTransfer.h
@@ -35,18 +35,14 @@ class CFileTransfer : public CAction
int m_nRetryCount;
int m_nRetryDelay;
- void CreateArchive(const std::string& pArchiveName,
- const std::string& pDir);
-
- void SendFile(const std::string& pURL,
- const std::string& pFilename);
+ void CreateArchive(const char *pArchiveName, const char *pDir);
+ void SendFile(const char *pURL, const char *pFilename);
public:
CFileTransfer();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
- virtual void Run(const std::string& pActiveDir,
- const std::string& pArgs);
+ virtual const map_plugin_settings_t& GetSettings();
+ virtual void Run(const char *pActionDir, const char *pArgs);
};
#endif /* FILETRANSFER_H_ */
diff --git a/lib/Plugins/Kerneloops.conf b/lib/Plugins/Kerneloops.conf
new file mode 100644
index 0000000..47b242f
--- /dev/null
+++ b/lib/Plugins/Kerneloops.conf
@@ -0,0 +1,2 @@
+# compatibility with kerneloops.org tool
+InformAllUsers = yes
diff --git a/lib/Plugins/Kerneloops.cpp b/lib/Plugins/Kerneloops.cpp
index e01bb42..b99183c 100644
--- a/lib/Plugins/Kerneloops.cpp
+++ b/lib/Plugins/Kerneloops.cpp
@@ -32,7 +32,7 @@
#define FILENAME_KERNELOOPS "kerneloops"
-std::string CAnalyzerKerneloops::GetLocalUUID(const std::string& pDebugDumpDir)
+std::string CAnalyzerKerneloops::GetLocalUUID(const char *pDebugDumpDir)
{
log(_("Getting local universal unique identification"));
@@ -58,7 +58,7 @@ std::string CAnalyzerKerneloops::GetLocalUUID(const std::string& pDebugDumpDir)
return to_string(hash);
}
-std::string CAnalyzerKerneloops::GetGlobalUUID(const std::string& pDebugDumpDir)
+std::string CAnalyzerKerneloops::GetGlobalUUID(const char *pDebugDumpDir)
{
return GetLocalUUID(pDebugDumpDir);
}
diff --git a/lib/Plugins/Kerneloops.h b/lib/Plugins/Kerneloops.h
index 13fb009..9e2010c 100644
--- a/lib/Plugins/Kerneloops.h
+++ b/lib/Plugins/Kerneloops.h
@@ -29,17 +29,14 @@
#include "Plugin.h"
#include "Analyzer.h"
-
#include <string>
-#include "KerneloopsSysLog.h"
-
class CAnalyzerKerneloops : public CAnalyzer
{
public:
- virtual std::string GetLocalUUID(const std::string& pDebugDumpDir);
- virtual std::string GetGlobalUUID(const std::string& pDebugDumpDir);
- virtual void CreateReport(const std::string& pDebugDumpDir, int force) {}
+ virtual std::string GetLocalUUID(const char *pDebugDumpDir);
+ virtual std::string GetGlobalUUID(const char *pDebugDumpDir);
+ virtual void CreateReport(const char *pDebugDumpDir, int force) {}
};
#endif
diff --git a/lib/Plugins/KerneloopsReporter.cpp b/lib/Plugins/KerneloopsReporter.cpp
index e9967fd..cfb4e05 100644
--- a/lib/Plugins/KerneloopsReporter.cpp
+++ b/lib/Plugins/KerneloopsReporter.cpp
@@ -93,15 +93,15 @@ CKerneloopsReporter::CKerneloopsReporter() :
m_sSubmitURL("http://submit.kerneloops.org/submitoops.php")
{}
-std::string CKerneloopsReporter::Report(const map_crash_report_t& pCrashReport, const std::string& pArgs)
+std::string CKerneloopsReporter::Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
+ const std::string& pArgs)
{
int ret = -1;
- map_crash_report_t::const_iterator it;
update_client(_("Creating and submitting a report..."));
- it = pCrashReport.begin();
- it = pCrashReport.find(FILENAME_KERNELOOPS);
+ map_crash_report_t::const_iterator it = pCrashReport.find(FILENAME_KERNELOOPS);
if (it != pCrashReport.end()) {
ret = http_post_to_kerneloops_site(
m_sSubmitURL.c_str(),
@@ -109,29 +109,26 @@ std::string CKerneloopsReporter::Report(const map_crash_report_t& pCrashReport,
);
}
- if (ret)
- {
+ if (ret) {
/* FIXME: be more informative */
- throw CABRTException(EXCEP_PLUGIN, std::string("CKerneloopsReporter::Report(): Report has not been sent..."));
+ throw CABRTException(EXCEP_PLUGIN, std::string("CKerneloopsReporter::Report(): Report has not been sent..."));
}
- return "Kernel oops report was uploaded to :" + m_sSubmitURL;
+ return "Kernel oops report was uploaded to: " + m_sSubmitURL;
}
void CKerneloopsReporter::SetSettings(const map_plugin_settings_t& pSettings)
{
- if (pSettings.find("SubmitURL") != pSettings.end())
- {
- m_sSubmitURL = pSettings.find("SubmitURL")->second;
+ map_plugin_settings_t::const_iterator it = pSettings.find("SubmitURL");
+ if (it != pSettings.end()) {
+ m_sSubmitURL = it->second;
}
}
-map_plugin_settings_t CKerneloopsReporter::GetSettings()
+const map_plugin_settings_t& CKerneloopsReporter::GetSettings()
{
- map_plugin_settings_t ret;
+ m_pSettings["SubmitURL"] = m_sSubmitURL;
- ret["SubmitURL"] = m_sSubmitURL;
-
- return ret;
+ return m_pSettings;
}
PLUGIN_INFO(REPORTER,
diff --git a/lib/Plugins/KerneloopsReporter.h b/lib/Plugins/KerneloopsReporter.h
index f1b427f..7f6ab8c 100644
--- a/lib/Plugins/KerneloopsReporter.h
+++ b/lib/Plugins/KerneloopsReporter.h
@@ -41,8 +41,9 @@ class CKerneloopsReporter : public CReporter
CKerneloopsReporter();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
const std::string& pArgs);
};
diff --git a/lib/Plugins/KerneloopsScanner.cpp b/lib/Plugins/KerneloopsScanner.cpp
index 60fa92e..8c8cd4b 100644
--- a/lib/Plugins/KerneloopsScanner.cpp
+++ b/lib/Plugins/KerneloopsScanner.cpp
@@ -31,8 +31,10 @@
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
+#include "KerneloopsSysLog.h"
#include "KerneloopsScanner.h"
+#include <limits.h>
#define FILENAME_KERNELOOPS "kerneloops"
@@ -41,7 +43,6 @@
CKerneloopsScanner::CKerneloopsScanner()
{
int cnt_FoundOopses;
- m_sSysLogFile = "/var/log/messages";
/* Scan dmesg, on first call only */
cnt_FoundOopses = ScanDmesg();
@@ -49,19 +50,23 @@ CKerneloopsScanner::CKerneloopsScanner()
SaveOopsToDebugDump();
}
-void CKerneloopsScanner::Run(const std::string& pActionDir,
- const std::string& pArgs)
+void CKerneloopsScanner::Run(const char *pActionDir, const char *pArgs)
{
- int cnt_FoundOopses;
+ const char *syslog_file = "/var/log/messages";
+ map_plugin_settings_t::const_iterator it = m_pSettings.find("SysLogFile");
+ if (it != m_pSettings.end())
+ {
+ syslog_file = it->second.c_str();
+ }
- cnt_FoundOopses = ScanSysLogFile(m_sSysLogFile.c_str());
+ int cnt_FoundOopses = ScanSysLogFile(syslog_file);
if (cnt_FoundOopses > 0) {
SaveOopsToDebugDump();
/*
* This marker in syslog file prevents us from
* re-parsing old oopses (any oops before it is
* ignored by ScanSysLogFile()). The only problem
- * is that we can't be sure here that m_sSysLogFile
+ * is that we can't be sure here that syslog_file
* is the file where syslog(xxx) stuff ends up.
*/
openlog("abrt", 0, LOG_KERN);
@@ -78,26 +83,29 @@ void CKerneloopsScanner::SaveOopsToDebugDump()
{
update_client(_("Creating kernel oops crash reports..."));
+ int countdown = 16; /* do not report hundreds of oopses */
time_t t = time(NULL);
- std::list<COops> oopsList = m_pSysLog.GetOopsList();
- m_pSysLog.ClearOopsList();
-
- while (!oopsList.empty()) {
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "%s/kerneloops-%lu-%lu",
- DEBUG_DUMPS_DIR, (long)t, (long)oopsList.size());
-
- COops oops = oopsList.back();
-
+ vector_string_t oopsList = m_pOopsList;
+ m_pOopsList.clear();
+
+ while (!oopsList.empty() && --countdown != 0) {
+ char path[sizeof(DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu") + 2 * sizeof(long)*3];
+ sprintf(path, DEBUG_DUMPS_DIR"/kerneloops-%lu-%lu",
+ (long)t, (long)oopsList.size());
+
+ std::string oops = oopsList.back();
+ const char *first_line = oops.c_str();
+ char *second_line = (char*)strchr(first_line, '\n'); /* never NULL */
+ *second_line++ = '\0';
try
{
CDebugDump debugDump;
debugDump.Create(path, 0);
debugDump.SaveText(FILENAME_ANALYZER, "Kerneloops");
debugDump.SaveText(FILENAME_EXECUTABLE, "kernel");
- debugDump.SaveText(FILENAME_KERNEL, oops.m_sVersion);
+ debugDump.SaveText(FILENAME_KERNEL, first_line);
debugDump.SaveText(FILENAME_PACKAGE, "not_applicable");
- debugDump.SaveText(FILENAME_KERNELOOPS, oops.m_sData);
+ debugDump.SaveText(FILENAME_KERNELOOPS, second_line);
}
catch (CABRTException& e)
{
@@ -118,7 +126,8 @@ int CKerneloopsScanner::ScanDmesg()
buffer = (char*)xzalloc(pagesz + 1);
syscall(__NR_syslog, 3, buffer, pagesz);
- cnt_FoundOopses = m_pSysLog.ExtractOops(buffer, strlen(buffer));
+ m_pOopsList.clear();
+ cnt_FoundOopses = extract_oopses(m_pOopsList, buffer, strlen(buffer));
free(buffer);
return cnt_FoundOopses;
@@ -162,30 +171,15 @@ int CKerneloopsScanner::ScanSysLogFile(const char *filename)
close(fd);
cnt_FoundOopses = 0;
- if (sz > 0)
- cnt_FoundOopses = m_pSysLog.ExtractOops(buffer, sz);
+ if (sz > 0) {
+ m_pOopsList.clear();
+ cnt_FoundOopses = extract_oopses(m_pOopsList, buffer, sz);
+ }
free(buffer);
return cnt_FoundOopses;
}
-void CKerneloopsScanner::SetSettings(const map_plugin_settings_t& pSettings)
-{
- if (pSettings.find("SysLogFile") != pSettings.end())
- {
- m_sSysLogFile = pSettings.find("SysLogFile")->second;
- }
-}
-
-map_plugin_settings_t CKerneloopsScanner::GetSettings()
-{
- map_plugin_settings_t ret;
-
- ret["SysLogFile"] = m_sSysLogFile;
-
- return ret;
-}
-
PLUGIN_INFO(ACTION,
CKerneloopsScanner,
"KerneloopsScanner",
@@ -195,7 +189,7 @@ PLUGIN_INFO(ACTION,
"http://people.redhat.com/aarapov",
"");
-/* for dumpoops tool */
+/* For "dumpoops" tool */
extern "C" {
int scan_syslog_file(CKerneloopsScanner *This, const char *filename)
diff --git a/lib/Plugins/KerneloopsScanner.h b/lib/Plugins/KerneloopsScanner.h
index 981f187..9f00df2 100644
--- a/lib/Plugins/KerneloopsScanner.h
+++ b/lib/Plugins/KerneloopsScanner.h
@@ -27,28 +27,26 @@
#ifndef KERNELOOPSSCANNER_H_
#define KERNELOOPSSCANNER_H_
-#include "KerneloopsSysLog.h"
+#include "abrt_types.h"
#include "Plugin.h"
#include "Action.h"
class CKerneloopsScanner : public CAction
{
- private:
- std::string m_sSysLogFile;
- CSysLog m_pSysLog;
+ /* For "dumpoops" tool */
+ public:
+ vector_string_t m_pOopsList;
+ /* For "dumpoops" tool */
public:
- /* For standalone oops processor */
void SaveOopsToDebugDump();
int ScanDmesg();
int ScanSysLogFile(const char *filename);
/* Plugin interface */
+ public:
CKerneloopsScanner();
- virtual void Run(const std::string& pActionDir,
- const std::string& pArgs);
- virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
+ virtual void Run(const char *pActionDir, const char *pArgs);
};
-#endif /* KERNELOOPSSCANNER_H_ */
+#endif
diff --git a/lib/Plugins/KerneloopsSysLog.cpp b/lib/Plugins/KerneloopsSysLog.cpp
index b1171cf..d28ce39 100644
--- a/lib/Plugins/KerneloopsSysLog.cpp
+++ b/lib/Plugins/KerneloopsSysLog.cpp
@@ -26,91 +26,70 @@
#include "abrtlib.h"
#include "KerneloopsSysLog.h"
-
-#include <list>
#include <assert.h>
-/*
- * This limits the number of oopses we'll submit per session;
- * it's important that this is bounded to avoid feedback loops
- * for the scenario where submitting an oopses causes a warning/oops
- */
-#define MAX_OOPS 16
-
-struct line_info {
- char *ptr;
- char level;
-};
-
-static struct line_info *lines_info;
-static int lines_info_alloc;
-static int linecount;
-
-#define REALLOC_CHUNK 1000
-
-static int set_line_info(int index, char *linepointer, char linelevel)
+static void queue_oops(vector_string_t &vec, const char *data, const char *version)
{
- if (index >= lines_info_alloc) {
- struct line_info *new_info;
- new_info = (line_info*)realloc(lines_info,
- (lines_info_alloc + REALLOC_CHUNK) * sizeof(struct line_info));
- if (!new_info)
- return -1;
- lines_info_alloc += REALLOC_CHUNK;
- lines_info = new_info;
- }
-
- lines_info[index].ptr = linepointer;
- lines_info[index].level = linelevel;
- return 0;
+ vec.push_back(ssprintf("%s\n%s", version, data));
}
-CSysLog::CSysLog() :
- m_nFoundOopses(0)
-{}
-
-void CSysLog::QueueOops(char *data, char *version)
+/*
+ * extract_version tries to find the kernel version in given data
+ */
+static int extract_version(const char *linepointer, char *version)
{
- COops m_NewOops;
-
- if (m_nFoundOopses > MAX_OOPS)
- return;
+ int ret;
- m_NewOops.m_sData = data;
- m_NewOops.m_sVersion = version;
+ ret = 0;
+ if ((strstr(linepointer, "Pid") != NULL)
+ || (strstr(linepointer, "comm") != NULL)
+ || (strstr(linepointer, "CPU") != NULL)
+ || (strstr(linepointer, "REGS") != NULL)
+ || (strstr(linepointer, "EFLAGS") != NULL)
+ ) {
+ char* start;
+ char* end;
- m_OopsQueue.push_back(m_NewOops);
- m_nFoundOopses++;
-}
+ start = strstr((char*)linepointer, "2.6.");
+ if (start) {
+ end = strchrnul(start, ' ');
+ strncpy(version, start, end-start);
+ ret = 1;
+ }
+ }
-void CSysLog::ClearOopsList()
-{
- m_OopsQueue.clear();
-}
+ if (!ret)
+ strncpy(version, "undefined", 9);
-const std::list<COops>& CSysLog::GetOopsList()
-{
- return m_OopsQueue;
+ return ret;
}
/*
- * This function splits the dmesg buffer data into lines
- * (null terminated).
+ * extract_oops tries to find oops signatures in a log
*/
-int CSysLog::FillLinePointers(char *buffer, size_t buflen)
+struct line_info {
+ char *ptr;
+ char level;
+};
+#define REALLOC_CHUNK 1000
+int extract_oopses(vector_string_t &oopses, char *buffer, size_t buflen)
{
- char *c, *linepointer, linelevel;
+ char *c;
enum { maybe, no, yes } syslog_format = maybe;
- linecount = 0;
+ int linecount = 0;
+ int lines_info_alloc = 0;
+ struct line_info *lines_info = NULL;
+
+ /* Split buffer into lines */
- if (!buflen)
- return 0;
- buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */
+ if (buflen != 0)
+ buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */
c = buffer;
while (c < buffer + buflen) {
- char v;
+ char v, linelevel;
int len = 0;
char *c9;
+ char *linepointer;
c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */
assert(c9);
@@ -183,68 +162,32 @@ int CSysLog::FillLinePointers(char *buffer, size_t buflen)
/* if we see our own marker, we know we submitted everything upto here already */
if (len >= 4 && memmem(linepointer, len, "Abrt", 4)) {
linecount = 0;
- lines_info[0].ptr = NULL;
+ lines_info_alloc = 0;
+ free(lines_info);
+ lines_info = NULL;
+ }
+
+ if (linecount >= lines_info_alloc) {
+ lines_info_alloc += REALLOC_CHUNK;
+ lines_info = (line_info*)xrealloc(lines_info,
+ lines_info_alloc * sizeof(struct line_info));
}
- if (set_line_info(linecount, linepointer, linelevel) < 0)
- return -1;
+ lines_info[linecount].ptr = linepointer;
+ lines_info[linecount].level = linelevel;
linecount++;
next_line:
c = c9 + 1;
}
- return 0;
-}
-
-/*
- * extract_version tries to find the kernel version in given data
- */
-int CSysLog::ExtractVersion(char *linepointer, char *version)
-{
- int ret;
-
- ret = 0;
- if ((strstr(linepointer, "Pid") != NULL) ||
- (strstr(linepointer, "comm") != NULL) ||
- (strstr(linepointer, "CPU") != NULL) ||
- (strstr(linepointer, "REGS") != NULL) ||
- (strstr(linepointer, "EFLAGS") != NULL))
- {
- char* start;
- char* end;
-
- start = strstr(linepointer, "2.6.");
- if (start) {
- end = strchrnul(start, ' ');
- strncpy(version, start, end-start);
- ret = 1;
- }
- }
-
- if (!ret)
- strncpy(version, "undefined", 9);
- return ret;
-}
+ /* Analyze lines */
-/*
- * extract_oops tries to find oops signatures in a log
- */
-int CSysLog::ExtractOops(char *buffer, size_t buflen)
-{
int i;
char prevlevel = 0;
int oopsstart = -1;
- int oopsend;
+ int oopsend = linecount;
int inbacktrace = 0;
int oopsesfound = 0;
- lines_info = NULL;
- lines_info_alloc = 0;
-
- if (FillLinePointers(buffer, buflen) < 0)
- goto fail;
-
- oopsend = linecount;
-
i = 0;
while (i < linecount) {
char *c = lines_info[i].ptr;
@@ -257,36 +200,36 @@ int CSysLog::ExtractOops(char *buffer, size_t buflen)
/* find start-of-oops markers */
if (strstr(c, "general protection fault:"))
oopsstart = i;
- if (strstr(c, "BUG:"))
+ else if (strstr(c, "BUG:"))
oopsstart = i;
- if (strstr(c, "kernel BUG at"))
+ else if (strstr(c, "kernel BUG at"))
oopsstart = i;
- if (strstr(c, "do_IRQ: stack overflow:"))
+ else if (strstr(c, "do_IRQ: stack overflow:"))
oopsstart = i;
- if (strstr(c, "RTNL: assertion failed"))
+ else if (strstr(c, "RTNL: assertion failed"))
oopsstart = i;
- if (strstr(c, "Eeek! page_mapcount(page) went negative!"))
+ else if (strstr(c, "Eeek! page_mapcount(page) went negative!"))
oopsstart = i;
- if (strstr(c, "near stack overflow (cur:"))
+ else if (strstr(c, "near stack overflow (cur:"))
oopsstart = i;
- if (strstr(c, "double fault:"))
+ else if (strstr(c, "double fault:"))
oopsstart = i;
- if (strstr(c, "Badness at"))
+ else if (strstr(c, "Badness at"))
oopsstart = i;
- if (strstr(c, "NETDEV WATCHDOG"))
+ else if (strstr(c, "NETDEV WATCHDOG"))
oopsstart = i;
- if (strstr(c, "WARNING:") &&
- !strstr(c, "appears to be on the same physical disk"))
+ else if (strstr(c, "WARNING:") &&
+ !strstr(c, "appears to be on the same physical disk"))
oopsstart = i;
- if (strstr(c, "Unable to handle kernel"))
+ else if (strstr(c, "Unable to handle kernel"))
oopsstart = i;
- if (strstr(c, "sysctl table check failed"))
+ else if (strstr(c, "sysctl table check failed"))
oopsstart = i;
- if (strstr(c, "------------[ cut here ]------------"))
+ else if (strstr(c, "------------[ cut here ]------------"))
oopsstart = i;
- if (strstr(c, "list_del corruption."))
+ else if (strstr(c, "list_del corruption."))
oopsstart = i;
- if (strstr(c, "list_add corruption."))
+ else if (strstr(c, "list_add corruption."))
oopsstart = i;
if (strstr(c, "Oops:") && i >= 3)
oopsstart = i-3;
@@ -323,26 +266,33 @@ int CSysLog::ExtractOops(char *buffer, size_t buflen)
c1 = strstr(lines_info[i].ptr, ">]");
c2 = strstr(lines_info[i].ptr, "+0x");
c3 = strstr(lines_info[i].ptr, "/0x");
- if (lines_info[i].ptr[0] == ' ' && lines_info[i].ptr[1] == '[' && lines_info[i].ptr[2] == '<' && c1 && c2 && c3)
+ if (lines_info[i].ptr[0] == ' '
+ && lines_info[i].ptr[1] == '['
+ && lines_info[i].ptr[2] == '<'
+ && c1 && c2 && c3
+ ) {
inbacktrace = 1;
- } else
+ }
+ }
/* try to see if we're at the end of an oops */
- if (oopsstart >= 0 && inbacktrace > 0) {
+ else if (oopsstart >= 0 && inbacktrace > 0) {
char c2, c3;
c2 = lines_info[i].ptr[0];
c3 = lines_info[i].ptr[1];
/* line needs to start with " [" or have "] ["*/
- if ((c2 != ' ' || c3 != '[') &&
- strstr(lines_info[i].ptr, "] [") == NULL &&
- strstr(lines_info[i].ptr, "--- Exception") == NULL &&
- strstr(lines_info[i].ptr, " LR =") == NULL &&
- strstr(lines_info[i].ptr, "<#DF>") == NULL &&
- strstr(lines_info[i].ptr, "<IRQ>") == NULL &&
- strstr(lines_info[i].ptr, "<EOI>") == NULL &&
- strstr(lines_info[i].ptr, "<<EOE>>") == NULL)
+ if ((c2 != ' ' || c3 != '[')
+ && strstr(lines_info[i].ptr, "] [") == NULL
+ && strstr(lines_info[i].ptr, "--- Exception") == NULL
+ && strstr(lines_info[i].ptr, " LR =") == NULL
+ && strstr(lines_info[i].ptr, "<#DF>") == NULL
+ && strstr(lines_info[i].ptr, "<IRQ>") == NULL
+ && strstr(lines_info[i].ptr, "<EOI>") == NULL
+ && strstr(lines_info[i].ptr, "<<EOE>>") == NULL
+ ) {
oopsend = i-1;
+ }
/* oops lines are always more than 8 long */
if (strlen(lines_info[i].ptr) < 8)
@@ -381,13 +331,15 @@ int CSysLog::ExtractOops(char *buffer, size_t buflen)
is_version = 0;
for (q = oopsstart; q <= oopsend; q++) {
if (!is_version)
- is_version = ExtractVersion(lines_info[q].ptr, version);
- strcat(oops, lines_info[q].ptr);
- strcat(oops, "\n");
+ is_version = extract_version(lines_info[q].ptr, version);
+ if (lines_info[q].ptr[0]) {
+ strcat(oops, lines_info[q].ptr);
+ strcat(oops, "\n");
+ }
}
/* too short oopses are invalid */
if (strlen(oops) > 100) {
- QueueOops(oops, version);
+ queue_oops(oopses, oops, version);
oopsesfound++;
}
oopsstart = -1;
@@ -431,13 +383,13 @@ int CSysLog::ExtractOops(char *buffer, size_t buflen)
is_version = 0;
for (q = oopsstart; q <= oopsend; q++) {
if (!is_version)
- is_version = ExtractVersion(lines_info[q].ptr, version);
+ is_version = extract_version(lines_info[q].ptr, version);
strcat(oops, lines_info[q].ptr);
strcat(oops, "\n");
}
/* too short oopses are invalid */
if (strlen(oops) > 100) {
- QueueOops(oops, version);
+ queue_oops(oopses, oops, version);
oopsesfound++;
}
oopsstart = -1;
@@ -446,8 +398,7 @@ int CSysLog::ExtractOops(char *buffer, size_t buflen)
free(oops);
free(version);
}
-fail:
+
free(lines_info);
- lines_info = NULL;
return oopsesfound;
}
diff --git a/lib/Plugins/KerneloopsSysLog.h b/lib/Plugins/KerneloopsSysLog.h
index c2e8c2d..a67b33d 100644
--- a/lib/Plugins/KerneloopsSysLog.h
+++ b/lib/Plugins/KerneloopsSysLog.h
@@ -27,30 +27,8 @@
#ifndef __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_
#define __INCLUDE_GUARD_KERNELOOPSSYSLOG_H_
-#include <string>
-#include <list>
+#include "abrt_types.h"
-class COops
-{
- public:
- std::string m_sData;
- std::string m_sVersion;
-};
-
-class CSysLog
-{
- private:
- void QueueOops(char *data, char *version);
- int ExtractVersion(char *linepointer, char *version);
- int FillLinePointers(char *buffer, size_t buflen);
- std::list<COops> m_OopsQueue;
- int m_nFoundOopses;
-
- public:
- CSysLog();
- const std::list<COops>& GetOopsList();
- void ClearOopsList();
- int ExtractOops(char *buffer, size_t buflen);
-};
+int extract_oopses(vector_string_t &oopses, char *buffer, size_t buflen);
#endif
diff --git a/lib/Plugins/Logger.cpp b/lib/Plugins/Logger.cpp
index ff7bbb8..b2ac1ad 100644
--- a/lib/Plugins/Logger.cpp
+++ b/lib/Plugins/Logger.cpp
@@ -43,99 +43,40 @@ void CLogger::SetSettings(const map_plugin_settings_t& pSettings)
}
}
-map_plugin_settings_t CLogger::GetSettings()
+const map_plugin_settings_t& CLogger::GetSettings()
{
- map_plugin_settings_t ret;
+ m_pSettings["LogPath"] = m_sLogPath;
+ m_pSettings["AppendLogs"] = m_bAppendLogs ? "yes" : "no";
- ret["LogPath"] = m_sLogPath;
- ret["AppendLogs"] = m_bAppendLogs ? "yes" : "no";
-
- return ret;
+ return m_pSettings;
}
-std::string CLogger::Report(const map_crash_report_t& pCrashReport, const std::string& pArgs)
+std::string CLogger::Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings, const std::string& pArgs)
{
update_client(_("Creating a report..."));
- std::stringstream binaryFiles, commonFiles, bigTextFiles, additionalFiles, UUIDFile;
- std::ofstream fOut;
-
- 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;
- }
- else if (it->first == CD_UUID)
- {
- UUIDFile << it->first << std::endl;
- UUIDFile << "-----" << std::endl;
- UUIDFile << it->second[CD_CONTENT] << std::endl << std::endl;
- }
- else
- {
- commonFiles << it->first << std::endl;
- commonFiles << "-----" << std::endl;
- commonFiles << it->second[CD_CONTENT] << std::endl << std::endl;
- }
- }
- if (it->second[CD_TYPE] == CD_ATT)
- {
- bigTextFiles << it->first << std::endl;
- bigTextFiles << "-----" << std::endl;
- bigTextFiles << it->second[CD_CONTENT] << std::endl << std::endl;
- }
- if (it->second[CD_TYPE] == CD_BIN)
- {
- binaryFiles << it->first << std::endl;
- binaryFiles << "-----" << std::endl;
- binaryFiles << it->second[CD_CONTENT] << std::endl << std::endl;
- }
- }
-
+ std::string description = make_description_logger(pCrashReport);
+ description += "\n\n\n";
+ FILE *fOut;
if (m_bAppendLogs)
{
- fOut.open(m_sLogPath.c_str(), std::ios::app);
+ fOut = fopen(m_sLogPath.c_str(), "a");
}
else
{
- fOut.open(m_sLogPath.c_str());
+ fOut = fopen(m_sLogPath.c_str(), "w");
}
- if (fOut.is_open())
- {
- fOut << "Duplicity check" << std::endl;
- fOut << "======" << std::endl << std::endl;
- fOut << UUIDFile.str() << std::endl;
- fOut << "Common information" << std::endl;
- fOut << "======" << std::endl << std::endl;
- fOut << commonFiles.str() << std::endl;
- fOut << "Additional information" << std::endl;
- fOut << "======" << std::endl << std::endl;
- fOut << additionalFiles.str() << std::endl;
- fOut << "Big Text Files" << std::endl;
- fOut << "======" << std::endl;
- fOut << bigTextFiles.str() << std::endl;
- fOut << "Binary files" << std::endl;
- fOut << "======" << std::endl;
- fOut << binaryFiles.str() << std::endl;
- fOut << std::endl;
- fOut.close();
- }
- else
+ if (fOut)
{
- throw CABRTException(EXCEP_PLUGIN, "CLogger::Report(): Cannot open file: " + m_sLogPath);
+ fputs(description.c_str(), fOut);
+ fclose(fOut);
+ return "file://" + m_sLogPath;
}
- return "file://" + m_sLogPath;
+
+ throw CABRTException(EXCEP_PLUGIN, "CLogger::Report(): Cannot open file: " + m_sLogPath);
}
PLUGIN_INFO(REPORTER,
diff --git a/lib/Plugins/Logger.h b/lib/Plugins/Logger.h
index 60c76e4..0969bea 100644
--- a/lib/Plugins/Logger.h
+++ b/lib/Plugins/Logger.h
@@ -35,8 +35,9 @@ class CLogger : public CReporter
CLogger();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
const std::string& pArgs);
};
diff --git a/lib/Plugins/Mailx.cpp b/lib/Plugins/Mailx.cpp
index f7a86fd..f083404 100644
--- a/lib/Plugins/Mailx.cpp
+++ b/lib/Plugins/Mailx.cpp
@@ -118,7 +118,8 @@ void CMailx::SendEmail(const std::string& pSubject, const std::string& pText, co
ExecMailx(atoi(pUID.c_str()), pText);
}
-std::string CMailx::Report(const map_crash_report_t& pCrashReport, const std::string& pArgs)
+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..."));
@@ -218,16 +219,14 @@ void CMailx::SetSettings(const map_plugin_settings_t& pSettings)
}
}
-map_plugin_settings_t CMailx::GetSettings()
+const map_plugin_settings_t& CMailx::GetSettings()
{
- map_plugin_settings_t ret;
+ m_pSettings["Subject"] = m_sSubject;
+ m_pSettings["EmailFrom"] = m_sEmailFrom;
+ m_pSettings["EmailTo"] = m_sEmailTo;
+ m_pSettings["SendBinaryData"] = m_bSendBinaryData ? "yes" : "no";
- ret["Subject"] = m_sSubject;
- ret["EmailFrom"] = m_sEmailFrom;
- ret["EmailTo"] = m_sEmailTo;
- ret["SendBinaryData"] = m_bSendBinaryData ? "yes" : "no";
-
- return ret;
+ return m_pSettings;
}
PLUGIN_INFO(REPORTER,
diff --git a/lib/Plugins/Mailx.h b/lib/Plugins/Mailx.h
index fd00bb8..7af1188 100644
--- a/lib/Plugins/Mailx.h
+++ b/lib/Plugins/Mailx.h
@@ -47,8 +47,9 @@ class CMailx : public CReporter
CMailx();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
const std::string& pArgs);
};
diff --git a/lib/Plugins/Makefile.am b/lib/Plugins/Makefile.am
index bc032d7..0502f5e 100644
--- a/lib/Plugins/Makefile.am
+++ b/lib/Plugins/Makefile.am
@@ -1,28 +1,44 @@
AM_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils
pluginslibdir=$(PLUGINS_LIB_DIR)
-pluginslib_LTLIBRARIES = libCCpp.la \
- libMailx.la \
- libSQLite3.la \
- libLogger.la \
- libKerneloopsScanner.la\
- libKerneloopsReporter.la\
- libKerneloops.la \
- libRunApp.la \
- libSOSreport.la \
- libBugzilla.la \
- libTicketUploader.la \
- libPython.la \
- libFileTransfer.la
-
-dist_pluginslib_DATA = KerneloopsReporter.GTKBuilder Logger.GTKBuilder Mailx.GTKBuilder Bugzilla.GTKBuilder TicketUploader.GTKBuilder
-
-pluginsconfdir=$(PLUGINS_CONF_DIR)
-dist_pluginsconf_DATA = CCpp.conf Mailx.conf SQLite3.conf Logger.conf KerneloopsScanner.conf KerneloopsReporter.conf Bugzilla.conf TicketUploader.conf FileTransfer.conf
-
-
-man_MANS = abrt-FileTransfer.7 abrt-Bugzilla.7 abrt-KerneloopsReporter.7\
- abrt-KerneloopsScanner.7 abrt-Logger.7 abrt-Mailx.7 abrt-plugins.7\
+pluginslib_LTLIBRARIES = \
+ libCCpp.la \
+ libMailx.la \
+ libSQLite3.la \
+ libLogger.la \
+ libKerneloopsScanner.la\
+ libKerneloopsReporter.la\
+ libKerneloops.la \
+ libRunApp.la \
+ libSOSreport.la \
+ libBugzilla.la \
+ libCatcut.la \
+ libTicketUploader.la \
+ libPython.la \
+ libFileTransfer.la
+
+dist_pluginslib_DATA = \
+ KerneloopsReporter.GTKBuilder Logger.GTKBuilder \
+ Mailx.GTKBuilder Bugzilla.GTKBuilder \
+ TicketUploader.GTKBuilder Catcut.GTKBuilder
+
+pluginsconfdir = $(PLUGINS_CONF_DIR)
+dist_pluginsconf_DATA = \
+ CCpp.conf \
+ Mailx.conf \
+ SQLite3.conf \
+ Logger.conf \
+ Kerneloops.conf \
+ KerneloopsScanner.conf \
+ KerneloopsReporter.conf \
+ Bugzilla.conf \
+ Catcut.conf \
+ TicketUploader.conf \
+ FileTransfer.conf
+
+man_MANS = abrt-FileTransfer.7 abrt-Bugzilla.7 abrt-KerneloopsReporter.7 \
+ abrt-KerneloopsScanner.7 abrt-Logger.7 abrt-Mailx.7 abrt-plugins.7 \
abrt-SQLite3.7 abrt-RunApp.7 abrt-TicketUploader.7
+# + abrt-Catcut.7
EXTRA_DIST = $(man_MANS)
@@ -36,7 +52,11 @@ install-data-hook:
libCCpp_la_SOURCES = CCpp.cpp CCpp.h
libCCpp_la_LDFLAGS = -avoid-version
libCCpp_la_LIBADD = $(NSS_LIBS)
-libCCpp_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils -DCCPP_HOOK_PATH=\"${libexecdir}/hookCCpp\" -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" $(NSS_CFLAGS)
+libCCpp_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
@@ -57,7 +77,7 @@ libKerneloopsScanner_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils -D
# Mailx
libMailx_la_SOURCES = Mailx.cpp Mailx.h
libMailx_la_LDFLAGS = -avoid-version
-libMailx_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\"
+libMailx_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" -DLOCALSTATEDIR='"$(localstatedir)"'
# SQLite3
libSQLite3_la_SOURCES = SQLite3.cpp SQLite3.h
@@ -80,9 +100,15 @@ libSOSreport_la_LDFLAGS = -avoid-version
# Bugzilla
libBugzilla_la_SOURCES = Bugzilla.h Bugzilla.cpp
-libBugzilla_la_LIBADD = $(XMLRPC_CPP_LIBS) $(XMLRPC_CLIENT_CPP_LIBS) $(NSS_LIBS)
+libBugzilla_la_LIBADD = $(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS)
libBugzilla_la_LDFLAGS = -avoid-version
-libBugzilla_la_CPPFLAGS = $(XMLRPC_CPP_CFLAGS) $(XMLRPC_CLIENT_CPP_CFLAGS) $(NSS_CFLAGS) -I$(srcdir)/../../inc -I$(srcdir)/../Utils -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\"
+libBugzilla_la_CPPFLAGS = $(XMLRPC_CFLAGS) $(XMLRPC_CLIENT_CFLAGS) -I$(srcdir)/../../inc -I$(srcdir)/../Utils -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\"
+
+# Catcut
+libCatcut_la_SOURCES = Catcut.h Catcut.cpp
+libCatcut_la_LIBADD = $(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS)
+libCatcut_la_LDFLAGS = -avoid-version
+libCatcut_la_CPPFLAGS = $(XMLRPC_CFLAGS) $(XMLRPC_CLIENT_CFLAGS) -I$(srcdir)/../../inc -I$(srcdir)/../Utils -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\"
# TicketUploader
libTicketUploader_la_SOURCES = TicketUploader.h TicketUploader.cpp
diff --git a/lib/Plugins/Python.cpp b/lib/Plugins/Python.cpp
index 9be76b3..9fb7880 100644
--- a/lib/Plugins/Python.cpp
+++ b/lib/Plugins/Python.cpp
@@ -6,7 +6,7 @@
#define FILENAME_BACKTRACE "backtrace"
#define PYHOOK_CONFIG "/etc/abrt/pyhook.conf"
-std::string CAnalyzerPython::CreateHash(const std::string& pDebugDumpDir)
+static std::string CreateHash(const char *pDebugDumpDir)
{
std::string uuid;
CDebugDump dd;
@@ -15,11 +15,11 @@ std::string CAnalyzerPython::CreateHash(const std::string& pDebugDumpDir)
return uuid;
}
-std::string CAnalyzerPython::GetLocalUUID(const std::string& pDebugDumpDir)
+std::string CAnalyzerPython::GetLocalUUID(const char *pDebugDumpDir)
{
return CreateHash(pDebugDumpDir);
}
-std::string CAnalyzerPython::GetGlobalUUID(const std::string& pDebugDumpDir)
+std::string CAnalyzerPython::GetGlobalUUID(const char *pDebugDumpDir)
{
return GetLocalUUID(pDebugDumpDir);
}
diff --git a/lib/Plugins/Python.h b/lib/Plugins/Python.h
index b54de8d..82f52c0 100644
--- a/lib/Plugins/Python.h
+++ b/lib/Plugins/Python.h
@@ -8,12 +8,11 @@
class CAnalyzerPython : public CAnalyzer
{
public:
- virtual std::string GetLocalUUID(const std::string& pDebugDumpDir);
- virtual std::string GetGlobalUUID(const std::string& pDebugDumpDir);
- virtual void CreateReport(const std::string& pDebugDumpDir, int force) {}
+ 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 std::string CreateHash(const std::string& pInput);
};
#endif /* PYTHON_H_ */
diff --git a/lib/Plugins/RunApp.cpp b/lib/Plugins/RunApp.cpp
index 5a5c1d4..f816dc2 100644
--- a/lib/Plugins/RunApp.cpp
+++ b/lib/Plugins/RunApp.cpp
@@ -29,41 +29,41 @@
#define COMMAND 0
#define FILENAME 1
-void CActionRunApp::ParseArgs(const std::string& psArgs, vector_string_t& pArgs)
+/* TODO: do not duplicate: SOSreport.cpp has same function too */
+static void ParseArgs(const char *psArgs, vector_string_t& pArgs)
{
- unsigned int ii;
+ unsigned ii;
bool is_quote = false;
- std::string item = "";
- for (ii = 0; ii < psArgs.length(); ii++)
+ std::string item;
+
+ for (ii = 0; psArgs[ii]; ii++)
{
- if (psArgs[ii] == '\"')
+ if (psArgs[ii] == '"')
{
- is_quote = is_quote == true ? false : true;
+ is_quote = !is_quote;
}
else if (psArgs[ii] == ',' && !is_quote)
{
pArgs.push_back(item);
- item = "";
+ item.clear();
}
else
{
item += psArgs[ii];
}
}
- if (item != "")
+
+ if (item.size() != 0)
{
pArgs.push_back(item);
}
}
-void CActionRunApp::Run(const std::string& pActionDir,
- const std::string& pArgs)
+void CActionRunApp::Run(const char *pActionDir, const char *pArgs)
{
update_client(_("Executing RunApp plugin..."));
- char line[1024];
- std::string output = "";
-
+ std::string output;
vector_string_t args;
ParseArgs(pArgs, args);
@@ -71,8 +71,9 @@ void CActionRunApp::Run(const std::string& pActionDir,
FILE *fp = popen(args[COMMAND].c_str(), "r");
if (fp == NULL)
{
- throw CABRTException(EXCEP_PLUGIN, "CActionRunApp::Run(): cannot execute " + args[COMMAND]);
+ throw CABRTException(EXCEP_PLUGIN, "Can't execute " + args[COMMAND]);
}
+ char line[1024];
while (fgets(line, 1024, fp) != NULL)
{
output += line;
@@ -83,7 +84,7 @@ void CActionRunApp::Run(const std::string& pActionDir,
{
CDebugDump dd;
dd.Open(pActionDir);
- dd.SaveText(args[FILENAME].c_str(), output);
+ dd.SaveText(args[FILENAME].c_str(), output.c_str());
}
}
diff --git a/lib/Plugins/RunApp.h b/lib/Plugins/RunApp.h
index 23315f1..939feaa 100644
--- a/lib/Plugins/RunApp.h
+++ b/lib/Plugins/RunApp.h
@@ -28,12 +28,8 @@
class CActionRunApp : public CAction
{
- private:
- void ParseArgs(const std::string& psArgs, vector_string_t& pArgs);
-
public:
- virtual void Run(const std::string& pActionDir,
- const std::string& pArgs);
+ virtual void Run(const char *pActionDir, const char *pArgs);
};
#endif
diff --git a/lib/Plugins/SOSreport.cpp b/lib/Plugins/SOSreport.cpp
index ab6125c..fedc51a 100644
--- a/lib/Plugins/SOSreport.cpp
+++ b/lib/Plugins/SOSreport.cpp
@@ -18,41 +18,26 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <stdio.h>
-#include <string.h>
#include <ext/stdio_filebuf.h>
#include <fstream>
#include <sstream>
+#include "abrtlib.h"
+#include "abrt_types.h"
+#include "ABRTException.h"
#include "SOSreport.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
-void CActionSOSreport::CopyFile(const std::string& pSourceName, const std::string& pDestName)
-{
- std::ifstream source(pSourceName.c_str(), std::fstream::binary);
-
- if (!source)
- {
- throw CABRTException(EXCEP_PLUGIN, "CActionSOSreport::CopyFile(): could not open input sosreport filename:" + pSourceName);
- }
- std::ofstream dest(pDestName.c_str(),std::fstream::trunc|std::fstream::binary);
- if (!dest)
- {
- throw CABRTException(EXCEP_PLUGIN, "CActionSOSreport::CopyFile(): could not open output sosreport filename:" + pDestName);
- }
- dest << source.rdbuf();
-}
-
-void CActionSOSreport::ErrorCheck(const index_type pI)
+static void ErrorCheck(int pos)
{
- if (pI == std::string::npos)
+ if (pos < 0)
{
- throw CABRTException(EXCEP_PLUGIN, std::string("CActionSOSreport::ErrorCheck(): could not find filename in sosreport output"));
+ throw CABRTException(EXCEP_PLUGIN, "Can't find filename in sosreport output");
}
}
-std::string CActionSOSreport::ParseFilename(const std::string& pOutput)
+static std::string ParseFilename(const std::string& pOutput)
{
/*
the sosreport's filename is embedded in sosreport's output.
@@ -63,83 +48,85 @@ std::string CActionSOSreport::ParseFilename(const std::string& pOutput)
static const char sosreport_filename_marker[] =
"Your sosreport has been generated and saved in:";
- index_type p = pOutput.find(sosreport_filename_marker);
+ int p = pOutput.find(sosreport_filename_marker);
ErrorCheck(p);
- p += strlen(sosreport_filename_marker);
+ p += sizeof(sosreport_filename_marker)-1;
- index_type filename_start = pOutput.find_first_not_of(" \n\t", p);
+ int filename_start = pOutput.find_first_not_of(" \n\t", p);
ErrorCheck(p);
- index_type line_end = pOutput.find_first_of('\n',filename_start);
+ int line_end = pOutput.find_first_of('\n',filename_start);
ErrorCheck(p);
- index_type filename_end = pOutput.find_last_not_of(" \n\t",line_end);
+ int filename_end = pOutput.find_last_not_of(" \n\t", line_end);
ErrorCheck(p);
- return pOutput.substr(filename_start,(filename_end-filename_start)+1);
+ return pOutput.substr(filename_start, filename_end - filename_start + 1);
}
-void CActionSOSreport::ParseArgs(const std::string& psArgs, vector_args_t& pArgs)
+/* TODO: do not duplicate: RunApp.cpp has same function too */
+static void ParseArgs(const char *psArgs, vector_string_t& pArgs)
{
- unsigned int ii;
+ unsigned ii;
bool is_quote = false;
- std::string item = "";
- for (ii = 0; ii < psArgs.length(); ii++)
+ std::string item;
+
+ for (ii = 0; psArgs[ii]; ii++)
{
- if (psArgs[ii] == '\"')
+ if (psArgs[ii] == '"')
{
- is_quote = is_quote == true ? false : true;
+ is_quote = !is_quote;
}
else if (psArgs[ii] == ',' && !is_quote)
{
pArgs.push_back(item);
- item = "";
+ item.clear();
}
else
{
item += psArgs[ii];
}
}
- if (item != "")
+
+ if (item.size() != 0)
{
pArgs.push_back(item);
}
}
-void CActionSOSreport::Run(const std::string& pActionDir,
- const std::string& pArgs)
+void CActionSOSreport::Run(const char *pActionDir, const char *pArgs)
{
update_client(_("Executing SOSreport plugin..."));
- const char command_default[] = "sosreport --batch --no-progressbar --only=anaconda --only=bootloader"
+ static const char command_default[] = "sosreport --batch --no-progressbar --only=anaconda --only=bootloader"
" --only=devicemapper --only=filesys --only=hardware --only=kernel"
" --only=libraries --only=memory --only=networking --only=nfsserver"
" --only=pam --only=process --only=rpm -k rpm.rpmva=off --only=ssh"
" --only=startup --only=yum 2>&1";
- const char command_prefix[] = "sosreport --batch --no-progressbar";
+ static const char command_prefix[] = "sosreport --batch --no-progressbar";
std::string command;
- vector_args_t args;
+ vector_string_t args;
ParseArgs(pArgs, args);
if (args.size() == 0 || args[0] == "")
{
- command = std::string(command_default);
+ command = command_default;
}
else
{
- command = std::string(command_prefix) + ' ' + args[0] + " 2>&1";
+ command = ssprintf("%s %s 2>&1", command_prefix, args[0].c_str());
}
- update_client(_("running sosreport: ") + command);
+ update_client(_("running sosreport: %s"), command.c_str());
FILE *fp = popen(command.c_str(), "r");
-
if (fp == NULL)
{
- throw CABRTException(EXCEP_PLUGIN, std::string("CActionSOSreport::Run(): cannot execute ") + command);
+ throw CABRTException(EXCEP_PLUGIN, ssprintf("Can't execute '%s'", command.c_str()));
}
+//vda TODO: fix this mess
std::ostringstream output_stream;
__gnu_cxx::stdio_filebuf<char> command_output_buffer(fp, std::ios_base::in);
@@ -152,13 +139,21 @@ void CActionSOSreport::Run(const std::string& pActionDir,
std::string output = output_stream.str();
std::string sosreport_filename = ParseFilename(output);
- std::string sosreport_dd_filename = pActionDir + "/sosreport.tar.bz2";
+ std::string sosreport_dd_filename = concat_path_file(pActionDir, "sosreport.tar.bz2");
CDebugDump dd;
dd.Open(pActionDir);
//Not useful
//dd.SaveText("sosreportoutput", output);
- CopyFile(sosreport_filename,sosreport_dd_filename);
+ if (copy_file(sosreport_filename.c_str(), sosreport_dd_filename.c_str()) < 0)
+ {
+ throw CABRTException(EXCEP_PLUGIN,
+ ssprintf("Can't copy '%s' to '%s'",
+ sosreport_filename.c_str(),
+ sosreport_dd_filename.c_str()
+ )
+ );
+ }
}
PLUGIN_INFO(ACTION,
diff --git a/lib/Plugins/SOSreport.h b/lib/Plugins/SOSreport.h
index 1a35287..d4e0d73 100644
--- a/lib/Plugins/SOSreport.h
+++ b/lib/Plugins/SOSreport.h
@@ -22,24 +22,11 @@
#define SOSREPORT_H_
#include "Action.h"
-#include <string>
-#include <vector>
class CActionSOSreport : public CAction
{
- private:
- typedef std::string::size_type index_type;
-
- void CopyFile(const std::string& pSourceName, const std::string& pDestName);
- void ErrorCheck(const index_type pI);
- std::string ParseFilename(const std::string& pOutput);
-
- typedef std::vector<std::string> vector_args_t;
- void ParseArgs(const std::string& psArgs, vector_args_t& pArgs);
-
public:
- virtual void Run(const std::string& pActionDir,
- const std::string& pArgs);
+ virtual void Run(const char *pActionDir, const char *pArgs);
};
#endif
diff --git a/lib/Plugins/SQLite3.cpp b/lib/Plugins/SQLite3.cpp
index a2dc426..ab39d04 100644
--- a/lib/Plugins/SQLite3.cpp
+++ b/lib/Plugins/SQLite3.cpp
@@ -24,7 +24,8 @@
#include <stdlib.h>
#include "SQLite3.h"
#include "ABRTException.h"
-
+#include <limits.h>
+#include <abrtlib.h>
#define ABRT_TABLE_VERSION 2
#define ABRT_TABLE_VERSION_STR "2"
@@ -96,8 +97,10 @@ bool CSQLite3::Exist(const std::string& pUUID, const std::string& pUID)
{
vector_database_rows_t table;
GetTable("SELECT "DATABASE_COLUMN_REPORTED" FROM "ABRT_TABLE" WHERE "
- DATABASE_COLUMN_UUID" = '"+pUUID+"' AND "
- DATABASE_COLUMN_UID" = '"+pUID+"';", table);
+ DATABASE_COLUMN_UUID" = '"+pUUID+"' "
+ "AND ("DATABASE_COLUMN_UID" = '"+pUID+"' "
+ "OR "DATABASE_COLUMN_UID" = '-1');"
+ , table);
if (table.empty())
{
return false;
@@ -311,7 +314,8 @@ void CSQLite3::Delete(const std::string& pUUID, const std::string& pUID)
{
Exec("DELETE FROM "ABRT_TABLE" "
"WHERE "DATABASE_COLUMN_UUID" = '"+pUUID+"' "
- "AND "DATABASE_COLUMN_UID" = '"+pUID+"';");
+ "AND "DATABASE_COLUMN_UID" = '"+pUID+"' "
+ "OR "DATABASE_COLUMN_UID" = '-1';");
}
else
{
@@ -321,7 +325,7 @@ void CSQLite3::Delete(const std::string& pUUID, const std::string& pUID)
void CSQLite3::SetReported(const std::string& pUUID, const std::string& pUID, const std::string& pMessage)
{
- if(pUID == "0")
+ if (pUID == "0")
{
Exec("UPDATE "ABRT_TABLE" "
"SET "DATABASE_COLUMN_REPORTED" = 1 "
@@ -335,15 +339,17 @@ void CSQLite3::SetReported(const std::string& pUUID, const std::string& pUID, co
Exec("UPDATE "ABRT_TABLE" "
"SET "DATABASE_COLUMN_REPORTED" = 1 "
"WHERE "DATABASE_COLUMN_UUID" = '"+pUUID+"' "
- "AND "DATABASE_COLUMN_UID" = '"+pUID+"';");
+ "AND ("DATABASE_COLUMN_UID" = '"+pUID+"' "
+ "OR "DATABASE_COLUMN_UID" = '-1');");
Exec("UPDATE "ABRT_TABLE" "
"SET "DATABASE_COLUMN_MESSAGE" = '" + pMessage + "' "
"WHERE "DATABASE_COLUMN_UUID" = '"+pUUID+"' "
- "AND "DATABASE_COLUMN_UID" = '"+pUID+"';");
+ "AND ("DATABASE_COLUMN_UID" = '"+pUID+"' "
+ "OR "DATABASE_COLUMN_UID" = '-1');");
}
else
{
- throw CABRTException(EXCEP_PLUGIN, "CSQLite3::SetReported(): UUID is not found in DB.");
+ throw CABRTException(EXCEP_PLUGIN, "CSQLite3::SetReported(): UUID"+pUID+" is not found in DB.");
}
}
@@ -357,7 +363,8 @@ vector_database_rows_t CSQLite3::GetUIDData(const std::string& pUID)
else
{
GetTable("SELECT * FROM "ABRT_TABLE
- " WHERE "DATABASE_COLUMN_UID" = '"+pUID+"';",
+ " WHERE "DATABASE_COLUMN_UID" = '"+pUID+"' "
+ "OR "DATABASE_COLUMN_UID" = '-1';",
table);
}
return table;
@@ -377,7 +384,8 @@ database_row_t CSQLite3::GetUUIDData(const std::string& pUUID, const std::string
{
GetTable("SELECT * FROM "ABRT_TABLE" "
"WHERE "DATABASE_COLUMN_UUID" = '"+pUUID+"' "
- "AND "DATABASE_COLUMN_UID" = '"+pUID+"';",
+ "AND ("DATABASE_COLUMN_UID" = '"+pUID+"' "
+ "OR "DATABASE_COLUMN_UID" = '-1');",
table);
}
@@ -396,13 +404,11 @@ void CSQLite3::SetSettings(const map_plugin_settings_t& pSettings)
}
}
-map_plugin_settings_t CSQLite3::GetSettings()
+const map_plugin_settings_t& CSQLite3::GetSettings()
{
- map_plugin_settings_t ret;
-
- ret["DBPath"] = m_sDBPath;
+ m_pSettings["DBPath"] = m_sDBPath;
- return ret;
+ return m_pSettings;
}
PLUGIN_INFO(DATABASE,
diff --git a/lib/Plugins/SQLite3.h b/lib/Plugins/SQLite3.h
index e7ca8ae..0eb3d08 100644
--- a/lib/Plugins/SQLite3.h
+++ b/lib/Plugins/SQLite3.h
@@ -58,7 +58,7 @@ class CSQLite3 : public CDatabase
virtual database_row_t GetUUIDData(const std::string& pUUID, const std::string& pUID);
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
};
#endif /* SQLITE3_H_ */
diff --git a/lib/Plugins/TicketUploader.cpp b/lib/Plugins/TicketUploader.cpp
index 69243cd..e380de0 100644
--- a/lib/Plugins/TicketUploader.cpp
+++ b/lib/Plugins/TicketUploader.cpp
@@ -17,26 +17,20 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <curl/curl.h>
+#include "abrtlib.h"
#include "TicketUploader.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
-#include <stdlib.h>
-#include <sys/stat.h>
-
-#include <string>
-#include <fstream>
-#include <sstream>
-#include <ext/stdio_filebuf.h>
-#include <curl/curl.h>
+using namespace std;
CTicketUploader::CTicketUploader() :
- m_sCustomer(""),
- m_sTicket(""),
- m_sURL(""),
m_bEncrypt(false),
m_bUpload(false),
m_nRetryCount(3),
@@ -47,196 +41,131 @@ CTicketUploader::~CTicketUploader()
{}
-
-void CTicketUploader::Error(string func, string msg)
-{
- update_client(msg);
- throw CABRTException(EXCEP_PLUGIN, func + msg);
-}
-
-void CTicketUploader::CopyFile(const std::string& pSourceName, const std::string& pDestName)
+static void Error(const char *msg)
{
- std::ifstream source(pSourceName.c_str(), std::fstream::binary);
-
- if (!source)
- {
- throw CABRTException(EXCEP_PLUGIN, "CActionSOSreport::CopyFile(): could not open input sosreport filename:" + pSourceName);
- }
- std::ofstream dest(pDestName.c_str(),std::fstream::trunc|std::fstream::binary);
- if (!dest)
- {
- throw CABRTException(EXCEP_PLUGIN, "CActionSOSreport::CopyFile(): could not open output sosreport filename:" + pDestName);
- }
- dest << source.rdbuf();
+ update_client("%s", msg);
+ throw CABRTException(EXCEP_PLUGIN, msg);
}
-void CTicketUploader::RunCommand(string cmd)
+static void RunCommand(const char *cmd)
{
- int retcode = system(cmd.c_str());
- if (retcode == -1)
- {
- Error("TicketUploader::RunCommand:", "error: could not start subshell: " + cmd);
- }
+ int retcode = system(cmd);
if (retcode)
{
- std::ostringstream msg;
- msg << "error: subshell failed (rc=" << retcode << "):" << cmd;
- Error("TicketUploader::RunCommand:", msg.str());
+ Error(ssprintf("'%s' exited with %d", cmd, retcode).c_str());
}
}
-string CTicketUploader::ReadCommand(string cmd)
+static string ReadCommand(const char *cmd)
{
- FILE* fp = popen(cmd.c_str(),"r");
+ FILE* fp = popen(cmd, "r");
if (!fp)
{
- Error("TicketUploader::ReadCommand:", "error: could not start subshell: " + cmd);
+ Error(ssprintf("error running '%s'", cmd).c_str());
}
- __gnu_cxx::stdio_filebuf<char> command_output_buffer(fp, std::ios_base::in);
- std::ostringstream output_stream;
- output_stream << &command_output_buffer;
+ string result;
+ char buff[1024];
+ while (fgets(buff, sizeof(buff), fp) != NULL)
+ {
+ result += buff;
+ }
int retcode = pclose(fp);
if (retcode)
{
- std::ostringstream msg;
- msg << "error: subshell failed (rc=" << retcode << "):" << cmd;
- Error("TicketUploader::ReadCommand:", msg.str());
+ Error(ssprintf("'%s' exited with %d", cmd, retcode).c_str());
}
- return output_stream.str();
+ return result;
}
-void CTicketUploader::WriteCommand(string cmd,string input)
+static void WriteCommand(const char *cmd, const char *input)
{
- FILE* fp = popen(cmd.c_str(),"w");
+ FILE* fp = popen(cmd, "w");
if (!fp)
{
- Error("TicketUploader::WriteCommand:", "error: could not start subshell: " + cmd);
+ Error(ssprintf("error running '%s'", cmd).c_str());
}
- size_t input_length = input.length();
- size_t check = fwrite(input.c_str(),1,input_length,fp);
- if (input_length != check)
- {
- Error("TicketUploader::WriteCommand:", "error: could not send input to subshell: " + cmd);
- }
+ /* Hoping it's not too big to get us forever blocked... */
+ fputs(input, fp);
int retcode = pclose(fp);
if (retcode)
{
- std::ostringstream msg;
- msg << "error: subshell failed (rc=" << retcode << "):" << cmd;
- Error("TicketUploader::ReadCommand:", msg.str());
+ Error(ssprintf("'%s' exited with %d", cmd, retcode).c_str());
}
-
}
-void CTicketUploader::SendFile(const std::string& pURL,
- const std::string& pFilename)
+void CTicketUploader::SendFile(const char *pURL, const char *pFilename)
{
- FILE * f;
- struct stat buf;
- CURL * curl;
- std::string wholeURL, protocol;
- int result, i, count = m_nRetryCount;
- int len = pURL.length();
- std::string file;
-
- if (pURL == "")
+ if (pURL[0] == '\0')
{
- warn_client(_("FileTransfer: URL not specified"));
+ error_msg(_("FileTransfer: URL not specified"));
return;
}
- protocol = "";
- i = 0;
- while(pURL[i] != ':')
- {
- protocol += pURL[i];
- i++;
- if(i == len)
- {
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): malformed URL, does not contain protocol");
- }
- }
- file = pFilename.substr(pFilename.rfind("/") + 1, pFilename.length());
-
- if( pURL[len-1] == '/' )
- {
- wholeURL = pURL + file;
- }
- else
- {
- wholeURL = pURL + "/" + file;
- }
-
- update_client(_("Sending archive ") + pFilename + _(" via ") + protocol + _(" to ") + pURL);
+ update_client(_("Sending archive %s to %s"), pFilename, pURL);
+ const char *base = (strrchr(pFilename, '/') ? : pFilename-1) + 1;
+ string wholeURL = concat_path_file(pURL, base);
+ int count = m_nRetryCount;
+ int result;
do
{
- f = fopen(pFilename.c_str(),"r");
- if(!f)
+ FILE* f = fopen(pFilename, "r");
+ if (!f)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): cannot open archive file "+pFilename);
+ throw CABRTException(EXCEP_PLUGIN, ssprintf("Can't open archive file '%s'", pFilename));
}
- if (stat(pFilename.c_str(), &buf) == -1)
+ struct stat buf;
+ if (fstat(fileno(f), &buf) == -1)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): cannot stat archive file "+pFilename);
+ throw CABRTException(EXCEP_PLUGIN, ssprintf("Can't stat archive file '%s'", pFilename));
}
- curl = curl_easy_init();
- if(!curl)
+ CURL* curl = curl_easy_init();
+ if (!curl)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): Curl library error.");
+ throw CABRTException(EXCEP_PLUGIN, "Curl library init error");
}
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* specify target */
curl_easy_setopt(curl, CURLOPT_URL, wholeURL.c_str());
- /*file handle: passed to the default callback, it will fread() it*/
curl_easy_setopt(curl, CURLOPT_READDATA, f);
- /*get file size*/
curl_easy_setopt(curl, CURLOPT_INFILESIZE, buf.st_size);
- /*everything is done here; result 0 means success*/
+ /* everything is done here; result 0 means success */
result = curl_easy_perform(curl);
- /*goodbye*/
+ /* goodbye */
curl_easy_cleanup(curl);
fclose(f);
if (result != 0)
{
- update_client(_("Sending failed, try it again: ") + std::string(curl_easy_strerror((CURLcode)result)));
+ update_client(_("Sending failed, trying again. %s"), curl_easy_strerror((CURLcode)result));
}
}
/*retry the upload if not succesful, wait a bit before next try*/
- while( result!=0 && --count != 0 && (sleep(m_nRetryDelay),1) );
+ while (result != 0 && --count != 0 && (sleep(m_nRetryDelay), 1));
if (count <= 0 && result != 0)
{
- throw CABRTException(EXCEP_PLUGIN, "CFileTransfer::SendFile(): Curl can not send a ticket.");
+ throw CABRTException(EXCEP_PLUGIN, "Curl can not send a ticket");
}
}
-string CTicketUploader::Report(const map_crash_report_t& pCrashReport, const std::string& pArgs)
+string CTicketUploader::Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings, const string& pArgs)
{
- string ret;
update_client(_("Creating an TicketUploader report..."));
-
-
// Get ticket name, customer name, and do_encrypt from config settings
- string ticket_name;
- string customer_name;
- string upload_url;
- bool do_encrypt = false;
- bool do_upload = false;
-
- customer_name = m_sCustomer;
- ticket_name = m_sTicket;
- upload_url = m_sURL;
- do_encrypt = m_bEncrypt;
- do_upload = m_bUpload;
+ string customer_name = m_sCustomer;
+ string ticket_name = m_sTicket;
+ string upload_url = m_sURL;
+ bool do_encrypt = m_bEncrypt;
+ bool do_upload = m_bUpload;
bool have_ticket_name = false;
if (ticket_name == "")
@@ -248,238 +177,221 @@ string CTicketUploader::Report(const map_crash_report_t& pCrashReport, const std
have_ticket_name = true;
}
-
-
// Format the time to add to the file name
const int timebufmax = 256;
char timebuf[timebufmax];
time_t curtime = time(NULL);
- if (!strftime(timebuf,timebufmax,"-%G%m%d%k%M%S",gmtime(&curtime)))
+ if (!strftime(timebuf, timebufmax, "-%G%m%d%k%M%S", gmtime(&curtime)))
{
- Error("TicketUploader::Report:","could not format time");
+ Error("Can't format time");
}
-
-
// Create a tmp work directory, and within that the directory
// that will be the root of the tarball
string file_name = ticket_name + timebuf;
- char TEMPLATE[] = "/tmp/rhuploadXXXXXX";
- string tmpdir_name = mkdtemp(TEMPLATE);
- string tmptar_name = tmpdir_name + '/' + file_name;
+ char tmpdir_name[] = "/tmp/rhuploadXXXXXX";
+ if (mkdtemp(tmpdir_name) == NULL)
+ {
+ Error("Can't mkdir a temporary directory in /tmp");
+ }
+ string tmptar_name = concat_path_file(tmpdir_name, file_name.c_str());
if (mkdir(tmptar_name.c_str(),S_IRWXU))
{
- Error("TicketUploader::Report:","error: could not mkdir: " + tmptar_name);
+ Error(ssprintf("Can't mkdir '%s'", tmptar_name.c_str()).c_str());
}
-
-
// Copy each entry into the tarball root,
// files are simply copied, strings are written to a file
map_crash_report_t::const_iterator it;
for (it = pCrashReport.begin(); it != pCrashReport.end(); it++)
{
- if (it->second[CD_TYPE] == CD_TXT)
- {
- string ofile_name = tmptar_name + '/' + it->first;
- std::ofstream ofile(ofile_name.c_str(),std::fstream::trunc|std::fstream::binary);
+ if (it->second[CD_TYPE] == CD_TXT
+ || it->second[CD_TYPE] == CD_ATT
+ ) {
+ string ofile_name = concat_path_file(tmptar_name.c_str(), it->first.c_str());
+ ofstream ofile(ofile_name.c_str(), fstream::trunc|fstream::binary);
if (!ofile)
{
- Error("TicketUploader::Report:","error: could not open: " + ofile_name);
+ Error(ssprintf("Can't open '%s'", ofile_name.c_str()).c_str());
}
- ofile << it->second[CD_CONTENT] << std::endl;
+ ofile << it->second[CD_CONTENT] << endl;
ofile.close();
}
- if (it->second[CD_TYPE] == CD_ATT)
+ else if (it->second[CD_TYPE] == CD_BIN)
{
- string ofile_name = tmptar_name + '/' + it->first;
- std::ofstream ofile(ofile_name.c_str(),std::fstream::trunc|std::fstream::binary);
- if (!ofile)
+ string ofile_name = concat_path_file(tmptar_name.c_str(), it->first.c_str());
+ if (copy_file(it->second[CD_CONTENT].c_str(), ofile_name.c_str()) < 0)
{
- Error("TicketUploader::Report:","error: could not open: " + ofile_name);
+ throw CABRTException(EXCEP_PLUGIN,
+ ssprintf("Can't copy '%s' to '%s'",
+ it->second[CD_CONTENT].c_str(),
+ ofile_name.c_str()
+ )
+ );
}
- ofile << it->second[CD_CONTENT] << std::endl;
- ofile.close();
- }
- if (it->second[CD_TYPE] == CD_BIN)
- {
- string ofile_name = tmptar_name + '/' + it->first;
- CopyFile(it->second[CD_CONTENT],ofile_name);
}
}
-
-
// add ticket_name and customer name to tarball
if (have_ticket_name)
{
string ofile_name = tmptar_name + "/TICKET";
- std::ofstream ofile(ofile_name.c_str(),std::fstream::trunc|std::fstream::binary);
+ ofstream ofile(ofile_name.c_str(), fstream::trunc|fstream::binary);
if (!ofile)
{
- Error("TicketUploader::Report:","error: could not open: " + ofile_name);
+ Error(ssprintf("Can't open '%s'", ofile_name.c_str()).c_str());
}
- ofile << ticket_name << std::endl;
+ ofile << ticket_name << endl;
ofile.close();
}
if (customer_name != "")
{
string ofile_name = tmptar_name + "/CUSTOMER";
- std::ofstream ofile(ofile_name.c_str(),std::fstream::trunc|std::fstream::binary);
+ ofstream ofile(ofile_name.c_str(), fstream::trunc|fstream::binary);
if (!ofile)
{
- Error("TicketUploader::Report:","error: could not open: " + ofile_name);
+ Error(ssprintf("Can't open '%s'", ofile_name.c_str()).c_str());
}
- ofile << customer_name << std::endl;
+ ofile << customer_name << endl;
ofile.close();
}
-
-
// Create the compressed tarball
string outfile_basename = file_name + ".tar.gz";
- string outfile_name = tmpdir_name + '/' + outfile_basename;
- string cmd = string("tar -C ") + tmpdir_name +
- " --create --gzip --file=" + outfile_name + ' ' + file_name;
- RunCommand(cmd);
-
-
-
+ string outfile_name = concat_path_file(tmpdir_name, outfile_basename.c_str());
+ string cmd = ssprintf("tar -C %s --create --gzip --file=%s %s", tmpdir_name, outfile_name.c_str(), file_name.c_str());
+ RunCommand(cmd.c_str());
// encrypt if requested
string key;
if (do_encrypt)
{
- cmd = string("openssl rand -base64 48");
- key = ReadCommand(cmd);
+ key = ReadCommand("openssl rand -base64 48");
string infile_name = outfile_name;
outfile_basename += ".aes";
outfile_name += ".aes";
- cmd = string("openssl aes-128-cbc -in ") + infile_name +
- " -out " + outfile_name + " -pass stdin";
- WriteCommand(cmd,key);
+ cmd = ssprintf("openssl aes-128-cbc -in %s -out %s -pass stdin", infile_name.c_str(), outfile_name.c_str());
+ WriteCommand(cmd.c_str(), key.c_str());
}
-
-
// generate md5sum
- cmd = string("cd ") + tmpdir_name + string("; md5sum ") + outfile_basename;
- string md5sum = ReadCommand(cmd);
-
-
+ cmd = ssprintf("cd %s; md5sum %s", tmpdir_name, outfile_basename.c_str());
+ string md5sum = ReadCommand(cmd.c_str());
// upload or cp to /tmp
if (do_upload)
{
// FIXME: SendFile isn't working sometime (scp)
- SendFile(upload_url,outfile_name);
+ SendFile(upload_url.c_str(), outfile_name.c_str());
}
else
{
- cmd = string("cp ") + outfile_name + " /tmp/";
- RunCommand(cmd);
+ cmd = ssprintf("cp %s /tmp/", outfile_name.c_str());
+ RunCommand(cmd.c_str());
}
-
-
// generate a reciept telling md5sum and encryption key
- std::ostringstream msgbuf;
+ ostringstream msgbuf;
if (have_ticket_name)
- msgbuf << _("Please copy this into ticket: ") << ticket_name << std::endl;
+ msgbuf << _("Please copy this into ticket: ") << ticket_name << endl;
else
- msgbuf << _("Please send this to your technical support: ") << std::endl;
+ msgbuf << _("Please send this to your technical support: ") << endl;
if (do_upload)
- msgbuf << _("RHUPLOAD: This report was sent to ") + upload_url << std::endl;
+ msgbuf << _("RHUPLOAD: This report was sent to ") + upload_url << endl;
else
- msgbuf << _("RHUPLOAD: This report was copied into /tmp/: ") << std::endl;
+ msgbuf << _("RHUPLOAD: This report was copied into /tmp/: ") << endl;
if (have_ticket_name)
- msgbuf << _("TICKET: ") << ticket_name << std::endl;
- msgbuf << _("FILE: ") << outfile_basename << std::endl;
- msgbuf << _("MD5SUM: ") << std::endl;
+ msgbuf << _("TICKET: ") << ticket_name << endl;
+ msgbuf << _("FILE: ") << outfile_basename << endl;
+ msgbuf << _("MD5SUM: ") << endl;
msgbuf << md5sum;
if (do_encrypt)
{
- msgbuf << _("KEY: aes-128-cbc") << std::endl;
+ msgbuf << _("KEY: aes-128-cbc") << endl;
msgbuf << key;
}
- msgbuf << _("END: ") << std::endl;
+ msgbuf << _("END: ") << endl;
- warn_client(msgbuf.str());
+ error_msg("%s", msgbuf.str().c_str());
+ string ret;
if (do_upload)
{
string xx = _("report sent to ") + upload_url + '/' + outfile_basename;
- update_client(xx);
+ update_client("%s", xx.c_str());
ret = xx;
}
else
{
string xx = _("report copied to /tmp/") + outfile_basename;
- update_client(xx);
+ update_client("%s", xx.c_str());
ret = xx;
}
// delete the temporary directory
- cmd = string("rm -rf ") + tmpdir_name;
- RunCommand(cmd);
+ cmd = ssprintf("rm -rf %s", tmpdir_name);
+ RunCommand(cmd.c_str());
return ret;
}
void CTicketUploader::SetSettings(const map_plugin_settings_t& pSettings)
{
- if (pSettings.find("Customer") != pSettings.end())
+ map_plugin_settings_t::const_iterator end = pSettings.end();
+ map_plugin_settings_t::const_iterator it;
+
+ it = pSettings.find("Customer");
+ if (it != end)
{
- m_sCustomer = pSettings.find("Customer")->second;
+ m_sCustomer = it->second;
}
- if (pSettings.find("Ticket") != pSettings.end())
+ it = pSettings.find("Ticket");
+ if (it != end)
{
- m_sTicket = pSettings.find("Ticket")->second;
+ m_sTicket = it->second;
}
- if (pSettings.find("URL") != pSettings.end())
+ it = pSettings.find("URL");
+ if (it != end)
{
- m_sURL = pSettings.find("URL")->second;
+ m_sURL = it->second;
}
- if (pSettings.find("Encrypt") != pSettings.end())
+ it = pSettings.find("Encrypt");
+ if (it != end)
{
- m_bEncrypt = pSettings.find("Encrypt")->second == "yes";
+ m_bEncrypt = it->second == "yes";
}
- if (pSettings.find("Upload") != pSettings.end())
+ it = pSettings.find("Upload");
+ if (it != end)
{
- m_bUpload = pSettings.find("Upload")->second == "yes";
+ m_bUpload = it->second == "yes";
}
- if (pSettings.find("RetryCount") != pSettings.end())
+ it = pSettings.find("RetryCount");
+ if (it != end)
{
- m_nRetryCount = atoi(pSettings.find("RetryCount")->second.c_str());
+ m_nRetryCount = atoi(it->second.c_str());
}
- if (pSettings.find("RetryDelay") != pSettings.end())
+ it = pSettings.find("RetryDelay");
+ if (it != end)
{
- m_nRetryDelay = atoi(pSettings.find("RetryDelay")->second.c_str());
+ m_nRetryDelay = atoi(it->second.c_str());
}
}
-map_plugin_settings_t CTicketUploader::GetSettings()
+const map_plugin_settings_t& CTicketUploader::GetSettings()
{
- map_plugin_settings_t ret;
-
- ret["Customer"] = m_sCustomer;
- ret["Ticket"] = m_sTicket;
- ret["URL"] = m_sURL;
- ret["Encrypt"] = m_bEncrypt ? "yes" : "no";
- ret["Upload"] = m_bEncrypt ? "yes" : "no";
-
- std::stringstream ss;
- ss << m_nRetryCount;
- ret["RetryCount"] = ss.str();
- ss.str("");
- ss << m_nRetryDelay;
- ret["RetryDelay"] = ss.str();
-
- return ret;
+ m_pSettings["Customer"] = m_sCustomer;
+ m_pSettings["Ticket"] = m_sTicket;
+ m_pSettings["URL"] = m_sURL;
+ m_pSettings["Encrypt"] = m_bEncrypt ? "yes" : "no";
+ m_pSettings["Upload"] = m_bEncrypt ? "yes" : "no";
+ m_pSettings["RetryCount"] = to_string(m_nRetryCount);
+ m_pSettings["RetryDelay"] = to_string(m_nRetryDelay);
+
+ return m_pSettings;
}
PLUGIN_INFO(REPORTER,
diff --git a/lib/Plugins/TicketUploader.h b/lib/Plugins/TicketUploader.h
index 68a2963..9ae3478 100644
--- a/lib/Plugins/TicketUploader.h
+++ b/lib/Plugins/TicketUploader.h
@@ -29,45 +29,28 @@
#include "Reporter.h"
#include "CrashTypes.h"
-typedef std::string string;
-
class CTicketUploader : public CReporter
{
private:
- string m_sCustomer;
- string m_sTicket;
- string m_sURL;
- bool m_bEncrypt;
- bool m_bUpload;
-
- int m_nRetryCount;
- int m_nRetryDelay;
-
- void Error(string func, string msg);
- void CopyFile(const std::string& pSourceName, const std::string& pDestName);
- // Wrappers around popen/system
- // the wrapper in each case handles errors,
- // and converts from string->char*
- // RunCommand - a wrapper around system(cmd)
- void RunCommand(string cmd);
- // ReadCommand - a wrapper around popen(cmd,"r")
- string ReadCommand(string cmd);
- // WriteCommand - a wrapper around popen(cmd,"w")
- void WriteCommand(string cmd, string input );
+ std::string m_sCustomer;
+ std::string m_sTicket;
+ std::string m_sURL;
+ bool m_bEncrypt;
+ bool m_bUpload;
+ int m_nRetryCount;
+ int m_nRetryDelay;
- void SendFile(const std::string& pURL,
- const std::string& pFilename);
+ void SendFile(const char *pURL, const char *pFilename);
public:
CTicketUploader();
virtual ~CTicketUploader();
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual string Report(const map_crash_report_t& pCrashReport,
+ virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
const std::string& pArgs);
-
-
};
-#endif /* TICKETUPLOADER_H_ */
+#endif
diff --git a/lib/Utils/Action.h b/lib/Utils/Action.h
index 1286feb..5992cbf 100644
--- a/lib/Utils/Action.h
+++ b/lib/Utils/Action.h
@@ -22,7 +22,6 @@
#ifndef ACTION_H_
#define ACTION_H_
-#include <string>
#include "Plugin.h"
/**
@@ -40,8 +39,7 @@ class CAction : public CPlugin
* @param pActionDir An actual directory.
* @param pArgs Plugin's arguments.
*/
- virtual void Run(const std::string& pActionDir,
- const std::string& pArgs) = 0;
+ virtual void Run(const char *pActionDir, const char *pArgs) = 0;
};
-#endif /*ACTION_H_*/
+#endif
diff --git a/lib/Utils/Analyzer.h b/lib/Utils/Analyzer.h
index e5bda57..9108a91 100644
--- a/lib/Utils/Analyzer.h
+++ b/lib/Utils/Analyzer.h
@@ -37,20 +37,20 @@ class CAnalyzer : public CPlugin
* @param pDebugDumpPath A debugdump dir containing all necessary data.
* @return A local UUID.
*/
- virtual std::string GetLocalUUID(const std::string& pDebugDumpPath) = 0;
+ virtual std::string GetLocalUUID(const char *pDebugDumpDir) = 0;
/**
* A method, which gets a global UUID of particular crash.
* @param pDebugDumpPath A debugdump dir containing all necessary data.
* @return A global UUID.
*/
- virtual std::string GetGlobalUUID(const std::string& pDebugDumpPath) = 0;
+ virtual std::string GetGlobalUUID(const char *pDebugDumpDir) = 0;
/**
* A method, which takes care of getting all additional data needed
* for computing UUIDs and creating a report. This report could be send
* somewhere afterwards.
* @param pDebugDumpPath A debugdump dir containing all necessary data.
*/
- virtual void CreateReport(const std::string& pDebugDumpPath, int force) = 0;
+ virtual void CreateReport(const char *pDebugDumpDir, int force) = 0;
};
#endif /*ANALYZER_H_*/
diff --git a/lib/Utils/CommLayerInner.cpp b/lib/Utils/CommLayerInner.cpp
index b5b8db7..307fe66 100644
--- a/lib/Utils/CommLayerInner.cpp
+++ b/lib/Utils/CommLayerInner.cpp
@@ -10,29 +10,48 @@ static map_uint_str_t s_mapClientID;
static pthread_mutex_t s_map_mutex;
static bool s_map_mutex_inited;
+/* called via [p]error_msg() */
+static void warn_client(const char *msg)
+{
+ if (!s_pObs)
+ return;
+
+ uint64_t key = uint64_t(pthread_self());
+
+ pthread_mutex_lock(&s_map_mutex);
+ map_uint_str_t::const_iterator ki = s_mapClientID.find(key);
+ const char* peer = (ki != s_mapClientID.end() ? ki->second.c_str() : NULL);
+ pthread_mutex_unlock(&s_map_mutex);
+
+ if (peer)
+ s_pObs->Warning(msg, peer, key);
+}
+
void init_daemon_logging(CObserver *pObs)
{
s_pObs = pObs;
if (!s_map_mutex_inited)
{
- pthread_mutex_init(&s_map_mutex, NULL);
s_map_mutex_inited = true;
+ pthread_mutex_init(&s_map_mutex, NULL);
+ g_custom_logger = &warn_client;
}
}
-void set_client_name(const char* name)
+void set_client_name(const char *name)
{
uint64_t key = uint64_t(pthread_self());
pthread_mutex_lock(&s_map_mutex);
- if (!name)
+ if (!name) {
s_mapClientID.erase(key);
- else
+ } else {
s_mapClientID[key] = name;
+ }
pthread_mutex_unlock(&s_map_mutex);
}
-void warn_client(const std::string& pMessage)
+void update_client(const char *fmt, ...)
{
if (!s_pObs)
return;
@@ -44,26 +63,16 @@ void warn_client(const std::string& pMessage)
const char* peer = (ki != s_mapClientID.end() ? ki->second.c_str() : NULL);
pthread_mutex_unlock(&s_map_mutex);
- if (peer)
- s_pObs->Warning(pMessage, peer, key);
- else /* Bug: someone tries to warn_client() without set_client_name()!? */
- log("Hmm, stray %s: '%s'", __func__, pMessage.c_str());
-}
-
-void update_client(const std::string& pMessage)
-{
- if (!s_pObs)
+ if (!peer)
return;
- uint64_t key = uint64_t(pthread_self());
+ va_list p;
+ va_start(p, fmt);
+ char *msg;
+ int used = vasprintf(&msg, fmt, p);
+ va_end(p);
+ if (used < 0)
+ return;
- pthread_mutex_lock(&s_map_mutex);
- map_uint_str_t::const_iterator ki = s_mapClientID.find(key);
- const char* peer = (ki != s_mapClientID.end() ? ki->second.c_str() : NULL);
- pthread_mutex_unlock(&s_map_mutex);
-
- if (peer)
- s_pObs->Status(pMessage, peer, key);
- else
- log("Hmm, stray %s: '%s'", __func__, pMessage.c_str());
+ s_pObs->Status(msg, peer, key);
}
diff --git a/lib/Utils/CommLayerInner.h b/lib/Utils/CommLayerInner.h
index d161cfc..9c22968 100644
--- a/lib/Utils/CommLayerInner.h
+++ b/lib/Utils/CommLayerInner.h
@@ -9,15 +9,19 @@ void init_daemon_logging(CObserver *pObs);
* Set client's name (dbus ID). NULL unsets it.
*/
void set_client_name(const char* name);
-/* Ask a client to warn the user about a non-fatal, but unexpected condition.
+
+/*
+ * Ask a client to warn the user about a non-fatal, but unexpected condition.
* In GUI, it will usually be presented as a popup message.
+ * Usually there is no need to call it directly, just use [p]error_msg().
*/
-void warn_client(const std::string& pMessage);
-/* Logs a message to a client.
+//now static: void warn_client(const char *msg);
+
+/*
+ * Logs a message to a client.
* In UI, it will usually appear as a new status line message in GUI,
* or as a new message line in CLI.
*/
-void update_client(const std::string& pMessage);
-
-#endif /* COMMLAYERINNER_H_ */
+void update_client(const char *fmt, ...);
+#endif
diff --git a/lib/Utils/DBusCommon.h b/lib/Utils/DBusCommon.h
index b3e3af2..2e3ed8a 100644
--- a/lib/Utils/DBusCommon.h
+++ b/lib/Utils/DBusCommon.h
@@ -22,8 +22,8 @@
#include "CrashTypes.h"
-#define CC_DBUS_NAME "com.redhat.abrt"
-#define CC_DBUS_PATH "/com/redhat/abrt"
-#define CC_DBUS_IFACE "com.redhat.abrt"
+#define ABRTD_DBUS_NAME "com.redhat.abrt"
+#define ABRTD_DBUS_PATH "/com/redhat/abrt"
+#define ABRTD_DBUS_IFACE "com.redhat.abrt"
#endif
diff --git a/lib/Utils/DebugDump.cpp b/lib/Utils/DebugDump.cpp
index 43eb324..bf793bb 100644
--- a/lib/Utils/DebugDump.cpp
+++ b/lib/Utils/DebugDump.cpp
@@ -23,45 +23,41 @@
#include <iostream>
#include <sstream>
#include <sys/utsname.h>
-#include <magic.h>
+//#include <magic.h>
#include "abrtlib.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
-/* Is it "." or ".."? */
-/* abrtlib candidate */
-static bool dot_or_dotdot(const char *filename)
-{
- if (filename[0] != '.') return false;
- if (filename[1] == '\0') return true;
- if (filename[1] != '.') return false;
- if (filename[2] == '\0') return true;
- return false;
-}
-
static bool isdigit_str(const char *str)
{
- while (*str)
+ do
{
if (*str < '0' || *str > '9') return false;
str++;
- }
+ } while (*str);
return true;
}
-static std::string RemoveBackSlashes(const std::string& pDir);
+static std::string RemoveBackSlashes(const char *pDir)
+{
+ unsigned len = strlen(pDir);
+ while (len != 0 && pDir[len-1] == '/')
+ len--;
+ return std::string(pDir, len);
+}
+
static bool ExistFileDir(const char* pPath);
-static void LoadTextFile(const std::string& pPath, std::string& pData);
+static void LoadTextFile(const char *pPath, std::string& pData);
CDebugDump::CDebugDump() :
m_sDebugDumpDir(""),
- m_bOpened(false),
m_pGetNextFileDir(NULL),
- m_nLockfileFD(-1)
+ m_bOpened(false),
+ m_bLocked(false)
{}
-void CDebugDump::Open(const std::string& pDir)
+void CDebugDump::Open(const char *pDir)
{
if (m_bOpened)
{
@@ -70,7 +66,7 @@ void CDebugDump::Open(const std::string& pDir)
m_sDebugDumpDir = RemoveBackSlashes(pDir);
if (!ExistFileDir(m_sDebugDumpDir.c_str()))
{
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::CDebugDump(): "+m_sDebugDumpDir+" does not exist.");
+ throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::CDebugDump(): " + m_sDebugDumpDir + " does not exist.");
}
Lock();
m_bOpened = true;
@@ -96,10 +92,49 @@ static bool ExistFileDir(const char* pPath)
return false;
}
-static int GetAndSetLock(const char* pLockFile, const char* pPID)
+static bool GetAndSetLock(const char* pLockFile, const char* pPID)
{
- int fd;
+ while (symlink(pPID, pLockFile) != 0)
+ {
+ if (errno != EEXIST)
+ perror_msg_and_die("Can't create lock file '%s'", pLockFile);
+ char pid_buf[sizeof(pid_t)*3 + 4];
+ ssize_t r = readlink(pLockFile, pid_buf, sizeof(pid_buf) - 1);
+ if (r < 0)
+ perror_msg_and_die("Can't read lock file '%s'", pLockFile);
+ pid_buf[r] = '\0';
+
+ if (strcmp(pid_buf, pPID) == 0)
+ {
+ log("Lock file '%s' is already locked by us", pLockFile);
+ return false;
+ }
+ if (isdigit_str(pid_buf))
+ {
+ if (access(ssprintf("/proc/%s", pid_buf).c_str(), F_OK) == 0)
+ {
+ log("Lock file '%s' is locked by process %s", pLockFile, pid_buf);
+ return false;
+ }
+ log("Lock file '%s' was locked by process %s, but it crashed?", pLockFile, pid_buf);
+ }
+ /* The file may be deleted by now by other process. Ignore ENOENT */
+ if (unlink(pLockFile) != 0 && errno != ENOENT)
+ {
+ perror_msg_and_die("Can't remove stale lock file '%s'", pLockFile);
+ }
+ }
+
+ VERB1 log("Locked '%s'", pLockFile);
+ return true;
+
+#if 0
+/* Old code was using ordinary files instead of symlinks,
+ * but it had a race window between open and write, during which file was
+ * empty. It was seen to happen in practice.
+ */
+ int fd;
while ((fd = open(pLockFile, O_WRONLY | O_CREAT | O_EXCL, 0640)) < 0)
{
if (errno != EEXIST)
@@ -148,20 +183,22 @@ static int GetAndSetLock(const char* pLockFile, const char* pPID)
/* close(fd); - not needed, exiting does it too */
perror_msg_and_die("Can't write lock file '%s'", pLockFile);
}
+ close(fd);
VERB1 log("Locked '%s'", pLockFile);
- return fd;
+ return true;
+#endif
}
void CDebugDump::Lock()
{
- if (m_nLockfileFD >= 0)
+ if (m_bLocked)
error_msg_and_die("Locking bug on '%s'", m_sDebugDumpDir.c_str());
std::string lockFile = m_sDebugDumpDir + ".lock";
char pid_buf[sizeof(int)*3 + 2];
sprintf(pid_buf, "%u", (unsigned)getpid());
- while ((m_nLockfileFD = GetAndSetLock(lockFile.c_str(), pid_buf)) < 0)
+ while ((m_bLocked = GetAndSetLock(lockFile.c_str(), pid_buf)) != true)
{
usleep(500000);
}
@@ -169,27 +206,26 @@ void CDebugDump::Lock()
void CDebugDump::UnLock()
{
- if (m_nLockfileFD >= 0)
+ if (m_bLocked)
{
+ m_bLocked = false;
std::string lockFile = m_sDebugDumpDir + ".lock";
- close(m_nLockfileFD);
- m_nLockfileFD = -1;
xunlink(lockFile.c_str());
VERB1 log("UnLocked '%s'", lockFile.c_str());
}
}
-void CDebugDump::Create(const std::string& pDir, uid_t uid)
+void CDebugDump::Create(const char *pDir, int64_t uid)
{
if (m_bOpened)
{
- throw CABRTException(EXCEP_ERROR, "CDebugDump::CDebugDump(): DebugDump is already opened.");
+ throw CABRTException(EXCEP_ERROR, "DebugDump is already opened");
}
m_sDebugDumpDir = RemoveBackSlashes(pDir);
if (ExistFileDir(m_sDebugDumpDir.c_str()))
{
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::CDebugDump(): "+m_sDebugDumpDir+" already exists.");
+ throw CABRTException(EXCEP_DD_OPEN, ssprintf("'%s' already exists", m_sDebugDumpDir.c_str()));
}
Lock();
@@ -199,13 +235,13 @@ void CDebugDump::Create(const std::string& pDir, uid_t uid)
{
UnLock();
m_bOpened = false;
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::Create(): Cannot create dir: " + pDir);
+ throw CABRTException(EXCEP_DD_OPEN, ssprintf("Can't create dir '%s'", pDir));
}
if (chmod(m_sDebugDumpDir.c_str(), 0700) == -1)
{
UnLock();
m_bOpened = false;
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::Create(): Cannot change permissions, dir: " + pDir);
+ throw CABRTException(EXCEP_DD_OPEN, ssprintf("Can't change mode of '%s'", pDir));
}
struct passwd* pw = getpwuid(uid);
gid_t gid = pw ? pw->pw_gid : uid;
@@ -216,14 +252,15 @@ void CDebugDump::Create(const std::string& pDir, uid_t uid)
perror_msg("can't change '%s' ownership to %u:%u", m_sDebugDumpDir.c_str(), (int)uid, (int)gid);
}
- SaveText(FILENAME_UID, ssprintf("%u", (int)uid));
+ SaveText(FILENAME_UID, to_string(uid).c_str());
SaveKernelArchitectureRelease();
- SaveTime();
+ time_t t = time(NULL);
+ SaveText(FILENAME_TIME, to_string(t).c_str());
}
-static void DeleteFileDir(const std::string& pDir)
+static void DeleteFileDir(const char *pDir)
{
- DIR *dir = opendir(pDir.c_str());
+ DIR *dir = opendir(pDir);
if (!dir)
return;
@@ -232,26 +269,28 @@ static void DeleteFileDir(const std::string& pDir)
{
if (dot_or_dotdot(dent->d_name))
continue;
- std::string fullPath = pDir + "/" + dent->d_name;
+ std::string fullPath = concat_path_file(pDir, dent->d_name);
if (unlink(fullPath.c_str()) == -1)
{
if (errno != EISDIR)
{
closedir(dir);
- throw CABRTException(EXCEP_DD_DELETE, std::string(__func__) + ": Cannot remove file: " + fullPath);
+ throw CABRTException(EXCEP_DD_DELETE, ssprintf("Can't remove dir %s", fullPath.c_str()));
}
- DeleteFileDir(fullPath);
+ DeleteFileDir(fullPath.c_str());
}
}
closedir(dir);
- if (remove(pDir.c_str()) == -1)
+ if (remove(pDir) == -1)
{
- throw CABRTException(EXCEP_DD_DELETE, std::string(__func__) + ": Cannot remove dir: " + pDir);
+ throw CABRTException(EXCEP_DD_DELETE, ssprintf("Can't remove dir %s", pDir));
}
}
-static bool IsTextFile(const std::string& pName)
+static bool IsTextFile(const char *name)
{
+/* This idiotic library thinks that file containing just "0" is not text (!!)
+
magic_t m = magic_open(MAGIC_MIME_TYPE);
if (m == NULL)
@@ -280,16 +319,24 @@ static bool IsTextFile(const std::string& pName)
magic_close(m);
return isText;
-}
+ */
+ int fd = open(name, O_RDONLY);
+ if (fd < 0)
+ return false;
-static std::string RemoveBackSlashes(const std::string& pDir)
-{
- std::string ret = pDir;
- while (ret[ret.length() - 1] == '/')
+ unsigned char buf[4*1024];
+ int r = full_read(fd, buf, sizeof(buf));
+ close(fd);
+
+ while (--r >= 0)
{
- ret = ret.substr(0, ret.length() - 2);
+ if (buf[r] >= 0x7f)
+ return false;
+ /* Among control chars, only '\t','\n' etc are allowed */
+ if (buf[r] < ' ' && !isspace(buf[r]))
+ return false;
}
- return ret;
+ return true;
}
void CDebugDump::Delete()
@@ -298,7 +345,7 @@ void CDebugDump::Delete()
{
return;
}
- DeleteFileDir(m_sDebugDumpDir);
+ DeleteFileDir(m_sDebugDumpDir.c_str());
}
void CDebugDump::Close()
@@ -322,100 +369,47 @@ void CDebugDump::SaveKernelArchitectureRelease()
}
std::string release;
LoadTextFile("/etc/redhat-release", release);
- SaveText(FILENAME_RELEASE, release);
+ const char *release_ptr = release.c_str();
+ unsigned len_1st_str = strchrnul(release_ptr, '\n') - release_ptr;
+ release.erase(len_1st_str); /* usually simply removes trailing '\n' */
+ SaveText(FILENAME_RELEASE, release.c_str());
}
-void CDebugDump::SaveTime()
+static void LoadTextFile(const char *pPath, std::string& pData)
{
- time_t t = time(NULL);
- SaveText(FILENAME_TIME, to_string(t));
-}
-
-static void LoadTextFile(const std::string& pPath, std::string& pData)
-{
- std::ifstream fIn;
+ FILE *fp = fopen(pPath, "r");
+ if (!fp)
+ {
+ throw CABRTException(EXCEP_DD_LOAD, ssprintf("Can't open file '%s'", pPath));
+ }
pData = "";
- fIn.open(pPath.c_str());
- if (fIn.is_open())
+ int ch;
+ while ((ch = fgetc(fp)) != EOF)
{
- // TODO: rewrite this
- int ch;
- while ((ch = fIn.get())!= EOF)
+ if (ch == '\0')
{
- if (ch == 0)
- {
- pData += " ";
- }
- else if (isspace(ch) || (isascii(ch) && !iscntrl(ch)))
- {
- pData += ch;
- }
+ pData += ' ';
}
- fIn.close();
- }
- else
- {
- throw CABRTException(EXCEP_DD_LOAD, std::string(__func__) + ": Cannot open file " + pPath);
- }
-}
-
-static void LoadBinaryFile(const std::string& pPath, char** pData, unsigned int* pSize)
-{
- std::ifstream fIn;
- fIn.open(pPath.c_str(), std::ios::binary | std::ios::ate);
- unsigned int size;
- if (fIn.is_open())
- {
- size = fIn.tellg();
- char *data = new char [size];
- fIn.read(data, size);
-
- *pData = data;
- *pSize = size;
-
- fIn.close();
- }
- else
- {
- throw CABRTException(EXCEP_DD_LOAD, std::string(__func__) + ": Cannot open file " + pPath);
- }
-}
-
-static void SaveTextFile(const std::string& pPath, const std::string& pData)
-{
- std::ofstream fOut;
- fOut.open(pPath.c_str());
- if (fOut.is_open())
- {
- fOut << pData;
- if (!fOut.good())
+ else if (isspace(ch) || (isascii(ch) && !iscntrl(ch)))
{
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot save file " + pPath);
+ pData += ch;
}
- fOut.close();
- }
- else
- {
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot open file " + pPath);
}
+ fclose(fp);
}
-static void SaveBinaryFile(const std::string& pPath, const char* pData, const unsigned pSize)
+static void SaveBinaryFile(const char *pPath, const char* pData, unsigned pSize)
{
- std::ofstream fOut;
- fOut.open(pPath.c_str(), std::ios::binary);
- if (fOut.is_open())
+ int fd = open(pPath, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (fd < 0)
{
- fOut.write(pData, pSize);
- if (!fOut.good())
- {
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot save file " + pPath);
- }
- fOut.close();
+ throw CABRTException(EXCEP_DD_SAVE, ssprintf("Can't open file '%s'", pPath));
}
- else
+ unsigned r = full_write(fd, pData, pSize);
+ close(fd);
+ if (r != pSize)
{
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot open file " + pPath);
+ throw CABRTException(EXCEP_DD_SAVE, ssprintf("Can't save file '%s'", pPath));
}
}
@@ -425,36 +419,27 @@ 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;
- LoadTextFile(fullPath, pData);
-}
-void CDebugDump::LoadBinary(const char* pName, char** pData, unsigned int* pSize)
-{
- if (!m_bOpened)
- {
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::LoadBinary(): DebugDump is not opened.");
- }
- std::string fullPath = m_sDebugDumpDir + "/" + pName;
- LoadBinaryFile(fullPath, pData, pSize);
+ std::string fullPath = m_sDebugDumpDir + '/' + pName;
+ LoadTextFile(fullPath.c_str(), pData);
}
-void CDebugDump::SaveText(const char* pName, const std::string& pData)
+void CDebugDump::SaveText(const char* pName, const char* pData)
{
if (!m_bOpened)
{
throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::SaveText(): DebugDump is not opened.");
}
std::string fullPath = m_sDebugDumpDir + "/" + pName;
- SaveTextFile(fullPath, pData);
+ SaveBinaryFile(fullPath.c_str(), pData, strlen(pData));
}
-void CDebugDump::SaveBinary(const char* pName, const char* pData, const unsigned int pSize)
+void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize)
{
if (!m_bOpened)
{
throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::SaveBinary(): DebugDump is not opened.");
}
std::string fullPath = m_sDebugDumpDir + "/" + pName;
- SaveBinaryFile(fullPath, pData, pSize);
+ SaveBinaryFile(fullPath.c_str(), pData, pSize);
}
void CDebugDump::InitGetNextFile()
@@ -486,17 +471,17 @@ bool CDebugDump::GetNextFile(std::string& pFileName, std::string& pContent, bool
{
if (is_regular_file(dent, m_sDebugDumpDir.c_str()))
{
- std::string fullname = m_sDebugDumpDir + "/" + dent->d_name;
+ std::string fullname = m_sDebugDumpDir + '/' + dent->d_name;
pFileName = dent->d_name;
- if (IsTextFile(fullname))
+ if (IsTextFile(fullname.c_str()))
{
LoadText(dent->d_name, pContent);
pIsTextFile = true;
}
else
{
- pContent = "";
+ pContent.clear();
pIsTextFile = false;
}
return true;
@@ -506,4 +491,3 @@ bool CDebugDump::GetNextFile(std::string& pFileName, std::string& pContent, bool
m_pGetNextFileDir = NULL;
return false;
}
-
diff --git a/lib/Utils/DebugDump.h b/lib/Utils/DebugDump.h
index d6ff4f9..b48a386 100644
--- a/lib/Utils/DebugDump.h
+++ b/lib/Utils/DebugDump.h
@@ -25,6 +25,7 @@
#include <string>
#include <dirent.h>
+#include <stdint.h>
#define FILENAME_ARCHITECTURE "architecture"
#define FILENAME_KERNEL "kernel"
@@ -39,17 +40,17 @@
#define FILENAME_REASON "reason"
#define FILENAME_COMMENT "comment"
#define FILENAME_REPRODUCE "reproduce"
+#define FILENAME_RATING "rating"
class CDebugDump
{
private:
std::string m_sDebugDumpDir;
- bool m_bOpened;
DIR* m_pGetNextFileDir;
- int m_nLockfileFD;
+ bool m_bOpened;
+ bool m_bLocked;
void SaveKernelArchitectureRelease();
- void SaveTime();
void Lock();
void UnLock();
@@ -58,18 +59,17 @@ class CDebugDump
CDebugDump();
~CDebugDump() { Close(); }
- void Open(const std::string& pDir);
- void Create(const std::string& pDir, uid_t nUID);
+ void Open(const char *pDir);
+ void Create(const char *pDir, int64_t uid);
void Delete();
void Close();
bool Exist(const char* pFileName);
void LoadText(const char* pName, std::string& pData);
- void LoadBinary(const char* pName, char** pData, unsigned int* pSize);
- void SaveText(const char* pName, const std::string& pData);
- void SaveBinary(const char* pName, const char* pData, const unsigned int pSize);
+ void SaveText(const char* pName, const char *pData);
+ void SaveBinary(const char* pName, const char* pData, unsigned pSize);
void InitGetNextFile();
bool GetNextFile(std::string& pFileName, std::string& pContent, bool& pIsTextFile);
diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am
index 713fe86..68c925f 100644
--- a/lib/Utils/Makefile.am
+++ b/lib/Utils/Makefile.am
@@ -1,15 +1,21 @@
lib_LTLIBRARIES = libABRTUtils.la
+# Not used just yet:
+# time.cpp
+# xconnect.cpp
+
libABRTUtils_la_SOURCES = \
xfuncs.cpp \
+ encbase64.cpp \
read_write.cpp \
logging.cpp \
copyfd.cpp \
+ skip_whitespace.cpp \
CrashTypesSocket.cpp \
DebugDump.h DebugDump.cpp \
CommLayerInner.h CommLayerInner.cpp \
abrt_dbus.h abrt_dbus.cpp \
- Plugin.h Plugin.cpp \
+ Plugin.h Plugin.cpp make_descr.cpp \
Polkit.h Polkit.cpp \
Action.h Database.h Reporter.h Analyzer.h \
Observer.h \
@@ -31,7 +37,6 @@ libABRTUtils_la_LDFLAGS = \
$(DL_LIBS) \
$(DBUS_LIBS)
libABRTUtils_la_LIBADD = \
- -lmagic \
$(POLKIT_LIBS)
install-data-local:
diff --git a/lib/Utils/Observer.h b/lib/Utils/Observer.h
index d6ec6f3..db74865 100644
--- a/lib/Utils/Observer.h
+++ b/lib/Utils/Observer.h
@@ -8,8 +8,8 @@
class CObserver {
public:
virtual ~CObserver() {}
- virtual void Status(const std::string& pMessage, const char* peer, uint64_t pDest) = 0;
- virtual void Warning(const std::string& pMessage, const char* peer, uint64_t pDest) = 0;
+ virtual void Status(const char *pMessage, const char* peer, uint64_t pDest) = 0;
+ virtual void Warning(const char *pMessage, const char* peer, uint64_t pDest) = 0;
};
#endif
diff --git a/lib/Utils/Plugin.cpp b/lib/Utils/Plugin.cpp
index 161ead8..4d561b4 100644
--- a/lib/Utils/Plugin.cpp
+++ b/lib/Utils/Plugin.cpp
@@ -19,9 +19,18 @@
#include "Plugin.h"
+CPlugin::CPlugin() {}
+
/* class CPlugin's virtuals */
CPlugin::~CPlugin() {}
void CPlugin::Init() {}
void CPlugin::DeInit() {}
-void CPlugin::SetSettings(const map_plugin_settings_t& pSettings) {}
-map_plugin_settings_t CPlugin::GetSettings() {return map_plugin_settings_t();}
+void CPlugin::SetSettings(const map_plugin_settings_t& pSettings)
+{
+ m_pSettings = pSettings;
+}
+
+const map_plugin_settings_t& CPlugin::GetSettings()
+{
+ return m_pSettings;
+}
diff --git a/lib/Utils/Plugin.h b/lib/Utils/Plugin.h
index 3929023..f93f7e7 100644
--- a/lib/Utils/Plugin.h
+++ b/lib/Utils/Plugin.h
@@ -24,17 +24,10 @@
#define PLUGIN_H_
#include "abrt_types.h"
-
-#define PLUGINS_MAGIC_NUMBER 6
-
-#define PLUGINS_CONF_EXTENSION "conf"
-#define PLUGINS_LIB_EXTENSION "so"
-#define PLUGINS_LIB_PREFIX "lib"
-
+#include "CrashTypes.h"
#if HAVE_CONFIG_H
#include <config.h>
#endif
-
#if ENABLE_NLS
#include <libintl.h>
#define _(S) gettext(S)
@@ -42,13 +35,23 @@
#define _(S) (S)
#endif
+#define PLUGINS_MAGIC_NUMBER 6
+
+#define PLUGINS_CONF_EXTENSION "conf"
+#define PLUGINS_LIB_EXTENSION "so"
+#define PLUGINS_LIB_PREFIX "lib"
+
/**
* An abstract class. The class defines a common plugin interface. If a plugin
* has some settings, then a *Settings(*) method has to be written.
*/
class CPlugin
{
+ protected:
+ map_plugin_settings_t m_pSettings;
+
public:
+ CPlugin();
/**
* A destructor.
*/
@@ -70,7 +73,7 @@ class CPlugin
* A method, which return current settings. It is not mandatory method.
* @return Plugin's settings
*/
- virtual map_plugin_settings_t GetSettings();
+ virtual const map_plugin_settings_t& GetSettings();
};
/**
@@ -115,4 +118,8 @@ typedef struct SPluginInfo
PLUGINS_MAGIC_NUMBER,\
};
-#endif /* PLUGIN_H_ */
+/* helper finctions */
+std::string make_description_bz(const map_crash_report_t& pCrashReport);
+std::string make_description_logger(const map_crash_report_t& pCrashReport);
+
+#endif
diff --git a/lib/Utils/Reporter.h b/lib/Utils/Reporter.h
index c74a10c..f278899 100644
--- a/lib/Utils/Reporter.h
+++ b/lib/Utils/Reporter.h
@@ -41,6 +41,7 @@ class CReporter : public CPlugin
* @retun A message which can be displayed after a report is created.
*/
virtual std::string Report(const map_crash_report_t& pCrashReport,
+ const map_plugin_settings_t& pSettings,
const std::string& pArgs) = 0;
};
diff --git a/lib/Utils/copyfd.cpp b/lib/Utils/copyfd.cpp
index cda52b0..9abe752 100644
--- a/lib/Utils/copyfd.cpp
+++ b/lib/Utils/copyfd.cpp
@@ -105,3 +105,25 @@ off_t copyfd_eof(int fd1, int fd2)
{
return full_fd_action(fd1, fd2, 0);
}
+
+off_t copy_file(const char *src_name, const char *dst_name)
+{
+ off_t r;
+ int src = open(src_name, O_RDONLY);
+ if (src < 0)
+ {
+ perror_msg("Can't open '%s'", src_name);
+ return -1;
+ }
+ int dst = open(dst_name, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (dst < 0)
+ {
+ close(src);
+ perror_msg("Can't open '%s'", dst_name);
+ return -1;
+ }
+ r = copyfd_eof(src, dst);
+ close(src);
+ close(dst);
+ return r;
+}
diff --git a/lib/Utils/encbase64.cpp b/lib/Utils/encbase64.cpp
new file mode 100644
index 0000000..6a6f1f7
--- /dev/null
+++ b/lib/Utils/encbase64.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2006 Rob Landley <rob@landley.net>
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include "abrtlib.h" /* xmalloc */
+
+/* Conversion table for base 64 */
+static const char tbl_base64[65 /*+ 2*/] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/',
+ '=' /* termination character */,
+ // '\n', '\0' /* needed for uudecode.c */
+};
+
+/* Conversion table for uuencode
+const char tbl_uuencode[65] ALIGN1 = {
+ '`', '!', '"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', ':', ';', '<', '=', '>', '?',
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
+ '`'
+};
+*/
+
+/*
+ * Encode bytes at S of length LENGTH.
+ * Result will be 0-terminated, and must point to a writable
+ * buffer of at least 1+BASE64_LENGTH(length) bytes,
+ * where BASE64_LENGTH(len) = 4 * ((LENGTH + 2) / 3)
+ */
+static void encode_64bit(char *p, const void *src, int length, const char *tbl)
+{
+ const unsigned char *s = (const unsigned char *)src;
+
+ /* Transform the 3x8 bits to 4x6 bits */
+ while (length > 0) {
+ unsigned s1, s2;
+
+ /* Are s[1], s[2] valid or should be assumed 0? */
+ s1 = s2 = 0;
+ length -= 3; /* can be >=0, -1, -2 */
+ if (length >= -1) {
+ s1 = s[1];
+ if (length >= 0)
+ s2 = s[2];
+ }
+ *p++ = tbl[s[0] >> 2];
+ *p++ = tbl[((s[0] & 3) << 4) + (s1 >> 4)];
+ *p++ = tbl[((s1 & 0xf) << 2) + (s2 >> 6)];
+ *p++ = tbl[s2 & 0x3f];
+ s += 3;
+ }
+ /* Zero-terminate */
+ *p = '\0';
+ /* If length is -2 or -1, pad last char or two */
+ while (length) {
+ *--p = tbl[64];
+ length++;
+ }
+}
+
+char *encode_base64(const void *src, int length)
+{
+ char *dst = (char *)xmalloc(4 * ((length + 2) / 3) + 1);
+ encode_64bit(dst, src, length, tbl_base64);
+ return dst;
+}
diff --git a/lib/Utils/logging.cpp b/lib/Utils/logging.cpp
index f70d23f..cae609b 100644
--- a/lib/Utils/logging.cpp
+++ b/lib/Utils/logging.cpp
@@ -7,19 +7,18 @@
#include <syslog.h>
int xfunc_error_retval = EXIT_FAILURE;
-
int g_verbose;
+int logmode = LOGMODE_STDIO;
+const char *msg_prefix = "";
+const char *msg_eol = "\n";
+void (*g_custom_logger)(const char*);
void xfunc_die(void)
{
exit(xfunc_error_retval);
}
-const char *msg_prefix = "";
-const char *msg_eol = "\n";
-int logmode = LOGMODE_STDIO;
-
-void verror_msg(const char *s, va_list p, const char* strerr)
+static void verror_msg_helper(const char *s, va_list p, const char* strerr, int flags)
{
char *msg;
int prefix_len, strerr_len, msgeol_len, used;
@@ -27,9 +26,6 @@ void verror_msg(const char *s, va_list p, const char* strerr)
if (!logmode)
return;
- if (!s) /* nomsg[_and_die] uses NULL fmt */
- s = ""; /* some libc don't like printf(NULL) */
-
used = vasprintf(&msg, s, p);
if (used < 0)
return;
@@ -51,7 +47,7 @@ void verror_msg(const char *s, va_list p, const char* strerr)
memcpy(msg, msg_prefix, prefix_len);
}
if (strerr) {
- if (s[0]) { /* not perror_nomsg? */
+ if (s[0]) {
msg[used++] = ':';
msg[used++] = ' ';
}
@@ -60,24 +56,26 @@ void verror_msg(const char *s, va_list p, const char* strerr)
}
strcpy(&msg[used], msg_eol);
- if (logmode & LOGMODE_STDIO) {
+ if (flags & LOGMODE_STDIO) {
fflush(stdout);
full_write(STDERR_FILENO, msg, used + msgeol_len);
}
- if (logmode & LOGMODE_SYSLOG) {
+ if (flags & LOGMODE_SYSLOG) {
syslog(LOG_ERR, "%s", msg + prefix_len);
}
+ if ((flags & LOGMODE_CUSTOM) && g_custom_logger) {
+ g_custom_logger(msg + prefix_len);
+ }
free(msg);
}
-void error_msg_and_die(const char *s, ...)
+void log_msg(const char *s, ...)
{
va_list p;
va_start(p, s);
- verror_msg(s, p, NULL);
+ verror_msg_helper(s, p, NULL, logmode);
va_end(p);
- xfunc_die();
}
void error_msg(const char *s, ...)
@@ -85,8 +83,18 @@ void error_msg(const char *s, ...)
va_list p;
va_start(p, s);
- verror_msg(s, p, NULL);
+ verror_msg_helper(s, p, NULL, (logmode | LOGMODE_CUSTOM));
+ va_end(p);
+}
+
+void error_msg_and_die(const char *s, ...)
+{
+ va_list p;
+
+ va_start(p, s);
+ verror_msg_helper(s, p, NULL, (logmode | LOGMODE_CUSTOM));
va_end(p);
+ xfunc_die();
}
void perror_msg_and_die(const char *s, ...)
@@ -95,7 +103,7 @@ void perror_msg_and_die(const char *s, ...)
va_start(p, s);
/* Guard against "<error message>: Success" */
- verror_msg(s, p, errno ? strerror(errno) : NULL);
+ verror_msg_helper(s, p, errno ? strerror(errno) : NULL, (logmode | LOGMODE_CUSTOM));
va_end(p);
xfunc_die();
}
@@ -106,7 +114,7 @@ void perror_msg(const char *s, ...)
va_start(p, s);
/* Guard against "<error message>: Success" */
- verror_msg(s, p, errno ? strerror(errno) : NULL);
+ verror_msg_helper(s, p, errno ? strerror(errno) : NULL, (logmode | LOGMODE_CUSTOM));
va_end(p);
}
@@ -122,5 +130,5 @@ void simple_perror_msg(const char *s)
void die_out_of_memory(void)
{
- error_msg_and_die("Out of memory, exiting");
+ error_msg_and_die("Out of memory, exiting");
}
diff --git a/lib/Utils/make_descr.cpp b/lib/Utils/make_descr.cpp
new file mode 100644
index 0000000..1352149
--- /dev/null
+++ b/lib/Utils/make_descr.cpp
@@ -0,0 +1,133 @@
+#include "abrtlib.h"
+//#include "abrt_types.h"
+#include "CrashTypes.h"
+#include "DebugDump.h" /* FILENAME_ARCHITECTURE etc */
+
+using namespace std;
+
+static void add_content(bool &was_multiline, string& description, const char *header, const char *content)
+{
+ /* We separate multiline contents with emply line */
+ if (was_multiline)
+ description += '\n';
+
+ while (content[0] == '\n')
+ content++;
+
+ if (strchr(content, '\n') == NULL)
+ {
+ if (skip_whitespace(content)[0] == '\0')
+ {
+ /* empty, dont report at all */
+ return;
+ }
+ /* one string value, like OS release */
+ description += header;
+ description += ": ";
+ description += content;
+ description += '\n';
+ was_multiline = 0;
+ }
+ else
+ {
+ /* multi-string value, like backtrace */
+ if (!was_multiline && description.size() != 0) /* if wasn't yet separated */
+ description += '\n'; /* do it now */
+ description += header;
+ description += "\n-----\n";
+ description += content;
+ if (content[strlen(content) - 1] != '\n')
+ description += '\n';
+ was_multiline = 1;
+ }
+}
+
+string make_description_bz(const map_crash_report_t& pCrashReport)
+{
+ string description;
+
+ map_crash_report_t::const_iterator it;
+ map_crash_report_t::const_iterator end = pCrashReport.end();
+
+ bool was_multiline = 0;
+ it = pCrashReport.find(CD_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 = pCrashReport.find(CD_COMMENT);
+ if (it != end)
+ {
+ add_content(was_multiline, description, "Comment", it->second[CD_CONTENT].c_str());
+ }
+
+ it = pCrashReport.begin();
+ for (; it != end; it++)
+ {
+ const string &filename = it->first;
+ const string &type = it->second[CD_TYPE];
+ const string &content = it->second[CD_CONTENT];
+ if (type == CD_TXT)
+ {
+ if (filename != CD_UUID
+ && filename != FILENAME_ARCHITECTURE
+ && filename != FILENAME_RELEASE
+ && filename != CD_REPRODUCE
+ && filename != CD_COMMENT
+ ) {
+ add_content(was_multiline, description, filename.c_str(), content.c_str());
+ }
+ }
+ else if (type == CD_ATT)
+ {
+ add_content(was_multiline, description, "Attached file", filename.c_str());
+ }
+ }
+
+ return description;
+}
+
+string make_description_logger(const map_crash_report_t& pCrashReport)
+{
+ string description;
+ string long_description;
+
+ map_crash_report_t::const_iterator it = pCrashReport.begin();
+ for (; it != pCrashReport.end(); it++)
+ {
+ const string &filename = it->first;
+ const string &type = it->second[CD_TYPE];
+ const string &content = it->second[CD_CONTENT];
+ if (type == CD_TXT
+ || type == CD_ATT
+ || type == CD_BIN
+ ) {
+ if (content == "1.\n2.\n3.\n")
+ continue; /* user did not change default "How to reproduce" */
+
+ bool was_multiline = 0;
+ string tmp;
+ add_content(was_multiline, tmp, filename.c_str(), content.c_str());
+
+ if (was_multiline)
+ {
+ if (long_description.size() != 0)
+ long_description += '\n';
+ long_description += tmp;
+ }
+ else
+ {
+ description += tmp;
+ }
+ }
+ }
+
+ if (description.size() != 0 && long_description.size() != 0)
+ {
+ description += '\n';
+ description += long_description;
+ }
+
+ return description;
+}
diff --git a/lib/Utils/skip_whitespace.cpp b/lib/Utils/skip_whitespace.cpp
new file mode 100644
index 0000000..816928b
--- /dev/null
+++ b/lib/Utils/skip_whitespace.cpp
@@ -0,0 +1,22 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "abrtlib.h"
+
+char* skip_whitespace(const char *s)
+{
+ /* NB: isspace('\0') returns 0 */
+ while (isspace(*s)) ++s;
+
+ return (char *) s;
+}
+
+char* skip_non_whitespace(const char *s)
+{
+ while (*s && !isspace(*s)) ++s;
+
+ return (char *) s;
+}
diff --git a/lib/Utils/time.cpp b/lib/Utils/time.cpp
new file mode 100644
index 0000000..37ade2c
--- /dev/null
+++ b/lib/Utils/time.cpp
@@ -0,0 +1,65 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ */
+#include "abrtlib.h"
+
+#define ENABLE_MONOTONIC_SYSCALL 1
+
+#if ENABLE_MONOTONIC_SYSCALL
+
+#include <sys/syscall.h>
+/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
+ * directly so this definition is safe. */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+
+/* libc has incredibly messy way of doing this,
+ * typically requiring -lrt. We just skip all this mess */
+static void get_mono(struct timespec *ts)
+{
+ if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts))
+ error_msg_and_die("clock_gettime(MONOTONIC) failed");
+}
+unsigned long long monotonic_ns(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+}
+unsigned long long monotonic_us(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec * 1000000ULL + ts.tv_nsec/1000;
+}
+unsigned monotonic_sec(void)
+{
+ struct timespec ts;
+ get_mono(&ts);
+ return ts.tv_sec;
+}
+
+#else
+
+unsigned long long monotonic_ns(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
+}
+unsigned long long monotonic_us(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000ULL + tv.tv_usec;
+}
+unsigned monotonic_sec(void)
+{
+ return time(NULL);
+}
+
+#endif
diff --git a/lib/Utils/xconnect.cpp b/lib/Utils/xconnect.cpp
new file mode 100644
index 0000000..746edd6
--- /dev/null
+++ b/lib/Utils/xconnect.cpp
@@ -0,0 +1,416 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Connect to host at port using address resolution from getaddrinfo
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include "abrtlib.h"
+#include <sys/socket.h> /* netinet/in.h needs it */
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/un.h>
+#include <netdb.h>
+
+#define ENABLE_FEATURE_IPV6 1
+#define ENABLE_FEATURE_PREFER_IPV4_ADDRESS 1
+
+static const int const_int_1 = 1;
+
+void setsockopt_reuseaddr(int fd)
+{
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
+}
+int setsockopt_broadcast(int fd)
+{
+ return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
+}
+int setsockopt_bindtodevice(int fd, const char *iface)
+{
+ int r;
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+ /* NB: passing (iface, strlen(iface) + 1) does not work!
+ * (maybe it works on _some_ kernels, but not on 2.6.26)
+ * Actually, ifr_name is at offset 0, and in practice
+ * just giving char[IFNAMSIZ] instead of struct ifreq works too.
+ * But just in case it's not true on some obscure arch... */
+ r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
+ if (r)
+ perror_msg("can't bind to interface %s", iface);
+ return r;
+}
+
+len_and_sockaddr* get_sock_lsa(int fd)
+{
+ len_and_sockaddr lsa;
+ len_and_sockaddr *lsa_ptr;
+
+ lsa.len = LSA_SIZEOF_SA;
+ if (getsockname(fd, &lsa.u.sa, &lsa.len) != 0)
+ return NULL;
+
+ lsa_ptr = (len_and_sockaddr *)xzalloc(LSA_LEN_SIZE + lsa.len);
+ if (lsa.len > LSA_SIZEOF_SA) { /* rarely (if ever) happens */
+ lsa_ptr->len = lsa.len;
+ getsockname(fd, &lsa_ptr->u.sa, &lsa_ptr->len);
+ } else {
+ memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len);
+ }
+ return lsa_ptr;
+}
+
+void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
+{
+ if (connect(s, s_addr, addrlen) < 0) {
+ close(s);
+ if (s_addr->sa_family == AF_INET)
+ perror_msg_and_die("%s (%s)",
+ "cannot connect to remote host",
+ inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
+ perror_msg_and_die("cannot connect to remote host");
+ }
+}
+
+/* Return port number for a service.
+ * If "port" is a number use it as the port.
+ * If "port" is a name it is looked up in /etc/services,
+ * if it isnt found return default_port
+ */
+unsigned lookup_port(const char *port, const char *protocol, unsigned default_port)
+{
+ unsigned port_nr = default_port;
+ if (port) {
+ int old_errno;
+ char *end;
+
+ /* Since this is a lib function, we're not allowed to reset errno to 0.
+ * Doing so could break an app that is deferring checking of errno. */
+ old_errno = errno;
+ errno = 0;
+ port_nr = strtoul(port, &end, 10);
+ if (errno || *end || port_nr > 65535) {
+ struct servent *tserv = getservbyname(port, protocol);
+ port_nr = default_port;
+ if (tserv)
+ port_nr = ntohs(tserv->s_port);
+ }
+ errno = old_errno;
+ }
+ return (uint16_t)port_nr;
+}
+
+int get_nport(const struct sockaddr *sa)
+{
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ return ((struct sockaddr_in6*)sa)->sin6_port;
+ }
+#endif
+ if (sa->sa_family == AF_INET) {
+ return ((struct sockaddr_in*)sa)->sin_port;
+ }
+ /* What? UNIX socket? IPX?? :) */
+ return -1;
+}
+
+void set_nport(len_and_sockaddr *lsa, unsigned port)
+{
+#if ENABLE_FEATURE_IPV6
+ if (lsa->u.sa.sa_family == AF_INET6) {
+ lsa->u.sin6.sin6_port = port;
+ return;
+ }
+#endif
+ if (lsa->u.sa.sa_family == AF_INET) {
+ lsa->u.sin.sin_port = port;
+ return;
+ }
+ /* What? UNIX socket? IPX?? :) */
+}
+
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will remove this bit anyway */
+#define DIE_ON_ERROR AI_CANONNAME
+
+/* host: "1.2.3.4[:port]", "www.google.com[:port]"
+ * port: if neither of above specifies port # */
+static len_and_sockaddr* str2sockaddr(
+ const char *host, int port,
+ sa_family_t af,
+ int ai_flags)
+{
+ int rc;
+ len_and_sockaddr *r;
+ struct addrinfo *result = NULL;
+ struct addrinfo *used_res;
+ const char *org_host = host; /* only for error msg */
+ const char *cp;
+ struct addrinfo hint;
+
+ r = NULL;
+
+ /* Ugly parsing of host:addr */
+ if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
+ /* Even uglier parsing of [xx]:nn */
+ host++;
+ cp = strchr(host, ']');
+ if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
+ /* Malformed: must be [xx]:nn or [xx] */
+ error_msg("bad address '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ return NULL;
+ }
+ } else {
+ cp = strrchr(host, ':');
+ if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) {
+ /* There is more than one ':' (e.g. "::1") */
+ cp = NULL; /* it's not a port spec */
+ }
+ }
+ if (cp) { /* points to ":" or "]:" */
+ int sz = cp - host + 1;
+ char *hbuf = (char*)alloca(sz);
+ hbuf[--sz] = '\0';
+ host = strncpy(hbuf, host, sz);
+ if (ENABLE_FEATURE_IPV6 && *cp != ':') {
+ cp++; /* skip ']' */
+ if (*cp == '\0') /* [xx] without port */
+ goto skip;
+ }
+ cp++; /* skip ':' */
+ char *end;
+ errno = 0;
+ port = strtoul(cp, &end, 10);
+ if (errno || *end || (unsigned)port > 0xffff) {
+ error_msg("bad port spec '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ return NULL;
+ }
+ skip: ;
+ }
+
+ memset(&hint, 0 , sizeof(hint));
+#if !ENABLE_FEATURE_IPV6
+ hint.ai_family = AF_INET; /* do not try to find IPv6 */
+#else
+ hint.ai_family = af;
+#endif
+ /* Needed. Or else we will get each address thrice (or more)
+ * for each possible socket type (tcp,udp,raw...): */
+ hint.ai_socktype = SOCK_STREAM;
+ hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
+ rc = getaddrinfo(host, NULL, &hint, &result);
+ if (rc || !result) {
+ error_msg("bad address '%s'", org_host);
+ if (ai_flags & DIE_ON_ERROR)
+ xfunc_die();
+ goto ret;
+ }
+ used_res = result;
+#if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
+ while (1) {
+ if (used_res->ai_family == AF_INET)
+ break;
+ used_res = used_res->ai_next;
+ if (!used_res) {
+ used_res = result;
+ break;
+ }
+ }
+#endif
+ r = (len_and_sockaddr *)xmalloc(offsetof(len_and_sockaddr, u.sa) + used_res->ai_addrlen);
+ r->len = used_res->ai_addrlen;
+ memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
+ set_nport(r, htons(port));
+ ret:
+ freeaddrinfo(result);
+ return r;
+}
+#if !ENABLE_FEATURE_IPV6
+#define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
+#endif
+
+#if ENABLE_FEATURE_IPV6
+len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af)
+{
+ return str2sockaddr(host, port, af, 0);
+}
+
+len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
+{
+ return str2sockaddr(host, port, af, DIE_ON_ERROR);
+}
+#endif
+
+len_and_sockaddr* host2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, 0);
+}
+
+len_and_sockaddr* xhost2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
+}
+
+len_and_sockaddr* xdotted2sockaddr(const char *host, int port)
+{
+ return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
+}
+
+#undef xsocket_type
+int xsocket_type(len_and_sockaddr **lsap, int family, int sock_type)
+{
+ len_and_sockaddr *lsa;
+ int fd;
+ int len;
+
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_UNSPEC) {
+ fd = socket(AF_INET6, sock_type, 0);
+ if (fd >= 0) {
+ family = AF_INET6;
+ goto done;
+ }
+ family = AF_INET;
+ }
+#endif
+ fd = xsocket(family, sock_type, 0);
+ len = sizeof(struct sockaddr_in);
+#if ENABLE_FEATURE_IPV6
+ if (family == AF_INET6) {
+ done:
+ len = sizeof(struct sockaddr_in6);
+ }
+#endif
+ lsa = (len_and_sockaddr *)xzalloc(offsetof(len_and_sockaddr, u.sa) + len);
+ lsa->len = len;
+ lsa->u.sa.sa_family = family;
+ *lsap = lsa;
+ return fd;
+}
+
+int xsocket_stream(len_and_sockaddr **lsap)
+{
+ return xsocket_type(lsap, AF_UNSPEC, SOCK_STREAM);
+}
+
+static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
+{
+ int fd;
+ len_and_sockaddr *lsa;
+
+ if (bindaddr && bindaddr[0]) {
+ lsa = xdotted2sockaddr(bindaddr, port);
+ /* user specified bind addr dictates family */
+ fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
+ } else {
+ fd = xsocket_type(&lsa, AF_UNSPEC, sock_type);
+ set_nport(lsa, htons(port));
+ }
+ setsockopt_reuseaddr(fd);
+ xbind(fd, &lsa->u.sa, lsa->len);
+ free(lsa);
+ return fd;
+}
+
+int create_and_bind_stream_or_die(const char *bindaddr, int port)
+{
+ return create_and_bind_or_die(bindaddr, port, SOCK_STREAM);
+}
+
+int create_and_bind_dgram_or_die(const char *bindaddr, int port)
+{
+ return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM);
+}
+
+
+int create_and_connect_stream_or_die(const char *peer, int port)
+{
+ int fd;
+ len_and_sockaddr *lsa;
+
+ lsa = xhost2sockaddr(peer, port);
+ fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
+ setsockopt_reuseaddr(fd);
+ xconnect(fd, &lsa->u.sa, lsa->len);
+ free(lsa);
+ return fd;
+}
+
+int xconnect_stream(const len_and_sockaddr *lsa)
+{
+ int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
+ xconnect(fd, &lsa->u.sa, lsa->len);
+ return fd;
+}
+
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will add this bit anyway */
+#define IGNORE_PORT NI_NUMERICSERV
+static char* sockaddr2str(const struct sockaddr *sa, int flags)
+{
+ char host[128];
+ char serv[16];
+ int rc;
+ socklen_t salen;
+
+ salen = LSA_SIZEOF_SA;
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ if (sa->sa_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+#endif
+ rc = getnameinfo(sa, salen,
+ host, sizeof(host),
+ /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
+ serv, sizeof(serv),
+ /* do not resolve port# into service _name_ */
+ flags | NI_NUMERICSERV
+ );
+ if (rc)
+ return NULL;
+ if (flags & IGNORE_PORT)
+ return xstrdup(host);
+#if ENABLE_FEATURE_IPV6
+ if (sa->sa_family == AF_INET6) {
+ if (strchr(host, ':')) /* heh, it's not a resolved hostname */
+ return xasprintf("[%s]:%s", host, serv);
+ /*return xasprintf("%s:%s", host, serv);*/
+ /* - fall through instead */
+ }
+#endif
+ /* For now we don't support anything else, so it has to be INET */
+ /*if (sa->sa_family == AF_INET)*/
+ return xasprintf("%s:%s", host, serv);
+ /*return xstrdup(host);*/
+}
+
+char* xmalloc_sockaddr2host(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, 0);
+}
+
+char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, IGNORE_PORT);
+}
+
+char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
+}
+char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST);
+}
+
+char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
+{
+ return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
+}
diff --git a/lib/Utils/xfuncs.cpp b/lib/Utils/xfuncs.cpp
index d256c19..97c2f76 100644
--- a/lib/Utils/xfuncs.cpp
+++ b/lib/Utils/xfuncs.cpp
@@ -5,6 +5,22 @@
*/
#include "abrtlib.h"
+/* Turn on nonblocking I/O on a fd */
+int ndelay_on(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
+}
+
+int ndelay_off(int fd)
+{
+ return fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) & ~O_NONBLOCK);
+}
+
+int close_on_exec_on(int fd)
+{
+ return fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
// Die if we can't allocate size bytes of memory.
void* xmalloc(size_t size)
{
@@ -305,3 +321,50 @@ int is_regular_file(struct dirent *dent, const char *dirname)
return r == 0 && S_ISREG(statbuf.st_mode);
}
+
+/* Is it "." or ".."? */
+/* abrtlib candidate */
+bool dot_or_dotdot(const char *filename)
+{
+ if (filename[0] != '.') return false;
+ if (filename[1] == '\0') return true;
+ if (filename[1] != '.') return false;
+ if (filename[2] == '\0') return true;
+ return false;
+}
+
+/* Find out if the last character of a string matches the one given.
+ * Don't underrun the buffer if the string length is 0.
+ */
+char *last_char_is(const char *s, int c)
+{
+ if (s && *s) {
+ s += strlen(s) - 1;
+ if ((unsigned char)*s == c)
+ return (char*)s;
+ }
+ return NULL;
+}
+
+std::string concat_path_file(const char *path, const char *filename)
+{
+ char *lc;
+
+ while (*filename == '/')
+ filename++;
+ lc = last_char_is(path, '/');
+ return ssprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
+}
+
+bool string_to_bool(const char *s)
+{
+ if (s[0] == '1' && s[1] == '\0')
+ return true;
+ if (strcasecmp(s, "on") == 0)
+ return true;
+ if (strcasecmp(s, "yes") == 0)
+ return true;
+ if (strcasecmp(s, "true") == 0)
+ return true;
+ return false;
+}