summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2010-03-18 11:18:19 +0100
committerKarel Klic <kklic@redhat.com>2010-03-18 11:18:19 +0100
commite2d79ab74c2bfa798a3ec9772eb57bc4bcc7a7b8 (patch)
tree05e4aeede1499a548d02304f1d68276e21630612
parentf916f9dc8938cd59fa8a119f245e6e61d1adf496 (diff)
downloadabrt-e2d79ab74c2bfa798a3ec9772eb57bc4bcc7a7b8.tar.gz
abrt-e2d79ab74c2bfa798a3ec9772eb57bc4bcc7a7b8.tar.xz
abrt-e2d79ab74c2bfa798a3ec9772eb57bc4bcc7a7b8.zip
Allow user to select which reporter he wants to use to report a crash using CLI.
The daemon skips reporters which are not in the list of reporters provided via Report() dbus call. Reviewed by: Jiri Moskovcak <jmoskovc@redhat.com> Reviewed by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--src/CLI/dbus.cpp20
-rw-r--r--src/CLI/dbus.h17
-rw-r--r--src/CLI/report.cpp199
-rw-r--r--src/Daemon/CommLayerServerDBus.cpp6
-rw-r--r--src/Daemon/MiddleWare.cpp43
-rw-r--r--src/Daemon/MiddleWare.h18
6 files changed, 218 insertions, 85 deletions
diff --git a/src/CLI/dbus.cpp b/src/CLI/dbus.cpp
index 600d8556..9dd5bff7 100644
--- a/src/CLI/dbus.cpp
+++ b/src/CLI/dbus.cpp
@@ -160,6 +160,7 @@ map_crash_data_t call_CreateReport(const char* crash_id)
}
report_status_t call_Report(const map_crash_data_t& report,
+ const vector_string_t& reporters,
const map_map_string_t &plugins)
{
DBusMessage* msg = new_call_msg(__func__ + 5);
@@ -169,8 +170,7 @@ report_status_t call_Report(const map_crash_data_t& report,
/* parameter #1: report data */
store_val(&out_iter, report);
/* parameter #2: reporters to use */
- vector_string_t reporters;
- store_val(&out_iter, reporters); /* unused by daemon so far */
+ store_val(&out_iter, reporters);
/* parameter #3 (opt): plugin config */
if (!plugins.empty())
store_val(&out_iter, plugins);
@@ -248,6 +248,22 @@ map_plugin_settings_t call_GetPluginSettings(const char *name)
return argout;
}
+map_map_string_t call_GetSettings()
+{
+ DBusMessage *msg = new_call_msg(__func__ + 5);
+ DBusMessage *reply = send_get_reply_and_unref(msg);
+
+ DBusMessageIter in_iter;
+ dbus_message_iter_init(reply, &in_iter);
+ map_map_string_t argout;
+ int r = load_val(&in_iter, argout);
+ if (r != ABRT_DBUS_LAST_FIELD) /* more values present, or bad type */
+ error_msg_and_die("dbus call %s: return type mismatch", __func__ + 5);
+
+ dbus_message_unref(reply);
+ return argout;
+}
+
void handle_dbus_err(bool error_flag, DBusError *err)
{
if (dbus_error_is_set(err))
diff --git a/src/CLI/dbus.h b/src/CLI/dbus.h
index be6b9615..4aaa4e96 100644
--- a/src/CLI/dbus.h
+++ b/src/CLI/dbus.h
@@ -24,21 +24,30 @@
extern DBusConnection* s_dbus_conn;
vector_map_crash_data_t call_GetCrashInfos();
+
map_crash_data_t call_CreateReport(const char *crash_id);
/** Sends report using enabled Reporter plugins.
+ * @param report
+ * The report sent to Reporter plugins.
+ * @param reporters
+ * List of names of Reporters which should be called.
* @param plugins
- * Optional settings for plugins, can be empty.
+ * Optional settings for Reporter plugins, can be empty.
* Format: plugins["PluginName"]["SettingsKey"] = "SettingsValue"
* If it contains settings for some plugin, it must contain _all fields_
* obtained by call_GetPluginSettings, otherwise the plugin might ignore
* the settings.
*/
report_status_t call_Report(const map_crash_data_t& report,
+ const vector_string_t& reporters,
const map_map_string_t &plugins);
+
int32_t call_DeleteDebugDump(const char* crash_id);
/* Gets basic data about all installed plugins.
+ * @todo
+ * Return more semantically structured output - maybe a struct instead of a map.
*/
map_map_string_t call_GetPluginsInfo();
@@ -48,6 +57,12 @@ map_map_string_t call_GetPluginsInfo();
*/
map_plugin_settings_t call_GetPluginSettings(const char *name);
+/** Gets global daemon settings.
+ * @todo
+ * Return more semantically structured output - maybe a struct instead of a map.
+ */
+map_map_string_t call_GetSettings();
+
void handle_dbus_err(bool error_flag, DBusError *err);
#endif
diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp
index 2d79d38d..60ed3c85 100644
--- a/src/CLI/report.cpp
+++ b/src/CLI/report.cpp
@@ -22,6 +22,8 @@
#include "DebugDump.h"
#include "CrashTypes.h" // FILENAME_* defines
#include "Plugin.h" // LoadPluginSettings
+#include <cassert>
+#include <algorithm>
#if HAVE_CONFIG_H
# include <config.h>
#endif
@@ -423,26 +425,82 @@ static int run_report_editor(map_crash_data_t &cr)
*/
static void read_from_stdin(const char *question, char *result, int result_size)
{
+ assert(result_size > 1);
printf("%s", question);
fflush(NULL);
- fgets(result, result_size, stdin);
+ if (NULL == fgets(result, result_size, stdin))
+ result[0] = '\0';
// Remove the newline from the login.
char *newline = strchr(result, '\n');
if (newline)
*newline = '\0';
}
-/**
- * Gets reporter plugin settings.
- * @param ask_user
- * If it's set to true and some reporter plugin settings are found to be missing
- * (like login name or password), user is asked to provide the missing parts.
- * @param settings
- * A structure filled with reporter plugin settings.
+/** Splits a string into substrings using chosen delimiters.
+ * @param delim
+ * Specifies a set of characters that delimit the
+ * tokens in the parsed string
*/
-static void get_reporter_plugin_settings(map_map_string_t &settings, bool ask_user)
+static vector_string_t split(const std::string &s, const char *delim)
{
- /* First of all, load system-wide report plugin settings. */
+ std::vector<std::string> elems;
+ char str[s.length() + 1];
+ /* str is modified by the following strtok_r,
+ so s.c_str() cannot be used directly */
+ strcpy(str, s.c_str());
+ char *saveptr, *token;
+ token = strtok_r(str, delim, &saveptr);
+ while (token != NULL)
+ {
+ elems.push_back(token);
+ token = strtok_r(NULL, delim, &saveptr);
+ }
+ return elems;
+}
+
+/** Returns a list of enabled Reporter plugins, that are used to report
+ * a particular crash.
+ * @todo
+ * Very similar code is used in the GUI, and also in the Daemon.
+ * It should be shared.
+ */
+static vector_string_t get_enabled_reporters(map_crash_data_t &crash_data)
+{
+ vector_string_t result;
+
+ /* Get global daemon settings. Analyzer->Reporters mapping is stored there. */
+ map_map_string_t settings = call_GetSettings();
+ /* Reporters are separated by comma in the following map. */
+ map_string_t &analyzer_to_reporters = settings["AnalyzerActionsAndReporters"];
+
+ /* Get the analyzer from the crash. */
+ const char *analyzer = get_crash_data_item_content_or_NULL(crash_data, FILENAME_ANALYZER);
+ if (!analyzer)
+ return result; /* No analyzer found in the crash data. */
+
+ /* First try to find package name dependent analyzer.
+ * nvr = name-version-release
+ * TODO: Similar code is in MiddleWare.cpp. It should not be duplicated.
+ */
+ const char *package_nvr = get_crash_data_item_content_or_NULL(crash_data, FILENAME_PACKAGE);
+ if (!package_nvr)
+ return result; /* No package name found in the crash data. */
+ std::string str_package_nvr(package_nvr);
+ std::string package_name = str_package_nvr.substr(0, str_package_nvr.rfind("-", str_package_nvr.rfind("-") - 1));
+ // analyzer with package name (CCpp:xorg-x11-app) has higher priority
+ std::string package_specific_analyzer = std::string(analyzer) + ":" + package_name;
+
+ map_string_t::const_iterator reporters_iter = analyzer_to_reporters.find(package_specific_analyzer);
+ if (analyzer_to_reporters.end() == reporters_iter)
+ {
+ reporters_iter = analyzer_to_reporters.find(analyzer);
+ if (analyzer_to_reporters.end() == reporters_iter)
+ return result; /* No reporters found for the analyzer. */
+ }
+
+ /* Reporters found, now parse the list. */
+ vector_string_t reporter_vec = split(reporters_iter->second, ",");
+
// Get informations about all plugins.
map_map_string_t plugins = call_GetPluginsInfo();
// Check the configuration of each enabled Reporter plugin.
@@ -455,11 +513,49 @@ static void get_reporter_plugin_settings(map_map_string_t &settings, bool ask_us
// Skip nonReporter plugins.
if (0 != strcmp(it->second["Type"].c_str(), "Reporter"))
continue;
- map_string_t single_plugin_settings = call_GetPluginSettings(it->first.c_str());
+ // Skip plugins not used in this particular crash.
+ if (reporter_vec.end() == std::find(reporter_vec.begin(), reporter_vec.end(), std::string(it->first)))
+ continue;
+ result.push_back(it->first);
+ }
+ return result;
+}
+
+/* Asks a [y/n] question on stdin/stdout.
+ * Returns true if the answer is yes, false otherwise.
+ */
+static bool ask_yesno(const char *question)
+{
+ printf(question);
+ fflush(NULL);
+ char answer[16] = "n";
+ fgets(answer, sizeof(answer), stdin);
+ /* TODO: localize 'y' */
+ return ((answer[0] | 0x20) == 'y');
+}
+
+/**
+ * Gets reporter plugin settings.
+ * @param reporters
+ * List of reporter names. Settings of these reporters are handled.
+ * @param settings
+ * A structure filled with reporter plugin settings.
+ * @param ask_user
+ * If it's set to true and some reporter plugin settings are found to be missing
+ * (like login name or password), user is asked to provide the missing parts.
+ */
+static void get_reporter_plugin_settings(const vector_string_t& reporters,
+ map_map_string_t &settings,
+ bool ask_user)
+{
+ /* First of all, load system-wide report plugin settings. */
+ for (vector_string_t::const_iterator it = reporters.begin(); it != reporters.end(); ++it)
+ {
+ map_string_t single_plugin_settings = call_GetPluginSettings(it->c_str());
// Copy the received settings as defaults.
// Plugins won't work without it, if some value is missing
// they use their default values for all fields.
- settings[it->first] = single_plugin_settings;
+ settings[it->c_str()] = single_plugin_settings;
}
/* Second, load user-specific settings, which override
@@ -468,14 +564,14 @@ static void get_reporter_plugin_settings(map_map_string_t &settings, bool ask_us
const char* homedir = pw ? pw->pw_dir : NULL;
if (homedir)
{
- itend = settings.end();
- for (it = settings.begin(); it != itend; ++it)
+ map_map_string_t::const_iterator itend = settings.end();
+ for (map_map_string_t::iterator it = settings.begin(); it != itend; ++it)
{
map_string_t single_plugin_settings;
std::string path = std::string(homedir) + "/.abrt/"
+ it->first + "."PLUGINS_CONF_EXTENSION;
/* Load plugin config in the home dir. Do not skip lines with empty value (but containing a "key="),
- because user may want to override password from /etc/abrt/plugins/*.conf, but he prefers to
+ because user may want to override password from /etc/abrt/plugins/\*.conf, but he prefers to
enter it every time he reports. */
bool success = LoadPluginSettings(path.c_str(), single_plugin_settings, false);
if (!success)
@@ -491,8 +587,8 @@ static void get_reporter_plugin_settings(map_map_string_t &settings, bool ask_us
return;
/* Third, check if a login or password is missing, and ask for it. */
- itend = settings.end();
- for (it = settings.begin(); it != itend; ++it)
+ map_map_string_t::const_iterator itend = settings.end();
+ for (map_map_string_t::iterator it = settings.begin(); it != itend; ++it)
{
map_string_t &single_plugin_settings = it->second;
// Login information is missing.
@@ -538,40 +634,55 @@ int report(const char *crash_id, bool always)
return result;
}
- /* Read the plugin settings. */
- map_map_string_t pluginSettings;
- get_reporter_plugin_settings(pluginSettings, !always);
+ /* Get enabled reporters associated with this particular crash. */
+ vector_string_t reporters = get_enabled_reporters(cr);
- /* Ask if user really wants to send the report. */
- if (!always)
+ int errors = 0;
+ int plugins = 0;
+ if (always)
{
- // Report only if the user is sure.
- printf(_("Do you want to send the report? [y/N]: "));
- fflush(NULL);
- char answer[16] = "n";
- fgets(answer, sizeof(answer), stdin);
- if ((answer[0] | 0x20) != 'y')
+ map_map_string_t reporters_settings; /* to be filled on the next line */
+ get_reporter_plugin_settings(reporters, reporters_settings, false);
+
+ puts(_("Reporting..."));
+ report_status_t r = call_Report(cr, reporters, reporters_settings);
+ report_status_t::iterator it = r.begin();
+ while (it != r.end())
{
- puts(_("Crash report was not sent."));
- return 0;
+ vector_string_t &v = it->second;
+ printf("%s: %s\n", it->first.c_str(), v[REPORT_STATUS_IDX_MSG].c_str());
+ plugins++;
+ if (v[REPORT_STATUS_IDX_FLAG] == "0")
+ errors++;
+ it++;
}
}
-
- int errors = 0;
- int plugins = 0;
- puts(_("Reporting..."));
- report_status_t r = call_Report(cr, pluginSettings);
- report_status_t::iterator it = r.begin();
- while (it != r.end())
+ else
{
- vector_string_t &v = it->second;
- printf("%s: %s\n", it->first.c_str(), v[REPORT_STATUS_IDX_MSG].c_str());
- plugins++;
- if (v[REPORT_STATUS_IDX_FLAG] == "0")
- errors++;
- it++;
+ /* For every reporter, ask if user really wants to report using it. */
+ for (vector_string_t::const_iterator it = reporters.begin(); it != reporters.end(); ++it)
+ {
+ char question[255];
+ snprintf(question, 255, _("Report using %s? [y/N]: "), it->c_str());
+ if (!ask_yesno(question))
+ {
+ puts(_("Skipping..."));
+ continue;
+ }
+
+ vector_string_t cur_reporter(1, *it);
+ map_map_string_t reporters_settings; /* to be filled on the next line */
+ get_reporter_plugin_settings(cur_reporter, reporters_settings, true);
+ report_status_t r = call_Report(cr, cur_reporter, reporters_settings);
+ assert(r.size() == 1); /* one reporter --> one report status */
+ vector_string_t &v = r.begin()->second;
+ printf("%s: %s\n", r.begin()->first.c_str(), v[REPORT_STATUS_IDX_MSG].c_str());
+ plugins++;
+ if (v[REPORT_STATUS_IDX_FLAG] == "0")
+ errors++;
+ }
}
- printf(_("Crash reported via %d plugins (%d errors)\n"), plugins, errors);
+ printf(_("Crash reported via %d plugins (%d errors)\n"), plugins, errors);
return errors != 0;
}
diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp
index 103f8675..d45209a3 100644
--- a/src/Daemon/CommLayerServerDBus.cpp
+++ b/src/Daemon/CommLayerServerDBus.cpp
@@ -247,7 +247,7 @@ static int handle_Report(DBusMessage* call, DBusMessage* reply)
return 0;
}
- /* Second parameter: reporters to use */
+ /* Second parameter: list of reporters to use */
vector_string_t reporters;
r = load_val(&in_iter, reporters);
if (r == ABRT_DBUS_ERROR)
@@ -256,7 +256,7 @@ static int handle_Report(DBusMessage* call, DBusMessage* reply)
return -1;
}
- /* Third parameter is optional */
+ /* Third parameter (optional): configuration data for plugins */
map_map_string_t user_conf_data;
if (r == ABRT_DBUS_MORE_FIELDS)
{
@@ -294,7 +294,7 @@ static int handle_Report(DBusMessage* call, DBusMessage* reply)
report_status_t argout1;
try
{
- argout1 = Report(argin1, user_conf_data, unix_uid);
+ argout1 = Report(argin1, reporters, user_conf_data, unix_uid);
}
catch (CABRTException &e)
{
diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp
index 3ab3ddd1..7792f5b8 100644
--- a/src/Daemon/MiddleWare.cpp
+++ b/src/Daemon/MiddleWare.cpp
@@ -27,6 +27,7 @@
#include "ABRTException.h"
#include "CommLayerInner.h"
#include "MiddleWare.h"
+#include <algorithm>
using namespace std;
@@ -377,10 +378,11 @@ void RunActionsAndReporters(const char *pDebugDumpDir)
}
-// We must not trust client_report here!
+// Do not trust client_report here!
// dbus handler passes it from user without checking
report_status_t Report(const map_crash_data_t& client_report,
- map_map_string_t& pSettings,
+ const vector_string_t &reporters,
+ map_map_string_t& settings,
long caller_uid)
{
// Get ID fields
@@ -498,39 +500,20 @@ report_status_t Report(const map_crash_data_t& client_report,
for (; it_r != keyPtr->second.end(); it_r++)
{
const char *plugin_name = it_r->first.c_str();
+
+ /* Check if the reporter is in the input list of allowed reporters. */
+ if (reporters.end() == std::find(reporters.begin(), reporters.end(), plugin_name))
+ {
+ continue;
+ }
+
try
{
if (g_pPluginManager->GetPluginType(plugin_name) == REPORTER)
{
CReporter* reporter = g_pPluginManager->GetReporter(plugin_name); /* can't be NULL */
-#if 0 /* Using ~user/.abrt/ is bad wrt security */
- std::string home;
- map_plugin_settings_t oldSettings;
- map_plugin_settings_t newSettings;
-
- if (pUID != "")
- {
- home = get_home_dir(xatoi_u(pUID.c_str()));
- if (home != "")
- {
- oldSettings = reporter->GetSettings();
-
- if (LoadPluginSettings(home + "/.abrt/" + plugin_name + "."PLUGINS_CONF_EXTENSION, newSettings))
- {
- reporter->SetSettings(newSettings);
- }
- }
- }
-#endif
- map_plugin_settings_t plugin_settings = pSettings[plugin_name];
+ map_plugin_settings_t plugin_settings = settings[plugin_name];
std::string res = reporter->Report(stored_report, plugin_settings, it_r->second.c_str());
-
-#if 0 /* Using ~user/.abrt/ is bad wrt security */
- if (home != "")
- {
- reporter->SetSettings(oldSettings);
- }
-#endif
ret[plugin_name].push_back("1"); // REPORT_STATUS_IDX_FLAG
ret[plugin_name].push_back(res); // REPORT_STATUS_IDX_MSG
if (message != "")
@@ -589,7 +572,7 @@ static bool IsDebugDumpSaved(long uid,
vector_database_rows_t rows = database->GetUIDData(uid);
database->DisConnect();
- int ii;
+ size_t ii;
bool found = false;
for (ii = 0; ii < rows.size(); ii++)
{
diff --git a/src/Daemon/MiddleWare.h b/src/Daemon/MiddleWare.h
index 275d5312..4a2903c2 100644
--- a/src/Daemon/MiddleWare.h
+++ b/src/Daemon/MiddleWare.h
@@ -87,12 +87,20 @@ void RunActionsAndReporters(const char *pDebugDumpDir);
* fails, then default config is used. If pUID is emply string, default
* config is used.
* ...).
- * @param pCrashData A crash report.
- * @param pUID An user uid
- * @return A report status, which reporters ends successfuly with messages.
+ * @param crash_data
+ * A crash report.
+ * @param reporters
+ * List of allowed reporters. Which reporters will be used depends
+ * on the analyzer of the crash_data. Reporters missing from this list
+ * will not be used.
+ * @param caller_uid
+ * An user uid.
+ * @return
+ * A report status, which reporters ends successfuly with messages.
*/
-report_status_t Report(const map_crash_data_t& pCrashData,
- map_map_string_t& pSettings,
+report_status_t Report(const map_crash_data_t& crash_data,
+ const vector_string_t& reporters,
+ map_map_string_t& settings,
long caller_uid);
/**
* Adds package name and description to debugdump dir.