[Automatic Bug Reporting Tool - ABRT] #819: abrt server support for rhel7
by fedora-badges
#819: abrt server support for rhel7
-------------------------------+------------------------------
Reporter: jmoskovc | Owner: crash-catcher@…
Type: defect | Status: new
Priority: major | Milestone: RHEL7
Component: rhtsupport-plugin | Version:
Keywords: | Blocked By:
Blocking: |
-------------------------------+------------------------------
We don't want customers to use ureport in RHEL7 directly. It has to be
sent by the rht-support plugin to the portal and portal will rely it to
the internal instance of ABRT server.
--
Ticket URL: <https://fedorahosted.org/abrt/ticket/819>
Automatic Bug Reporting Tool - ABRT <http://fedorahoted.org/abrt/>
Automatic bug reporting tool
11 years, 3 months
[Automatic Bug Reporting Tool - ABRT] #917: anonymous reporting only
by fedora-badges
#917: anonymous reporting only
-------------------------+--------------------------------------
Reporter: jfilak | Owner: crash-catcher@…
Type: enhancement | Status: new
Priority: major | Milestone: Gnome_Shell_integration
Component: abrt | Version:
Keywords: | Blocked By:
Blocking: |
-------------------------+--------------------------------------
The current implementation of abrt-applet runs an event stored in
autoreporting option after user clicks on the 'Report' button. If the
reported problem is unknown, abrt-applet runs report-gui event, else if
the problem is known, applet shows notification bubble.
With enabled anonymous reporting abrt-applet shows the notification bubble
in all cases.
With enabled anonymous reporting ABRT doesn't care about errors, it goes
headless and shows notification bubble at the end.
Workflow with enabled anonymous reporting and disabled autoreporting:
- 0. Problem detected
- 1. Show notification bubble with Ignore and Report buttons
- 2. Report button clicked
- 3. Autoreporting event run
- 4. Regardless of errors show notification bubble without any button
with the following message:
"Problem in $package has been reported"
Workflow with enabled anonymous reporting and enabled autoreporting:
- 0. Problem detected
- 1. Autoreporting event run
- 2. Regardless of errors shows notification bubble without any button
with the following message:
"Problem in $package has been reported"
--
Ticket URL: <https://fedorahosted.org/abrt/ticket/917>
Automatic Bug Reporting Tool - ABRT <http://fedorahoted.org/abrt/>
Automatic bug reporting tool
11 years, 4 months
[ABRT PATCH 1/2] abrt-applet: update the seen list on every possible action
by Jakub Filak
- losses are still possible during applet termination because of missing
functionality in GTK3
- related to rhbz#886094
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/applet/applet.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 53 insertions(+), 7 deletions(-)
diff --git a/src/applet/applet.c b/src/applet/applet.c
index 7586d11..602e0fa 100644
--- a/src/applet/applet.c
+++ b/src/applet/applet.c
@@ -528,13 +528,6 @@ static void action_report(NotifyNotification *notification, gchar *action, gpoin
run_event_async(pi, get_autoreport_event_name(), REPORT_UNKNOWN_PROBLEM_IMMEDIATELY);
}
-
- /* Scan dirs and save new $XDG_CACHE_HOME/abrt/applet_dirlist.
- * (Oterwise, after a crash, next time applet is started,
- * it will show alert icon even if we did click on it
- * "in previous life"). We ignore finction return value.
- */
- new_dir_exists(/* new dirs list */ NULL);
}
else
problem_info_free(pi);
@@ -613,6 +606,13 @@ static void on_notify_close(NotifyNotification *notification, gpointer user_data
{
VERB3 log("Notify closed!");
g_object_unref(notification);
+
+ /* Scan dirs and save new $XDG_CACHE_HOME/abrt/applet_dirlist.
+ * (Oterwise, after a crash, next time applet is started,
+ * it will show alert icon even if we did click on it
+ * "in previous life"). We ignore finction return value.
+ */
+ new_dir_exists(/* new dirs list */ NULL);
}
static NotifyNotification *new_warn_notification(bool persistence)
@@ -1088,6 +1088,13 @@ static void Crash(DBusMessage* signal)
}
}
+ /*
+ * Can't append dir to the seen list because of directory stealing
+ *
+ * append_dirlist(dir);
+ *
+ */
+
/* If this problem seems to be repeating, do not annoy user with popup dialog.
* (The icon in the tray is not suppressed)
*/
@@ -1324,10 +1331,49 @@ int main(int argc, char** argv)
/* Enter main loop */
gtk_main();
+
+ /* GTK3 doesn't return from main loop in case of termination due to desktop
+ * session end. (GTK handles XSMP (X Session Management Protocol) messages
+ * on its own and exits on session end.)
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=32839
+ * https://bugzilla.gnome.org/show_bug.cgi?id=639770
+ *
+ * !!! None of the following commands will be executed. !!!
+ *
+ * The commands should be pushed into some callback used by deprecated
+ * gtk_quit_add() or proposed g_flush_all()
+ *
+ * Or we can use proposed GtkSMClient (currently available in libegg)
+ * https://live.gnome.org/SessionManagement/EggSMClient
+ *
+ * Or DBus GnomeSession manager (this won't work for other desktops)
+ * http://people.gnome.org/~mccann/gnome-session/docs/gnome-session.html
+ */
+
#if (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 31)
gdk_threads_leave();
#endif
+ /* new_dir_exists() is called for each notification and if user clicks on
+ * the abrt icon. Those calls cover 99.97% of detected crashes
+ *
+ * The rest of detected crashes:
+ *
+ * 0.01%
+ * applet doesn't append a repeated crash to the seen list if the crash was
+ * the last caught crash before exit (notification is not shown in case of
+ * repeated crash)
+ *
+ * 0.01%
+ * applet doesn't append a stolen directory to the seen list if
+ * notification was closed before the notified directory had been stolen
+ *
+ * 0.1%
+ * crashes of abrt-applet
+ */
+ new_dir_exists(/* new dirs list */ NULL);
+
if (notify_is_initted())
notify_uninit();
--
1.7.11.7
11 years, 4 months
[PATCH] report-cli rework
by Denys Vlasenko
This change removes obsolete analyze/collect/report
paradigm and brings report-cli more in line with
report-gtk.
The change is not very easy to review in patch form,
since it significantly changes src/cli/cli-report.c.
It may be easier top apply the patch and review
the resulting src/cli/cli-report.c.
--
vda
diff -urpN libreport.7/src/cli/cli.c libreport.9/src/cli/cli.c
--- libreport.7/src/cli/cli.c 2012-11-14 12:05:15.000000000 +0100
+++ libreport.9/src/cli/cli.c 2012-12-20 13:26:01.166171031 +0100
@@ -60,37 +60,32 @@ int main(int argc, char** argv)
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- "& [-vsp] -L[PREFIX] [PROBLEM_DIR]\n"
- " or: & [-vsp] -e EVENT PROBLEM_DIR\n"
- " or: & [-vsp] -a[y] PROBLEM_DIR\n"
- " or: & [-vsp] -c[y] PROBLEM_DIR\n"
- " or: & [-vsp] -r[y|d] PROBLEM_DIR"
+ "& [-vsp] -L[PREFIX] [PROBLEM_DIR]"
+ "\n"" or: & [-vspy] -e EVENT PROBLEM_DIR"
+ "\n"" or: & [-vspy] -d PROBLEM_DIR"
+ "\n"" or: & [-vspy] -x PROBLEM_DIR"
);
enum {
OPT_list_events = 1 << 0,
OPT_run_event = 1 << 1,
- OPT_analyze = 1 << 2,
- OPT_collect = 1 << 3,
- OPT_report = 1 << 4,
- OPT_version = 1 << 5,
- OPT_delete = 1 << 6,
- OPTMASK_op = OPT_list_events|OPT_run_event|OPT_analyze|OPT_collect|OPT_report|OPT_version,
- OPTMASK_need_arg = OPT_run_event|OPT_analyze|OPT_collect|OPT_report,
- OPT_y = 1 << 7,
- OPT_v = 1 << 8,
- OPT_s = 1 << 9,
- OPT_p = 1 << 10,
+ OPT_delete = 1 << 2,
+ OPT_expert = 1 << 3,
+ OPT_version = 1 << 4,
+ OPT_y = 1 << 5,
+ OPT_v = 1 << 6,
+ OPT_s = 1 << 7,
+ OPT_p = 1 << 8,
+ OPTMASK_op = OPT_list_events|OPT_run_event|OPT_delete|OPT_expert|OPT_version,
+ OPTMASK_need_arg = OPT_run_event|OPT_delete|OPT_expert
};
/* Keep enum above and order of options below in sync! */
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_LIST( 'e', "event" , &event_list, "EVENT", _("Run only these events")),
- OPT_BOOL( 'a', "analyze", NULL, _("Run analyze event(s) on PROBLEM_DIR")),
- OPT_BOOL( 'c', "collect", NULL, _("Run collect event(s) on PROBLEM_DIR")),
- OPT_BOOL( 'r', "report" , NULL, _("Analyze, collect and report problem data in PROBLEM_DIR")),
- OPT_BOOL( 'V', "version", NULL, _("Display version and exit")),
OPT_BOOL( 'd', "delete" , NULL, _("Remove PROBLEM_DIR after reporting")),
+ OPT_BOOL( 'x', "expert" , NULL, _("Expert mode")),
+ OPT_BOOL( 'V', "version", NULL, _("Display version and exit")),
OPT_BOOL( 'y', "always" , NULL, _("Noninteractive: don't ask questions, assume 'yes'")),
OPT__VERBOSE(&g_verbose),
OPT_BOOL( 's', NULL , NULL, _("Log to syslog")),
@@ -104,13 +99,16 @@ int main(int argc, char** argv)
show_usage_and_die(program_usage_string, program_options);
argv += optind;
argc -= optind;
- if (argc > 1
+
+ /* Check for bad usage */
+ if (argc > 1 /* more than one arg? */
+ ||
/* dont_need_arg == have_arg? bad in both cases:
* TRUE == TRUE (dont need arg but have) or
* FALSE == FALSE (need arg but havent).
* OPT_list_events is an exception, it can be used in both cases.
*/
- || ((op != OPT_list_events) && (!(opts & OPTMASK_need_arg) == argc))
+ ((!(opts & OPTMASK_need_arg) == argc) && (op != OPT_list_events))
) {
show_usage_and_die(program_usage_string, program_options);
}
@@ -129,7 +127,7 @@ int main(int argc, char** argv)
}
char *dump_dir_name = argv[0];
- bool always = (opts & OPT_y);
+ g_interactive = !(opts & OPT_y);
/* Get settings */
load_event_config_data();
@@ -145,8 +143,8 @@ int main(int argc, char** argv)
{
case OPT_list_events: /* -L[PREFIX] */
{
- /* Note that dump_dir_name may be NULL here, it means "show all
- * possible events regardless of dir"
+ /* Note that dump_dir_name may be NULL here, it means
+ * "show all possible events regardless of dir"
*/
char *events = list_possible_events(NULL, dump_dir_name, pfx);
if (!events)
@@ -161,57 +159,16 @@ int main(int argc, char** argv)
exitcode = run_events_chain(dump_dir_name, event_list);
break;
}
- case OPT_analyze:
- {
- /* Load problem_data from dump dir */
- struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
- if (!dd)
- return 1;
- char *analyze_events_as_lines = list_possible_events(dd, NULL, "analyze");
- dd_close(dd);
-
- if (analyze_events_as_lines && *analyze_events_as_lines)
- {
- GList *list_analyze_events = str_to_glist(analyze_events_as_lines, '\n');
- char *event = select_event_option(list_analyze_events);
- list_free_with_free(list_analyze_events);
- exitcode = run_analyze_event(dump_dir_name, event);
- free(event);
- }
- free(analyze_events_as_lines);
- break;
- }
- case OPT_collect:
+ case OPT_delete:
{
- exitcode = collect(dump_dir_name, always);
-
- /* Be consistent and return 1 when opening dd failed */
- if (exitcode == -1)
- exitcode = 1;
-
+ dump_dir_name = steal_directory_if_needed(dump_dir_name);
+ exitcode = delete_dump_dir_possibly_using_abrtd(dump_dir_name);
break;
}
- case OPT_report:
+ case OPT_expert:
{
dump_dir_name = steal_directory_if_needed(dump_dir_name);
-
- exitcode = report(dump_dir_name,
- (always ? CLI_REPORT_BATCH : 0));
-
- if (exitcode == -1)
- { /* Be consistent and return 1 */
- exitcode = 1;
- /* Can't use error_msg_and_die() function because we want to
- * store user's answers on yes/no/yes forever questions */
- error_msg("Crash '%s' not found", dump_dir_name);
- }
- else if (opts & OPT_delete)
- {
- int r = delete_dump_dir_possibly_using_abrtd(dump_dir_name);
- if (exitcode == 0)
- exitcode = r;
- }
-
+ exitcode = select_one_event_and_run_interactively(dump_dir_name, pfx);
break;
}
}
diff -urpN libreport.7/src/cli/cli-report.c libreport.9/src/cli/cli-report.c
--- libreport.7/src/cli/cli-report.c 2012-12-06 16:18:16.000000000 +0100
+++ libreport.9/src/cli/cli-report.c 2012-12-20 13:30:45.303737201 +0100
@@ -23,6 +23,8 @@
/* Field separator for the crash report file that is edited by user. */
#define FIELD_SEP "%----"
+int g_interactive;
+
/*
* Escapes the field content string to avoid confusion with file comments.
* Returned field must be free()d by caller.
@@ -382,7 +384,7 @@ static void read_from_stdin(const char *
fflush(NULL);
if (NULL == fgets(result, result_size, stdin))
result[0] = '\0';
- // Remove the newline from the login.
+ // Remove the trailing newline
strchrnul(result, '\n')[0] = '\0';
}
@@ -406,31 +408,6 @@ static bool ask_yesno(const char *questi
return 0 == strncmp(answer, yes, strlen(yes));
}
-/* Returns true if the string contains the specified number. */
-static bool is_number_in_string(unsigned number, const char *str)
-{
- const char *c;
- char numstr[sizeof(int) * 3 + 2];
- int len;
-
- len = snprintf(numstr, sizeof(numstr), "%u", number);
- for (c = str; *c; c++)
- {
- c = strstr(c, numstr);
- if (!c)
- /* no such number exists in the string */
- return false;
- if ((c == str || !isalnum(c[-1])) && !isalnum(c[len]))
- /* found */
- return true;
-
- /* found, but it's part of another number. Continue
- * from the next position. */
- }
-
- return false;
-}
-
/**
* Asks user for missing information
*/
@@ -507,79 +484,16 @@ static void ask_for_missing_settings(con
}
/* we ask for 3 times and still don't have valid infromation */
- error_msg_and_die("Invalid input, program exiting...");
+ error_msg_and_die("Invalid input, exiting.");
}
-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_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);
+/*** Event running ***/
- 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;
-
- // Run events
- 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 (GList *li = events; li; li = li->next)
- {
- char *event = (char *) li->data;
- if (run_event(run_state, dump_dir_name, event, &l_state) == 0)
- {
- printf("%s: ", event);
- if (l_state.last_line)
- printf("%s\n", l_state.last_line);
- else
- printf("%s succeeded\n", event_type);
- }
- else
- {
- error_msg("%s via '%s' was not successful%s%s",
- event_type,
- event,
- 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);
-
- return error_cnt;
-}
+struct logging_state {
+ bool saw_THANKYOU;
+ bool output_was_produced;
+};
static char *do_log(char *log_line, void *param)
{
@@ -587,165 +501,59 @@ static char *do_log(char *log_line, void
return log_line;
}
-int run_analyze_event(const char *dump_dir_name, const char *analyzer)
+static char *do_log_and_check_for_THANKYOU(char *log_line, void *param)
{
- 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, analyzer);
- free_run_event_state(run_state);
- return res;
+ struct logging_state *l_state = param;
+ l_state->saw_THANKYOU |= (strcmp("THANKYOU", log_line) == 0);
+ l_state->output_was_produced |= (log_line[0] != '\0');
+ log("%s", log_line);
+ return log_line;
}
-/* show even description? */
-char *select_event_option(GList *list_options)
+static int export_config_and_run_event(
+ struct run_event_state *state,
+ const char *dump_dir_name,
+ const char *event)
{
- if (!list_options)
- return NULL;
-
- unsigned count = g_list_length(list_options);
- if (count == 1)
- return xstrdup((char*)list_options->data);
-
- int pos = 0;
- fprintf(stdout, _("How you would like to analyze the problem?\n"));
- for (GList *li = list_options; li; li = li->next)
- {
- char *opt = (char*)li->data;
- event_config_t *config = get_event_config(opt);
- if (config)
- {
- ++pos;
- printf(" %i) %s\n", pos, ec_get_screen_name(config));
- }
- }
-
- unsigned picked;
- unsigned ii;
- for (ii = 0; ii < 3; ++ii)
- {
- char answer[16];
-
- read_from_stdin(_("Select analyzer: "), answer, sizeof(answer));
- if (!*answer)
- continue;
-
- picked = xatou(answer);
- if (picked > count || picked < 1)
- {
- fprintf(stdout, _("You have chosen number out of range"));
- fprintf(stdout, "\n");
- continue;
- }
+ /* Export overridden settings as environment variables */
+ GList *env_list = export_event_config(event);
- break;
- }
+ int r = run_event_on_dir_name(state, dump_dir_name, event);
- if (ii == 3)
- error_msg_and_die(_("Invalid input, program exiting..."));
+ unexport_event_config(env_list);
- GList *choosen = g_list_nth(list_options, picked - 1);
- return xstrdup((char*)choosen->data);
+ return r;
}
-GList *str_to_glist(char *str, int delim)
+static int is_not_reportable(problem_data_t *problem_data)
{
- GList *list = NULL;
- while (*str)
+ const char *not_reportable = problem_data_get_content_or_NULL(problem_data, FILENAME_NOT_REPORTABLE);
+ if (not_reportable)
{
- char *end = strchrnul(str, delim);
- if (end != str)
- list = g_list_append(list, xstrndup(str, end - str));
-
- str = end;
- if (!*str)
- break;
- str++;
+ printf("%s\n", not_reportable);
+ return 1;
}
-
- if (!list && !g_list_length(list))
- return NULL;
-
- return list;
+ return 0;
}
-/* Runs collect_* events if there are any. If batch is nonzero, no questions
- * are asked and positive answers are assumed, i.e. all events are ran.
- * returns: 0: success
- * -1: failed to open dumpdir
- * >0: number of errors encountered when running the events
- */
-int collect(const char *dump_dir_name, int batch)
+static int is_backtrace_rating_usable(event_config_t *config, problem_data_t *problem_data)
{
- int errors = 0;
- char wanted_collectors[255];
- GList *selected_events = NULL;
-
- struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
- if (!dd)
- return -1;
-
- char *collect_events_as_lines = list_possible_events(dd, NULL, "collect");
- dd_close(dd);
-
- /* return if there are no collect events */
- if (!collect_events_as_lines)
- return 0;
-
- if (!*collect_events_as_lines)
- {
- free(collect_events_as_lines);
- return 0;
- }
-
- GList *list_collect_events = str_to_glist(collect_events_as_lines, '\n');
- free(collect_events_as_lines);
-
- if (!batch)
- {
- GList *li;
- unsigned i;
-
- puts(_("What additional information would you like to collect?"));
- /* Print list of collectors and ask the user which should be used. */
- for (li = list_collect_events, i = 1; li; li = li->next, i++)
- {
- char *collector_name = (char *) li->data;
- event_config_t *config = get_event_config(collector_name);
-
- if (!config)
- VERB1 log("No configuration file found for collector '%s'", collector_name);
-
- printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : collector_name);
- }
-
- read_from_stdin(_("Select collector(s): "), wanted_collectors, sizeof(wanted_collectors));
-
- for (li = list_collect_events, i = 1; li; li = li->next, i++)
- {
- char *collector_name = (char *) li->data;
-
- /* Was this collector requested? */
- if (!is_number_in_string(i, wanted_collectors))
- continue;
+ char *usability_description = NULL;
+ char *usability_detail = NULL;
+ const bool usable_rating = check_problem_rating_usability(config, problem_data,
+ &usability_description,
+ &usability_detail);
- selected_events = g_list_append(selected_events, collector_name);
- }
- }
- else
+ if (!usable_rating)
{
- /* run all collectors in noninteractive mode */
- selected_events = list_collect_events;
+ printf("%s\n", usability_description);
+ printf("%s\n", usability_detail);
}
- errors = run_events(dump_dir_name, selected_events, "Collection");
-
- list_free_with_free(list_collect_events);
- if (!batch)
- g_list_free(selected_events);
+ free(usability_description);
+ free(usability_detail);
- return errors;
+ return usable_rating;
}
static int review_problem_data(const char *dump_dir_name, problem_data_t *problem_data)
@@ -773,197 +581,177 @@ static int review_problem_data(const cha
return 0;
}
-static int is_backtrace_rating_usable(event_config_t *config, problem_data_t *problem_data)
+static problem_data_t *load_problem_data_if_not_yet(problem_data_t *problem_data, const char *dump_dir_name)
{
- 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 (problem_data)
+ return problem_data;
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
{
- printf("%s\n", usability_description);
- printf("%s\n", usability_detail);
+ problem_data_free(problem_data);
+ return NULL;
}
-
- free(usability_description);
- free(usability_detail);
-
- return usable_rating;
+ problem_data = create_problem_data_from_dump_dir(dd);
+ dd_close(dd);
+ return problem_data;
}
-/* Report the crash */
-int report(const char *dump_dir_name, int flags)
+int run_event_on_dir_name_interactively(
+ struct run_event_state *state,
+ const char *dump_dir_name,
+ const char *event_name)
{
- /* Load problem_data from (possibly updated by analyze) dump dir */
- struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (!dd)
- return -1;
-
- char *not_reportable = dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
- | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
- | DD_FAIL_QUIETLY_ENOENT
- | DD_FAIL_QUIETLY_EACCES);
+ int retval = -1;
+ problem_data_t *problem_data = NULL;
- if (not_reportable)
+ event_config_t *config = get_event_config(event_name);
+ if (config)
{
- char *reason = dd_load_text_ext(dd, FILENAME_REASON, 0
- | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
- char *t = xasprintf("%s%s%s",
- not_reportable ? : "",
- not_reportable ? " " : "",
- reason ? : _("(no description)"));
-
- dd_close(dd);
- error_msg("%s", t);
- free(t);
- xfunc_die();
- }
+ if (config->ec_minimal_rating != 0)
+ {
+ problem_data = load_problem_data_if_not_yet(problem_data, dump_dir_name);
+ if (!problem_data)
+ goto ret;
+ if (!is_backtrace_rating_usable(config, problem_data))
+ goto ret;
+ }
- char *analyze_events_as_lines = list_possible_events(dd, NULL, "analyze");
- dd_close(dd);
+ if (config->ec_sending_sensitive_data)
+ {
+ /* We assume this event is a reporter */
- if (analyze_events_as_lines && *analyze_events_as_lines)
- {
- GList *list_analyze_events = str_to_glist(analyze_events_as_lines, '\n');
- free(analyze_events_as_lines);
+ /* Is problem non-reportable? */
+ problem_data = load_problem_data_if_not_yet(problem_data, dump_dir_name);
+ if (!problem_data)
+ goto ret;
+ if (is_not_reportable(problem_data))
+ goto ret;
- char *event = select_event_option(list_analyze_events);
- list_free_with_free(list_analyze_events);
+ char *msg = xasprintf(_("Event '%s' requires permission to send possibly sensitive data."
+ " Do you want to continue?"),
+ ec_get_screen_name(config) ? ec_get_screen_name(config) : event_name);
+ bool ok = ask_yesno(msg);
+ free(msg);
+ if (!ok)
+ goto ret;
+ }
- int analyzer_result = run_analyze_event(dump_dir_name, event);
- free(event);
+ /* can't fail */
+ ask_for_missing_settings(event_name);
- if (analyzer_result != 0)
- return 1;
+ /* review problem data only if the event needs it */
+ if (!config->ec_skip_review)
+ {
+ problem_data = load_problem_data_if_not_yet(problem_data, dump_dir_name);
+ if (!problem_data)
+ goto ret;
+ retval = review_problem_data(dump_dir_name, problem_data);
+ if (retval != 0)
+ /* review failed, an error message was already logged */
+ goto ret;
+ }
}
- /* Run collect events if there are any */
- int collect_res = collect(dump_dir_name, flags & CLI_REPORT_BATCH);
- if (collect_res == -1)
- return -1;
- else if (collect_res > 0)
- printf(_("There were %d errors while collecting additional data\n"), collect_res);
+ problem_data_free(problem_data);
+ problem_data = NULL;
- /* Load dd from (possibly updated by collect) dump dir */
- dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (!dd)
- return -1;
+ retval = export_config_and_run_event(state, dump_dir_name, event_name);
- char *report_events_as_lines = list_possible_events(dd, NULL, "report");
- problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
- dd_close(dd);
+ ret:
+ problem_data_free(problem_data);
+ return retval;
+}
- if (!(flags & (CLI_REPORT_BATCH))
- && review_problem_data(dump_dir_name, problem_data))
+static GList *str_to_glist(const char *str, int delim)
+{
+ GList *list = NULL;
+ while (*str)
{
- problem_data_free(problem_data);
- free(report_events_as_lines);
- return 1;
- }
+ char *end = strchrnul(str, delim);
+ if (end != str)
+ list = g_list_append(list, xstrndup(str, end - str));
- /* Get possible reporters associated with this particular crash */
- GList *report_events = NULL;
- if (report_events_as_lines && *report_events_as_lines)
- report_events = str_to_glist(report_events_as_lines, '\n');
+ str = end;
+ if (!*str)
+ break;
+ str++;
+ }
- free(report_events_as_lines);
+ return list;
+}
- if (!report_events)
- {
- problem_data_free(problem_data);
- error_msg_and_die("The problem directory '%s' has no defined reporters",
- dump_dir_name);
- }
+static char *select_event_name(GList *list_options)
+{
+ if (!list_options)
+ return NULL;
- /* Get settings */
- load_event_config_data();
+ /* Just one? */
+ if (!list_options->next)
+ return xstrdup((char*)list_options->data);
- int errors = 0;
- int plugins = 0;
- if (flags & CLI_REPORT_BATCH)
+ int count = 0;
+ for (GList *li = list_options; li; li = li->next)
{
- puts(_("Reporting..."));
- errors += run_events(dump_dir_name, report_events, "Reporting");
- plugins += g_list_length(report_events);
+ char *opt = (char*)li->data;
+ event_config_t *config = get_event_config(opt);
+ count++;
+ printf(" %i) %s\n", count, config ? ec_get_screen_name(config) : opt);
}
- else
- {
- unsigned i;
- GList *li;
- char wanted_reporters[255];
-
- puts(_("How would you like to report the problem?"));
- /* Print list of reporters and ask the user which should be used. */
- for (li = report_events, i = 1; li; li = li->next, i++)
- {
- char *reporter_name = (char *) li->data;
- event_config_t *config = get_event_config(reporter_name);
-
- printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : reporter_name);
- }
- read_from_stdin(_("Select reporter(s): "), wanted_reporters, sizeof(wanted_reporters));
+ unsigned picked;
+ unsigned ii;
+ for (ii = 0; ii < 3; ++ii)
+ {
+ char answer[16];
- for (li = report_events, i = 1; li; li = li->next, i++)
- {
- char *reporter_name = (char *) li->data;
- event_config_t *config = get_event_config(reporter_name);
+ read_from_stdin(_("Select an event to run: "), answer, sizeof(answer));
+ if (!*answer)
+ continue;
- if (!config)
- VERB1 log("No configuration file found for '%s' reporter", reporter_name);
+ picked = xatou(answer);
+ if (picked <= count && picked != 0)
+ break;
- /* Was this reporter requested? */
- if (!is_number_in_string(i, wanted_reporters))
- continue;
+ printf("%s\n", _("You have chosen number out of range"));
+ }
- if (!is_backtrace_rating_usable(config, problem_data))
- {
- errors++;
- goto next_plugin;
- }
+ if (ii == 3)
+ error_msg_and_die(_("Invalid input, exiting."));
- ask_for_missing_settings(reporter_name);
+ GList *chosen = g_list_nth(list_options, picked - 1);
+ return xstrdup((char*)chosen->data);
+}
- /*
- * to avoid creating list with one item, we probably should
- * provide something like
- * run_event(char*, char*)
- */
- GList *cur_event = NULL;
- cur_event = g_list_append(cur_event, reporter_name);
- errors += run_events(dump_dir_name, cur_event, "Reporting");
- g_list_free(cur_event);
+int select_one_event_and_run_interactively(const char *dump_dir_name, const char *pfx)
+{
+ char *events_as_lines = list_possible_events(NULL, dump_dir_name, pfx);
-next_plugin:
- plugins++;
- }
- }
+ if (!events_as_lines)
+ return -1;
- printf(_("Problem reported via %d report events (%d errors)\n"), plugins, errors);
- problem_data_free(problem_data);
- list_free_with_free(report_events);
- return errors;
-}
+//FIXME: why use intermediate representation?
+ GList *list_events = str_to_glist(events_as_lines, '\n');
+ free(events_as_lines);
+ char *event_name = select_event_name(list_events);
+ list_free_with_free(list_events);
-struct chain_logging_param
-{
- struct logging_state l_state;
- bool terminate;
-};
+ struct run_event_state *run_state = new_run_event_state();
+ run_state->logging_callback = do_log;
+ int r = g_interactive
+ ? run_event_on_dir_name_interactively(run_state, dump_dir_name, event_name)
+//FIXME: still need to check is_backtrace_rating_usable() and is_not_reportable():
+ : export_config_and_run_event(run_state, dump_dir_name, event_name)
+ ;
-static char *do_log_and_terminate_chain_on_request(char *log_line, void *param)
-{
- struct chain_logging_param *arg = (struct chain_logging_param *)param;
+ free_run_event_state(run_state);
- arg->terminate = strcmp("THANKYOU", log_line) == 0;
+ free(event_name);
- return do_log_and_save_line(log_line, &(arg->l_state));
+ return r;
}
/*
- * Runs event from chain. Perform the following steps for each event from chain.
+ * Run 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.
@@ -971,80 +759,52 @@ static char *do_log_and_terminate_chain_
* 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.
+ * 7. Continues 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;
- memset(&chain_state, 0, sizeof(chain_state));
+ struct logging_state l_state;
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;
+ run_state->logging_callback = do_log_and_check_for_THANKYOU;
+ run_state->logging_param = &l_state;
- for (GList *eitem = chain; !chain_state.terminate && eitem; eitem = g_list_next(eitem))
+ int retval = 0;
+ for (GList *eitem = chain; eitem; eitem = g_list_next(eitem))
{
- const char *const event = (const char *)eitem->data;
- event_config_t *config = get_event_config(event);
+ l_state.saw_THANKYOU = 0;
+ l_state.output_was_produced = 0;
+ const char *event_name = eitem->data;
+ retval = g_interactive
+ ? run_event_on_dir_name_interactively(run_state, dump_dir_name, event_name)
+//FIXME: still need to check is_backtrace_rating_usable() and is_not_reportable():
+ : export_config_and_run_event(run_state, dump_dir_name, event_name)
+ ;
- if (!is_backtrace_rating_usable(config, problem_data))
- /* it is not a failure of event if the backtrace is unusable */
+ if (retval < 0)
+ /* Nothing was run (bad backtrace, user declined, etc... */
break;
-
- if (config)
+ if (retval == 0 && run_state->children_count == 0)
{
- if (config->ec_sending_sensitive_data)
- {
- char *msg = xasprintf(_("Event '%s' requires permission to send possibly sensitive data."
- " Do you want to continue?"),
- ec_get_screen_name(config) ? ec_get_screen_name(config) : event);
- const bool response = ask_yesno(msg);
- free(msg);
- if (!response)
- break;
- }
-
- /* 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;
- }
+ printf("Error: no processing is specified for event '%s'", event_name);
+ retval = 1;
}
-
- returncode = run_event(run_state, dump_dir_name, event, &chain_state.l_state);
- if (returncode != 0)
+ else
+ /* If program failed, or if it finished successfully without saying anything... */
+ if (retval != 0 || !l_state.output_was_produced)
{
- 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;
+ if (WIFSIGNALED(run_state->process_status))
+ printf("(killed by signal %u)\n", WTERMSIG(run_state->process_status));
+ else
+ printf("(exited with %u)\n", retval);
}
-
- free(chain_state.l_state.last_line);
- chain_state.l_state.last_line = NULL;
+ if (retval != 0)
+ break;
+ if (l_state.saw_THANKYOU)
+ break;
}
free_run_event_state(run_state);
- free(chain_state.l_state.last_line);
- problem_data_free(problem_data);
- return returncode;
+ return retval;
}
diff -urpN libreport.7/src/cli/cli-report.h libreport.9/src/cli/cli-report.h
--- libreport.7/src/cli/cli-report.h 2012-11-14 12:05:15.000000000 +0100
+++ libreport.9/src/cli/cli-report.h 2012-12-20 13:26:10.289156983 +0100
@@ -22,16 +22,9 @@
extern "C" {
#endif
-int run_analyze_event(const char *dump_dir_name, const char *analyzer);
-char *select_event_option(GList *list_options);
-GList *str_to_glist(char *str, int delim);
+extern int g_interactive;
-/* Report the crash */
-enum {
- CLI_REPORT_BATCH = 1 << 0,
-};
-int report(const char *dump_dir_name, int flags);
-int collect(const char *dump_dir_name, int batch);
+int select_one_event_and_run_interactively(const char *dump_dir_name, const char *pfx);
int run_events_chain(const char *dump_dir_name, GList *chain);
#ifdef __cplusplus
diff -urpN libreport.7/src/gui-wizard-gtk/main.c libreport.9/src/gui-wizard-gtk/main.c
--- libreport.7/src/gui-wizard-gtk/main.c 2012-12-04 15:40:28.000000000 +0100
+++ libreport.9/src/gui-wizard-gtk/main.c 2012-12-18 12:21:49.000000000 +0100
@@ -102,9 +102,9 @@ int main(int argc, char **argv)
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
- "& [-vpd] [-g GUI_FILE] DIR\n"
+ "& [-vpdx] [-e EVENT]... [-g GUI_FILE] PROBLEM_DIR\n"
"\n"
- "GUI tool to analyze and report problem saved in specified DIR"
+ "GUI tool to analyze and report problem saved in specified PROBLEM_DIR"
);
enum {
OPT_v = 1 << 0,
@@ -119,10 +119,9 @@ int main(int argc, char **argv)
OPT__VERBOSE(&g_verbose),
OPT_STRING('g', NULL, &g_glade_file, "FILE", _("Alternate GUI file")),
OPT_BOOL( 'p', NULL, NULL, _("Add program names to log")),
- /* for use from 3rd party apps to show just a reporter selector */
- OPT_BOOL( 'd', "delete", NULL, _("Remove DIR after reporting")),
- OPT_LIST( 'e', "event", &g_auto_event_list, "EVENT", _("Run only this event")),
- OPT_BOOL( 'x', "expert", &expert_mode, _("Run wizard in expert mode - shows advanced options")),
+ OPT_BOOL( 'd', "delete", NULL, _("Remove PROBLEM_DIR after reporting")),
+ OPT_LIST( 'e', "event", &g_auto_event_list, "EVENT", _("Run only these events")),
+ OPT_BOOL( 'x', "expert", &expert_mode, _("Expert mode")),
OPT_END()
};
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
11 years, 4 months