* naive implementation of running of event chain in report-cli
Signed-off-by: Jakub Filak jfilak@redhat.com --- src/cli/cli-report.c | 223 ++++++++++++++++++++++++++++++++++++++------------ src/cli/cli-report.h | 1 + src/cli/cli.c | 34 ++++---- 3 files changed, 187 insertions(+), 71 deletions(-)
diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c index 988bfc7..e204435 100644 --- a/src/cli/cli-report.c +++ b/src/cli/cli-report.c @@ -520,10 +520,30 @@ static char *do_log_and_save_line(char *log_line, void *param) l_state->last_line = log_line; return NULL; } + +static int run_event(struct run_event_state *state, const char *dump_dir_name, + const char *event, struct logging_state *l_state) +{ + // Export overridden settings as environment variables + GList *env_list = export_event_config(event); + + int r = run_event_on_dir_name(state, dump_dir_name, event); + if (r == 0 && state->children_count == 0) + { + l_state->last_line = xasprintf("Error: no processing is specified for event '%s'", + event); + r = -1; + } + + // Unexport overridden settings + unexport_event_config(env_list); + + return r; +} + static int run_events(const char *dump_dir_name, GList *events, const char *event_type) { int error_cnt = 0; - GList *env_list = NULL;
// Run events struct logging_state l_state; @@ -534,18 +554,7 @@ static int run_events(const char *dump_dir_name, GList *events, const char *even for (GList *li = events; li; li = li->next) { char *event = (char *) li->data; - - // Export overridden settings as environment variables - env_list = export_event_config(event); - - int r = run_event_on_dir_name(run_state, dump_dir_name, event); - if (r == 0 && run_state->children_count == 0) - { - l_state.last_line = xasprintf("Error: no processing is specified for event '%s'", - event); - r = -1; - } - if (r == 0) + if (run_event(run_state, dump_dir_name, event, &l_state) == 0) { printf("%s: ", event); if (l_state.last_line) @@ -560,14 +569,11 @@ static int run_events(const char *dump_dir_name, GList *events, const char *even event, l_state.last_line ? ": " : "", l_state.last_line ? l_state.last_line : "" - ); - error_cnt++; + ); + ++error_cnt; } free(l_state.last_line); l_state.last_line = NULL; - - // Unexport overridden settings - unexport_event_config(env_list); } free_run_event_state(run_state);
@@ -742,6 +748,51 @@ int collect(const char *dump_dir_name, int batch) return errors; }
+static int review_problem_data(const char *dump_dir_name, problem_data_t *problem_data) +{ + /* Open text editor and give a chance to review the backtrace etc */ + create_fields_for_editor(problem_data); + int result = run_report_editor(problem_data); + if (result != 0) + return 1; + + /* Save comment, backtrace */ + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (dd) + { + //TODO: we should iterate through problem_data and modify all modifiable fields + const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT); + const char *backtrace = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE); + if (comment) + dd_save_text(dd, FILENAME_COMMENT, comment); + if (backtrace) + dd_save_text(dd, FILENAME_BACKTRACE, backtrace); + dd_close(dd); + } + + return 0; +} + +static int is_backtrace_rating_usable(event_config_t *config, problem_data_t *problem_data) +{ + char *usability_description = NULL; + char *usability_detail = NULL; + const bool usable_rating = check_problem_rating_usability(config, problem_data, + &usability_description, + &usability_detail); + + if (!usable_rating) + { + printf("%s\n", usability_description); + printf("%s\n", usability_detail); + } + + free(usability_description); + free(usability_detail); + + return usable_rating; +} + /* Report the crash */ int report(const char *dump_dir_name, int flags) { @@ -804,30 +855,12 @@ int report(const char *dump_dir_name, int flags) problem_data_t *problem_data = create_problem_data_from_dump_dir(dd); dd_close(dd);
- if (!(flags & (CLI_REPORT_BATCH))) + if (!(flags & (CLI_REPORT_BATCH)) + && review_problem_data(dump_dir_name, problem_data)) { - /* Open text editor and give a chance to review the backtrace etc */ - create_fields_for_editor(problem_data); - int result = run_report_editor(problem_data); - if (result != 0) - { - problem_data_free(problem_data); - free(report_events_as_lines); - return 1; - } - /* Save comment, backtrace */ - dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (dd) - { -//TODO: we should iterate through problem_data and modify all modifiable fields - const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT); - const char *backtrace = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE); - if (comment) - dd_save_text(dd, FILENAME_COMMENT, comment); - if (backtrace) - dd_save_text(dd, FILENAME_BACKTRACE, backtrace); - dd_close(dd); - } + problem_data_free(problem_data); + free(report_events_as_lines); + return 1; }
/* Get possible reporters associated with this particular crash */ @@ -885,17 +918,8 @@ int report(const char *dump_dir_name, int flags) if (!is_number_in_string(i, wanted_reporters)) continue;
- char *usability_description = NULL; - char *usability_detail = NULL; - const bool usable_rating = check_problem_rating_usability(config, problem_data, - &usability_description, - &usability_detail); - - if (!usable_rating) + if (!is_backtrace_rating_usable(config, problem_data)) { - printf("%s\n", usability_description); - printf("%s\n", usability_detail); - errors++; goto next_plugin; } @@ -914,8 +938,6 @@ int report(const char *dump_dir_name, int flags)
next_plugin: plugins++; - free(usability_description); - free(usability_detail); } }
@@ -924,3 +946,98 @@ next_plugin: list_free_with_free(report_events); return errors; } + +struct chain_logging_param +{ + struct logging_state l_state; + bool terminate; +}; + +static char *do_log_and_terminate_chain_on_request(char *log_line, void *param) +{ + struct chain_logging_param *arg = (struct chain_logging_param *)param; + + arg->terminate = strcmp("THANKYOU", log_line) == 0; + + return do_log_and_save_line(log_line, &(arg->l_state)); +} + +/* + * Runs event from chain. Perform the following steps for each event from chain. + * 1. Terminates a chain run if a backtrace is not usable. + * 2. Asks for missing settings. + * 3. Performs review of problem data if event requires review. + * 4. Runs events commands. + * 5. Terminates a chain run if any event from the chain requires termination + * (prints THANKYOU to stdout in the current implementation) + * 6. Terminates a chain run if any error occurs. + * 7. Continues immediately with processing of next event. + */ +int run_events_chain(const char *dump_dir_name, GList *chain) +{ + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + return -1; + + problem_data_t *problem_data = create_problem_data_from_dump_dir(dd); + + dd_close(dd); + + struct chain_logging_param chain_state = { + .l_state = { + .last_line = NULL, + }, + .terminate = false, + }; + + struct run_event_state *run_state = new_run_event_state(); + run_state->logging_callback = do_log_and_terminate_chain_on_request; + run_state->logging_param = &chain_state; + + int returncode = 0; + + for (GList *eitem = chain; !chain_state.terminate && eitem; eitem = g_list_next(eitem)) + { + const char *const event = (const char *)eitem->data; + event_config_t *config = get_event_config(event); + + if (!is_backtrace_rating_usable(config, problem_data)) + /* it is not a failure of event if the backtrace is unusable */ + break; + + if (config) + { + /* can't fail */ + ask_for_missing_settings(event); + + /* review problem data only if the event needs it */ + if (!config->ec_skip_review + && review_problem_data(dump_dir_name, problem_data)) + { + /* review failed, an error message was already logged */ + returncode = -1; + break; + } + } + + returncode = run_event(run_state, dump_dir_name, event, &chain_state.l_state); + if (returncode != 0) + { + error_msg("'%s' event was not successful%s%s", + event, + chain_state.l_state.last_line ? ": " : "", + chain_state.l_state.last_line ? chain_state.l_state.last_line : "" + ); + break; + } + + free(chain_state.l_state.last_line); + chain_state.l_state.last_line = NULL; + } + + free_run_event_state(run_state); + free(chain_state.l_state.last_line); + problem_data_free(problem_data); + + return returncode; +} diff --git a/src/cli/cli-report.h b/src/cli/cli-report.h index b34293d..8dd3773 100644 --- a/src/cli/cli-report.h +++ b/src/cli/cli-report.h @@ -32,6 +32,7 @@ enum { }; int report(const char *dump_dir_name, int flags); int collect(const char *dump_dir_name, int batch); +int run_events_chain(const char *dump_dir_name, GList *chain);
#ifdef __cplusplus } diff --git a/src/cli/cli.c b/src/cli/cli.c index 66ebbe2..5a221ad 100644 --- a/src/cli/cli.c +++ b/src/cli/cli.c @@ -23,10 +23,18 @@ #include "internal_libreport.h" #include "cli-report.h"
-static char *do_log(char *log_line, void *param) +static char *steal_directory_if_needed(char *dump_dir_name) { - log("%s", log_line); - return log_line; + struct dump_dir *dd = open_directory_for_writing(dump_dir_name, + /* ask callback */ NULL); + + if (dd) + { + dump_dir_name = xstrdup(dd->dd_dirname); + dd_close(dd); + } + + return dump_dir_name; }
int main(int argc, char** argv) @@ -47,7 +55,7 @@ int main(int argc, char** argv) textdomain(PACKAGE); #endif
- const char *event_name = NULL; + GList *event_list = NULL; const char *pfx = "";
/* Can't keep these strings/structs static: _() doesn't support that */ @@ -77,7 +85,7 @@ int main(int argc, char** argv) struct options program_options[] = { /* short_name long_name value parameter_name help */ OPT_OPTSTRING('L', NULL , &pfx, "PREFIX", _("List possible events [which start with PREFIX]")), - OPT_STRING( 'e', NULL , &event_name, "EVENT", _("Run EVENT on DUMP_DIR")), + OPT_LIST( 'e', "event" , &event_list, "EVENT", _("Run only these events")), OPT_BOOL( 'a', "analyze", NULL, _("Run analyze event(s) on DUMP_DIR")), OPT_BOOL( 'c', "collect", NULL, _("Run collect event(s) on DUMP_DIR")), OPT_BOOL( 'r', "report" , NULL, _("Analyze, collect and report problem data in DUMP_DIR")), @@ -144,12 +152,8 @@ int main(int argc, char** argv) } case OPT_run_event: /* -e EVENT: run event */ { - struct run_event_state *run_state = new_run_event_state(); - run_state->logging_callback = do_log; - int r = run_event_on_dir_name(run_state, dump_dir_name, event_name); - if (r == 0 && run_state->children_count == 0) - error_msg_and_die("No actions are found for event '%s'", event_name); - free_run_event_state(run_state); + dump_dir_name = steal_directory_if_needed(dump_dir_name); + exitcode = run_events_chain(dump_dir_name, event_list); break; } case OPT_analyze: @@ -184,13 +188,7 @@ int main(int argc, char** argv) } case OPT_report: { - struct dump_dir *dd = open_directory_for_writing(dump_dir_name, NULL); - - if (dd) - { - dump_dir_name = xstrdup(dd->dd_dirname); - dd_close(dd); - } + dump_dir_name = steal_directory_if_needed(dump_dir_name);
exitcode = report(dump_dir_name, (always ? CLI_REPORT_BATCH : 0));