summaryrefslogtreecommitdiffstats
path: root/src/cli/report.cpp
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2011-02-01 15:57:39 +0100
committerDenys Vlasenko <dvlasenk@redhat.com>2011-02-01 15:57:39 +0100
commit876664f002c5f90e5722602956a6d60591619680 (patch)
tree4794bef8e75ba7059cf1b67fda666e660c7fc7a1 /src/cli/report.cpp
parent7cad610805bac55eb6c82f6377aaf35a5fe7d44b (diff)
downloadabrt-876664f002c5f90e5722602956a6d60591619680.tar.gz
abrt-876664f002c5f90e5722602956a6d60591619680.tar.xz
abrt-876664f002c5f90e5722602956a6d60591619680.zip
abrt-cli: converted to process events locally
Only -d DIR operation still goes through the daemon. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'src/cli/report.cpp')
-rw-r--r--src/cli/report.cpp350
1 files changed, 253 insertions, 97 deletions
diff --git a/src/cli/report.cpp b/src/cli/report.cpp
index 38653e67..56740e25 100644
--- a/src/cli/report.cpp
+++ b/src/cli/report.cpp
@@ -464,36 +464,51 @@ static bool set_echo(bool enable)
return true;
}
-static void free_map_string_t(gpointer data)
-{
- delete (map_string_t *)data;
-}
/**
* Gets reporter plugin settings.
- * @param reporters
- * List of reporter names. Settings of these reporters are handled.
* @return settings
* A structure filled with reporter plugin settings.
* It's GHashTable<char *, map_plugin_t *> and must be passed to
* g_hash_table_destroy();
*/
-static GHashTable *get_reporter_plugin_settings(const vector_string_t& reporters)
+static void get_plugin_system_settings(GHashTable *settings)
{
- /* First of all, load system-wide report plugin settings. */
- GHashTable *settings = g_hash_table_new_full(g_str_hash, g_str_equal,
- free, free_map_string_t);
+ DIR *dir = opendir(PLUGINS_CONF_DIR);
+ if (!dir)
+ return;
- for (vector_string_t::const_iterator it = reporters.begin(); it != reporters.end(); ++it)
+ struct dirent *dent;
+ while ((dent = readdir(dir)) != NULL)
{
- map_string_t *single_plugin_settings = new 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.
- g_hash_table_replace(settings, xstrdup(it->c_str()), single_plugin_settings);
+ char *ext = strrchr(dent->d_name, '.');
+ if (!ext || strcmp(ext + 1, "conf") != 0)
+ continue;
+ if (!is_regular_file(dent, PLUGINS_CONF_DIR))
+ continue;
+ VERB3 log("Found %s", dent->d_name);
+
+ char *conf_file = concat_path_file(PLUGINS_CONF_DIR, dent->d_name);
+ map_string_h *single_plugin_settings = new_map_string();
+ if (load_conf_file(conf_file, single_plugin_settings, /*skip w/o value:*/ false))
+ VERB3 log("Loaded %s", dent->d_name);
+ free(conf_file);
+
+ *ext = '\0';
+ g_hash_table_replace(settings, xstrdup(dent->d_name), single_plugin_settings);
}
+ closedir(dir);
+}
+
+static GHashTable *get_plugin_settings(void)
+{
+ /* First of all, load system-wide plugin settings. */
+ GHashTable *settings = g_hash_table_new_full(
+ g_str_hash, g_str_equal,
+ free, (void (*)(void*))free_map_string
+ );
+
+ get_plugin_system_settings(settings);
/* Second, load user-specific settings, which override
* the system-wide settings. */
@@ -503,7 +518,7 @@ static GHashTable *get_reporter_plugin_settings(const vector_string_t& reporters
{
GHashTableIter iter;
char *plugin_name;
- map_string_t *plugin_settings;
+ map_string_h *plugin_settings;
g_hash_table_iter_init(&iter, settings);
while (g_hash_table_iter_next(&iter, (void**)&plugin_name, (void**)&plugin_settings))
{
@@ -528,7 +543,7 @@ static GHashTable *get_reporter_plugin_settings(const vector_string_t& reporters
char *value;
g_hash_table_iter_init(&iter2, single_plugin_settings);
while (g_hash_table_iter_next(&iter2, (void**)&key, (void**)&value))
- (*plugin_settings)[key] = xstrdup(value);
+ g_hash_table_replace(plugin_settings, xstrdup(key), xstrdup(value));
free_map_string(single_plugin_settings);
}
@@ -539,13 +554,13 @@ static GHashTable *get_reporter_plugin_settings(const vector_string_t& reporters
/**
* Asks user for missing login information
*/
-static void ask_for_missing_settings(const char *plugin_name, map_string_t &single_plugin_settings)
+static void ask_for_missing_settings(const char *plugin_name, map_string_h *single_plugin_settings)
{
// Login information is missing.
- bool loginMissing = single_plugin_settings.find("Login") != single_plugin_settings.end()
- && 0 == strcmp(single_plugin_settings["Login"].c_str(), "");
- bool passwordMissing = single_plugin_settings.find("Password") != single_plugin_settings.end()
- && 0 == strcmp(single_plugin_settings["Password"].c_str(), "");
+ const char *login = get_map_string_item_or_NULL(single_plugin_settings, "Login");
+ const char *password = get_map_string_item_or_NULL(single_plugin_settings, "Password");
+ bool loginMissing = (login && login[0] == '\0');
+ bool passwordMissing = (password && password[0] == '\0');
if (!loginMissing && !passwordMissing)
return;
@@ -555,7 +570,7 @@ static void ask_for_missing_settings(const char *plugin_name, map_string_t &sing
if (loginMissing)
{
read_from_stdin(_("Enter your login: "), result, 64);
- single_plugin_settings["Login"] = std::string(result);
+ g_hash_table_replace(single_plugin_settings, xstrdup("Login"), xstrdup(result));
}
if (passwordMissing)
{
@@ -566,77 +581,224 @@ static void ask_for_missing_settings(const char *plugin_name, map_string_t &sing
// Newline was not added by pressing Enter because ECHO was disabled, so add it now.
puts("");
- single_plugin_settings["Password"] = std::string(result);
+ g_hash_table_replace(single_plugin_settings, xstrdup("Password"), xstrdup(result));
}
}
-/* Reports the crash over DBus. */
-int report(const char *dump_dir_name, int flags)
+
+struct logging_state {
+ char *last_line;
+};
+static char *do_log_and_save_line(char *log_line, void *param)
+{
+ struct logging_state *l_state = (struct logging_state *)param;
+ log("%s", log_line);
+ free(l_state->last_line);
+ l_state->last_line = log_line;
+ return NULL;
+}
+static int run_events(const char *dump_dir_name,
+ const vector_string_t& events,
+ GHashTable *map_map_settings
+) {
+ int error_cnt = 0;
+ GList *env_list = NULL;
+
+ // Export overridden settings as environment variables
+ GHashTableIter iter;
+ char *plugin_name;
+ map_string_h *single_plugin_settings;
+ g_hash_table_iter_init(&iter, map_map_settings);
+ while (g_hash_table_iter_next(&iter, (void**)&plugin_name, (void**)&single_plugin_settings))
+ {
+ GHashTableIter iter2;
+ char *key;
+ char *value;
+ g_hash_table_iter_init(&iter2, single_plugin_settings);
+ while (g_hash_table_iter_next(&iter2, (void**)&key, (void**)&value))
+ {
+ char *s = xasprintf("%s_%s=%s", plugin_name, key, value);
+ VERB3 log("Exporting '%s'", s);
+ putenv(s);
+ env_list = g_list_append(env_list, s);
+ }
+ }
+
+ // Run events
+ bool at_least_one_reporter_succeeded = false;
+ std::string message;
+ struct logging_state l_state;
+ l_state.last_line = NULL;
+ struct run_event_state *run_state = new_run_event_state();
+ run_state->logging_callback = do_log_and_save_line;
+ run_state->logging_param = &l_state;
+ for (unsigned i = 0; i < events.size(); i++)
+ {
+ std::string event = events[i];
+
+ int r = run_event_on_dir_name(run_state, dump_dir_name, event.c_str());
+ if (r == -1)
+ {
+ l_state.last_line = xasprintf("Error: no processing is specified for event '%s'", event.c_str());
+ }
+ if (r == 0)
+ {
+ at_least_one_reporter_succeeded = true;
+ printf("%s: %s\n", event.c_str(), (l_state.last_line ? : "Reporting succeeded"));
+ if (message != "")
+ message += ";";
+ message += (l_state.last_line ? : "Reporting succeeded");
+ }
+ else
+ {
+ error_msg("Reporting via '%s' was not successful%s%s",
+ event.c_str(),
+ l_state.last_line ? ": " : "",
+ l_state.last_line ? l_state.last_line : ""
+ );
+ error_cnt++;
+ }
+ free(l_state.last_line);
+ l_state.last_line = NULL;
+ }
+ free_run_event_state(run_state);
+
+ // Unexport overridden settings
+ for (GList *li = env_list; li; li = g_list_next(li))
+ {
+ char *s = (char*)li->data;
+ /* Need to make a copy: just cutting s at '=' and unsetenv'ing
+ * the result would be a bug! s _itself_ is in environment now,
+ * we must not modify it there!
+ */
+ char *name = xstrndup(s, strchrnul(s, '=') - s);
+ VERB3 log("Unexporting '%s'", name);
+ unsetenv(name);
+ free(name);
+ free(s);
+ }
+ g_list_free(env_list);
+
+ // Save reporting results
+ if (at_least_one_reporter_succeeded)
+ {
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (dd)
+ {
+ dd_save_text(dd, FILENAME_MESSAGE, message.c_str());
+ dd_close(dd);
+ }
+ }
+
+ return error_cnt;
+}
+
+
+static char *do_log(char *log_line, void *param)
{
- // Ask for an initial report.
- crash_data_t *crash_data = call_CreateReport(dump_dir_name);
- if (!crash_data || g_hash_table_size(crash_data) == 0)
+ log("%s", log_line);
+ return log_line;
+}
+int run_analyze_event(const char *dump_dir_name)
+{
+ VERB2 log("run_analyze_event('%s')", dump_dir_name);
+
+ struct run_event_state *run_state = new_run_event_state();
+ run_state->logging_callback = do_log;
+ int res = run_event_on_dir_name(run_state, dump_dir_name, "analyze");
+ free_run_event_state(run_state);
+
+ if (res != 0 && res != -1) /* -1 is "nothing was done", here it is ok */
{
- free_crash_data(crash_data);
- return -1;
+ error_msg("Error while running analyze event on '%s'", dump_dir_name);
+ return 1;
}
+ return 0;
+}
+
+
+/* Report the crash */
+int report(const char *dump_dir_name, int flags)
+{
+ if (run_analyze_event(dump_dir_name) != 0)
+ return 1;
- const char *rating_str = get_crash_item_content_or_NULL(crash_data, FILENAME_RATING);
- unsigned rating = rating_str ? xatou(rating_str) : 4;
+ /* Load crash_data from (possibly updated by analyze) dump dir */
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
+ return -1;
+
+ crash_data_t *crash_data = create_crash_data_from_dump_dir(dd);
+ char *events_as_lines = list_possible_events(dd, NULL, "");
+ dd_close(dd);
- /* Open text editor and give a chance to review the backtrace etc. */
if (!(flags & CLI_REPORT_BATCH))
{
+ /* Open text editor and give a chance to review the backtrace etc */
create_fields_for_editor(crash_data);
int result = run_report_editor(crash_data);
if (result != 0)
{
free_crash_data(crash_data);
- return result;
+ free(events_as_lines);
+ return 1;
+ }
+ /* Save comment, "how to reproduce", backtrace */
+ dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (dd)
+ {
+//TODO: we should iterate through crash_data and modify all modifiable fields
+ const char *comment = get_crash_item_content_or_NULL(crash_data, FILENAME_COMMENT);
+ const char *reproduce = get_crash_item_content_or_NULL(crash_data, FILENAME_REPRODUCE);
+ const char *backtrace = get_crash_item_content_or_NULL(crash_data, FILENAME_BACKTRACE);
+ if (comment)
+ dd_save_text(dd, FILENAME_COMMENT, comment);
+ if (reproduce)
+ dd_save_text(dd, FILENAME_REPRODUCE, reproduce);
+ if (backtrace)
+ dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
+ dd_close(dd);
}
}
- /* Get possible reporters associated with this particular crash. */
- const char *events = get_crash_item_content_or_NULL(crash_data, CD_EVENTS);
+ /* Get possible reporters associated with this particular crash */
vector_string_t report_events;
- if (events) while (*events)
+ if (events_as_lines)
{
- const char *end = strchrnul(events, '\n');
- if (strncmp(events, "report", 6) == 0
- && (events[6] == '\0' || events[6] == '_')
- ) {
- char *tmp = xstrndup(events, end - events);
- report_events.push_back(tmp);
- free(tmp);
+ char *events = events_as_lines;
+ while (*events)
+ {
+ char *end = strchrnul(events, '\n');
+ if (strncmp(events, "report", 6) == 0
+ && (events[6] == '\0' || events[6] == '_')
+ ) {
+ char *tmp = xstrndup(events, end - events);
+ report_events.push_back(tmp);
+ free(tmp);
+ }
+ events = end;
+ if (!*events)
+ break;
+ events++;
}
- events = end;
- if (!*events)
- break;
- events++;
}
/* Get settings */
- GHashTable *reporters_settings = get_reporter_plugin_settings(report_events);
+ GHashTable *map_map_settings = get_plugin_settings();
int errors = 0;
int plugins = 0;
if (flags & CLI_REPORT_BATCH)
{
puts(_("Reporting..."));
- report_status_t r = call_Report(crash_data, report_events, reporters_settings);
- report_status_t::iterator it = r.begin();
- while (it != r.end())
- {
- 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++;
- }
+ errors += run_events(dump_dir_name, report_events, map_map_settings);
+ plugins += report_events.size();
}
else
{
+ const char *rating_str = get_crash_item_content_or_NULL(crash_data, FILENAME_RATING);
+ unsigned rating = rating_str ? xatou(rating_str) : 4;
+
/* For every reporter, ask if user really wants to report using it. */
for (vector_string_t::const_iterator it = report_events.begin(); it != report_events.end(); ++it)
{
@@ -648,48 +810,42 @@ int report(const char *dump_dir_name, int flags)
continue;
}
- map_string_t *settings = (map_string_t *)g_hash_table_lookup(reporters_settings, it->c_str());
- if (settings)
+//TODO: rethink how we associate report events with configs
+ if (strncmp(it->c_str(), "report_", strlen("report_")) == 0)
{
- map_string_t::iterator rating_setting = settings->find("RatingRequired");
- if (rating_setting != settings->end()
- && string_to_bool(rating_setting->second.c_str())
- && rating < 3)
+ const char *config_name = it->c_str() + strlen("report_");
+ map_string_h *single_plugin_settings = (map_string_h *)g_hash_table_lookup(map_map_settings, config_name);
+ if (single_plugin_settings)
{
- puts(_("Reporting disabled because the backtrace is unusable"));
-
- const char *package = get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE);
- if (package && package[0])
- printf(_("Please try to install debuginfo manually using the command: \"debuginfo-install %s\" and try again\n"), package);
-
- plugins++;
- errors++;
- continue;
+ const char *rating_required = get_map_string_item_or_NULL(single_plugin_settings, "RatingRequired");
+ if (rating_required
+ && string_to_bool(rating_required) == true
+ && rating < 3
+ ) {
+ puts(_("Reporting disabled because the backtrace is unusable"));
+
+ const char *package = get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE);
+ if (package && package[0])
+ printf(_("Please try to install debuginfo manually using the command: \"debuginfo-install %s\" and try again\n"), package);
+
+ plugins++;
+ errors++;
+ continue;
+ }
+ ask_for_missing_settings(it->c_str(), single_plugin_settings);
}
}
- else
- {
- puts(_("Error loading reporter settings"));
- plugins++;
- errors++;
- continue;
- }
-
- ask_for_missing_settings(it->c_str(), *settings);
vector_string_t cur_event(1, *it);
- report_status_t r = call_Report(crash_data, cur_event, 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());
+ errors += run_events(dump_dir_name, cur_event, map_map_settings);
plugins++;
- if (v[REPORT_STATUS_IDX_FLAG] == "0")
- errors++;
}
}
- g_hash_table_destroy(reporters_settings);
- free_crash_data(crash_data);
+ g_hash_table_destroy(map_map_settings);
+
printf(_("Crash reported via %d report events (%d errors)\n"), plugins, errors);
- return errors != 0;
+ free_crash_data(crash_data);
+ free(events_as_lines);
+ return errors;
}