summaryrefslogtreecommitdiffstats
path: root/src/cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/Makefile.am49
-rw-r--r--src/cli/abrt-cli.158
-rw-r--r--src/cli/abrt-cli.txt75
-rw-r--r--src/cli/abrt-handle-crashdump.c99
-rw-r--r--src/cli/cli.c299
-rw-r--r--src/cli/report.c82
6 files changed, 405 insertions, 257 deletions
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am
index d6cd5ef2..bc02236e 100644
--- a/src/cli/Makefile.am
+++ b/src/cli/Makefile.am
@@ -1,4 +1,8 @@
-bin_PROGRAMS = abrt-cli
+-include ../../config.mak
+
+bin_PROGRAMS = \
+ abrt-handle-crashdump \
+ abrt-cli
abrt_cli_SOURCES = \
cli.c \
@@ -19,10 +23,49 @@ abrt_cli_LDADD = \
../lib/libabrt_dbus.la \
$(GLIB_LIBS)
-man_MANS = abrt-cli.1
-EXTRA_DIST = $(man_MANS)
+abrt_handle_crashdump_SOURCES = \
+ abrt-handle-crashdump.c
+abrt_handle_crashdump_CPPFLAGS = \
+ -I$(srcdir)/../include/report -I$(srcdir)/../include \
+ -I$(srcdir)/../lib \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DLOCALSTATEDIR='"$(localstatedir)"' \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -DLIBEXEC_DIR=\"$(LIBEXEC_DIR)\" \
+ $(GLIB_CFLAGS) \
+ -D_GNU_SOURCE \
+ -Wall -Wwrite-strings -Werror
+abrt_handle_crashdump_LDADD = \
+ ../lib/libreport.la
+
+MAN_TXT = \
+ abrt-cli.txt
+
+# Manual pages are generated from .txt via Docbook
+man1_MANS = ${MAN_TXT:%.txt=%.1}
+
+%.1 %.5 %.7: %.xml
+ $(XMLTO_SILENT) xmlto man $< 2>&1 | sed '/Note/d'
+
+%.xml: %.txt ../../asciidoc.conf
+ $(ASCIIDOC_SILENT) asciidoc --backend=docbook --doctype=manpage --conf-file ../../asciidoc.conf -aabrt_version=$(PACKAGE_VERSION) -o $@ $<
+
+CLEANFILES = $(man1_MANS)
+
+PYTHON_FILES = \
+ abrt-action-install-debuginfo.py \
+ abrt-action-list-dsos.py \
+ abrt-action-analyze-core.py
completiondir = $(sysconfdir)/bash_completion.d
dist_completion_DATA = abrt-cli.bash
DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
+
+EXTRA_DIST = $(MAN_TXT)
+
diff --git a/src/cli/abrt-cli.1 b/src/cli/abrt-cli.1
deleted file mode 100644
index 9e0a630e..00000000
--- a/src/cli/abrt-cli.1
+++ /dev/null
@@ -1,58 +0,0 @@
-.TH abrt\-cli "1" "12 Oct 2009" ""
-.SH NAME
-abrt\-cli \- a command line interface to abrt
-.SH SYNOPSIS
-.B abrt\-cli
-[option]
-.SH DESCRIPTION
-.I abrt\-cli
-is a command line tool that manages application crashes catched by
-.I abrtd
-daemon. It enables access to problem data, and allows to report
-problems depending on active abrt plugins.
-.SH OPTIONS
-.B Basic startup options
-.IP "\-V, \-\-version"
-Displays version of abrt\-cli.
-.IP "\-?, \-\-help"
-Print a help message describing all of abrt-cli’s command-line options.
-
-.PP
-.B Crash action options
-.IP "\-l, \-\-list"
-Prints list of crashes which are not reported yet.
-.IP "\-r, \-\-report \fIDUMPDIR\fR"
-Creates a crash report and then the text editor is invoked on that
-report. When you are done with editing the report just exit the editor
-and then you will be asked if you want to send the report.
-.IP "\-d, \-\-delete \fIDUMPDIR\fR"
-Removes data about particular crash.
-.IP "\-i, \-\-info \fIDUMPDIR\fR"
-Prints detailed information about particular crash.
-
-.PP
-.B Listing options
-.IP "\-f, \-\-full"
-List all crashes, including already reported.
-
-.PP
-.B Report options
-.IP "\-y, \-\-always"
-Creates and sends the crash report automatically, without asking
-any questions.
-
-.PP
-.B Info options
-.IP "\-b, \-\-backtrace"
-Includes the crash backtrace in the info output if the backtrace is
-available.
-
-.SH ENVIRONMENT VARIABLES
-The editor used to edit the crash report is chosen from the
-ABRT_EDITOR environment variable, the VISUAL environment variable, or
-the EDITOR environment variable, in that order.
-
-.SH SEE ALSO
-.IR abrtd (8),
-.IR abrt.conf (5),
-.IR abrt-plugins (7)
diff --git a/src/cli/abrt-cli.txt b/src/cli/abrt-cli.txt
new file mode 100644
index 00000000..ea3111c8
--- /dev/null
+++ b/src/cli/abrt-cli.txt
@@ -0,0 +1,75 @@
+abrt-cli(1)
+===========
+
+NAME
+----
+abrt-cli - Work with ABRT dump directories from command line.
+
+SYNOPSIS
+--------
+'abrt-cli' [-vsp] -l[f] [-D BASE_DIR]...
+
+'abrt-cli' [-vsp] -i[f] DUMP_DIR
+
+'abrt-cli' [-vsp] -L[PREFIX] [DUMP_DIR]
+
+'abrt-cli' [-vsp] -e EVENT DUMP_DIR
+
+'abrt-cli' [-vsp] -a[y] DUMP_DIR
+
+'abrt-cli' [-vsp] -r[y] DUMP_DIR
+
+'abrt-cli' [-vsp] -d DUMP_DIR
+
+DESCRIPTION
+-----------
+'abrt-cli' is a command line tool that manages application crashes and other problems
+catched by abrtd daemon. It enables access to, manipulation of problem data, and reporting.
+
+OPTIONS
+-------
+-l::
+ List not yet reported problems, or all problems with -f
+
+-D BASE_DIR::
+ Directory to list problems from (default: -D $HOME/.abrt/spool -D /var/spool/abrt)
+
+-i, --info::
+ Print information about DUMP_DIR (detailed with -f)
+
+-L[PREFIX]::
+ List possible events [which start with PREFIX]
+
+-e EVENT::
+ Run EVENT on DUMP_DIR
+
+-a, --analyze::
+ Run analyze event(s) on DUMP_DIR
+
+-r, --report::
+ Send a report about DUMP_DIR
+
+-d, --delete::
+ Remove DUMP_DIR
+
+-f, --full::
+ Full listing
+
+-y, --always::
+ Noninteractive: don't ask questions, assume positive answer to all of them
+
+-v, --verbose::
+ Be verbose
+
+-s::
+ Log to syslog
+
+-p::
+ Add program names to log
+
+-V, --version::
+ Display version and exit
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/cli/abrt-handle-crashdump.c b/src/cli/abrt-handle-crashdump.c
new file mode 100644
index 00000000..d04e4fef
--- /dev/null
+++ b/src/cli/abrt-handle-crashdump.c
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2010 ABRT team
+ Copyright (C) 2010 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "abrtlib.h"
+#include "parse_options.h"
+
+static const char *dump_dir_name = NULL;
+//static const char *conf_filename = CONF_DIR"/abrt_event.conf";
+static const char *event;
+static const char *pfx = "";
+
+static char *do_log(char *log_line, void *param)
+{
+ log("%s", log_line);
+ return log_line;
+}
+
+int main(int argc, char **argv)
+{
+ abrt_init(argv);
+
+ /* Can't keep these strings/structs static: _() doesn't support that */
+ const char *program_usage_string = _(
+ "\b [-vs]" /*" [-c CONFFILE]"*/ " -d DIR -e EVENT\n"
+ " or: \b [-vs]" /*" [-c CONFFILE]"*/ " [-d DIR] -l[PFX]\n"
+ "\n"
+ "Handles dump directory DIR according to rules in abrt_event.conf"
+ );
+ enum {
+ OPT_v = 1 << 0,
+ OPT_s = 1 << 1,
+ OPT_d = 1 << 2,
+ OPT_e = 1 << 3,
+ OPT_l = 1 << 4,
+ OPT_p = 1 << 5,
+// OPT_c = 1 << ?,
+ };
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ OPT__VERBOSE(&g_verbose),
+ OPT_BOOL( 's', NULL, NULL , _("Log to syslog" )),
+ OPT_STRING( 'd', NULL, &dump_dir_name, "DIR" , _("Dump directory")),
+ OPT_STRING( 'e', NULL, &event , "EVENT" , _("Handle EVENT" )),
+ OPT_OPTSTRING('l', NULL, &pfx , "PFX" , _("List possible events [which start with PFX]")),
+ OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")),
+// OPT_STRING( 'c', NULL, &conf_filename, "CONFFILE", _("Configuration file" )),
+ OPT_END()
+ };
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+ if (!(opts & (OPT_e|OPT_l)))
+ show_usage_and_die(program_usage_string, program_options);
+
+ export_abrt_envvars(opts & OPT_p);
+
+ if (opts & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+ }
+
+ if (opts & OPT_l)
+ {
+ /* 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)
+ return 1; /* error msg is already logged */
+ fputs(events, stdout);
+ free(events);
+ return 0;
+ }
+
+ /* -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 ? dump_dir_name : ".", event);
+ if (r == 0 && run_state->children_count == 0)
+ error_msg_and_die("No actions are found for event '%s'", event);
+ free_run_event_state(run_state);
+
+ return r;
+}
diff --git a/src/cli/cli.c b/src/cli/cli.c
index 1a84b1a5..3981c1bc 100644
--- a/src/cli/cli.c
+++ b/src/cli/cli.c
@@ -120,92 +120,15 @@ static void print_crash_info(problem_data_t *problem_data, bool show_multiline)
free(desc);
}
-/* Program options */
-enum
+static char *do_log(char *log_line, void *param)
{
- OPT_GET_LIST,
- OPT_REPORT,
- OPT_DELETE,
- OPT_INFO
-};
-
-/**
- * Long options.
- * Do not use the has_arg field. Arguments are handled after parsing all options.
- * The reason is that we want to use all the following combinations:
- * --report ID
- * --report ID --always
- * --report --always ID
- */
-static const struct option longopts[] =
-{
- /* name, has_arg, flag, val */
- { "help" , no_argument, NULL, '?' },
- { "verbose" , no_argument, NULL, 'v' },
- { "version" , no_argument, NULL, 'V' },
- { "list" , no_argument, NULL, 'l' },
- { "full" , no_argument, NULL, 'f' },
- { "always" , no_argument, NULL, 'y' },
- { "report" , no_argument, NULL, 'r' },
- { "delete" , no_argument, NULL, 'd' },
- { "info" , no_argument, NULL, 'i' },
- { 0, 0, 0, 0 } /* prevents crashes for unknown options*/
-};
-
-/* Gets the program name from the first command line argument. */
-static const char *progname(const char *argv0)
-{
- const char* name = strrchr(argv0, '/');
- if (name)
- return ++name;
- return argv0;
-}
-
-/**
- * Prints abrt-cli version and some help text.
- * Then exits the program with return value 1.
- */
-static void print_usage_and_die(char *argv0)
-{
- const char *name = progname(argv0);
- printf("%s "VERSION"\n\n", name);
-
- /* Message has embedded tabs. */
- printf(_(
- "Usage: %s -l[f] [-D BASE_DIR]...]\n"
- " or: %s -r[y] CRASH_DIR\n"
- " or: %s -i[b] CRASH_DIR\n"
- " or: %s -d CRASH_DIR\n"
- "\n"
- " -l, --list List not yet reported problems\n"
- " -f, --full List all problems\n"
- " -D BASE_DIR Directory to list problems from\n"
- " (default: -D $HOME/.abrt/spool -D %s)\n"
- "\n"
- " -r, --report Send a report about CRASH_DIR\n"
- " -y, --always ...without editing and asking\n"
- " -i, --info Print detailed information about CRASH_DIR\n"
- " -f, --full ...including multi-line entries\n"
- " Note: -if will run analyzers\n"
- " (if this CRASH_DIR have defined analyzers)\n"
- " -d, --delete Remove CRASH_DIR\n"
- "\n"
- " -V, --version Display version and exit\n"
- " -v, --verbose Be verbose\n"
- ),
- name, name, name, name,
- DEBUG_DUMPS_DIR
- );
- exit(1);
+ log("%s", log_line);
+ return log_line;
}
int main(int argc, char** argv)
{
- GList *D_list = NULL;
- char *dump_dir_name = NULL;
- int op = -1;
- bool full = false;
- bool always = false;
+ abrt_init(argv);
setlocale(LC_ALL, "");
#if ENABLE_NLS
@@ -213,41 +136,91 @@ int main(int argc, char** argv)
textdomain(PACKAGE);
#endif
- while (1)
- {
- /* Do not use colons, arguments are handled after parsing all options. */
- int c = getopt_long(argc, argv, "?Vvrdlfyib", longopts, NULL);
+ GList *D_list = NULL;
+ const char *event_name = NULL;
+ const char *pfx = "";
+
+ /* Can't keep these strings/structs static: _() doesn't support that */
+ const char *program_usage_string = _(
+ "\b [-vsp] -l[f] [-D BASE_DIR]...\n"
+ "or: \b [-vsp] -i[f] DUMP_DIR\n"
+ "or: \b [-vsp] -L[PREFIX] [DUMP_DIR]\n"
+ "or: \b [-vsp] -e EVENT DUMP_DIR\n"
+ "or: \b [-vsp] -a[y] DUMP_DIR\n"
+ "or: \b [-vsp] -r[y] DUMP_DIR\n"
+ "or: \b [-vsp] -d DUMP_DIR"
+ );
+ enum {
+ OPT_list = 1 << 0,
+ OPT_D = 1 << 1,
+ OPT_info = 1 << 2,
+ OPT_list_events = 1 << 3,
+ OPT_run_event = 1 << 4,
+ OPT_analyze = 1 << 5,
+ OPT_report = 1 << 6,
+ OPT_delete = 1 << 7,
+ OPT_version = 1 << 8,
+ OPTMASK_op = OPT_list|OPT_info|OPT_list_events|OPT_run_event|OPT_analyze|OPT_report|OPT_delete|OPT_version,
+ OPTMASK_need_arg = OPT_info|OPT_run_event|OPT_analyze|OPT_report|OPT_delete,
+ OPT_f = 1 << 9,
+ OPT_y = 1 << 10,
+ OPT_v = 1 << 11,
+ OPT_s = 1 << 12,
+ OPT_p = 1 << 13,
+ };
+ /* Keep enum above and order of options below in sync! */
+ struct options program_options[] = {
+ /* short_name long_name value parameter_name help */
+ OPT_BOOL( 'l', "list" , NULL, _("List not yet reported problems, or all with -f")),
+ OPT_LIST( 'D', NULL , &D_list, "BASE_DIR", _("Directory to list problems from (default: -D $HOME/.abrt/spool -D "DEBUG_DUMPS_DIR")")),
+ OPT_BOOL( 'i', "info" , NULL, _("Print information about DUMP_DIR (detailed with -f)")),
+ 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_BOOL( 'a', "analyze", NULL, _("Run analyze event(s) on DUMP_DIR")),
+ OPT_BOOL( 'r', "report" , NULL, _("Send a report about DUMP_DIR")),
+ OPT_BOOL( 'd', "delete" , NULL, _("Remove DUMP_DIR")),
+ OPT_BOOL( 'V', "version", NULL, _("Display version and exit")),
+ OPT_BOOL( 'f', "full" , NULL, _("Full listing")),
+ OPT_BOOL( 'y', "always" , NULL, _("Noninteractive: don't ask questions, assume 'yes'")),
+ OPT__VERBOSE(&g_verbose),
+ OPT_BOOL( 's', NULL , NULL, _("Log to syslog")),
+ OPT_BOOL( 'p', NULL , NULL, _("Add program names to log")),
+ OPT_END()
+ };
+ unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+ unsigned op = (opts & OPTMASK_op);
+ if (!op || ((op-1) & op))
+ /* "You must specify exactly one operation" */
+ show_usage_and_die(program_usage_string, program_options);
+ argv += optind;
+ argc -= optind;
+ if (argc > 1
+ /* 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))
+ ) {
+ show_usage_and_die(program_usage_string, program_options);
+ }
-#define SET_OP(newop) \
- do { \
- if (op != -1 && op != newop) \
- error_msg_and_die(_("You must specify exactly one operation")); \
- op = newop; \
- } while (0)
+ if (op == OPT_version)
+ {
+ printf("%s "VERSION"\n", g_progname);
+ return 0;
+ }
- switch (c)
- {
- case -1: goto end_of_arg_parsing;
- case 'r': SET_OP(OPT_REPORT); break;
- case 'd': SET_OP(OPT_DELETE); break;
- case 'l': SET_OP(OPT_GET_LIST); break;
- case 'i': SET_OP(OPT_INFO); break;
- case 'f': full = true; break;
- case 'y': always = true; break;
- case 'v': g_verbose++; break;
- case 'D':
- D_list = g_list_append(D_list, optarg);
- break;
- case 'V':
- printf("%s "VERSION"\n", progname(argv[0]));
- return 0;
- case '?':
- default: /* some error */
- print_usage_and_die(argv[0]); /* exits app */
- }
-#undef SET_OP
+ export_abrt_envvars(opts & OPT_p);
+ if (opts & OPT_s)
+ {
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
}
- end_of_arg_parsing: ;
+
+ char *dump_dir_name = argv[0];
+ bool full = (opts & OPT_f);
+ bool always = (opts & OPT_y);
if (!D_list)
{
@@ -257,31 +230,6 @@ int main(int argc, char** argv)
D_list = g_list_append(D_list, (void*)DEBUG_DUMPS_DIR);
}
- /* Handle option arguments. */
- argc -= optind;
- switch (argc)
- {
- case 0:
- if (op == OPT_REPORT || op == OPT_DELETE || op == OPT_INFO)
- print_usage_and_die(argv[0]);
- break;
- case 1:
- if (op != OPT_REPORT && op != OPT_DELETE && op != OPT_INFO)
- print_usage_and_die(argv[0]);
- dump_dir_name = argv[optind];
- break;
- default:
- print_usage_and_die(argv[0]);
- }
-
- /* Check if we have an operation.
- * Limit --full and --always to certain operations.
- */
- if ((always && op != OPT_REPORT) || op == -1)
- {
- print_usage_and_die(argv[0]);
- }
-
/* Get settings */
load_event_config_data();
@@ -289,7 +237,7 @@ int main(int argc, char** argv)
int exitcode = 0;
switch (op)
{
- case OPT_GET_LIST:
+ case OPT_list:
{
vector_of_problem_data_t *ci = new_vector_of_problem_data();
while (D_list)
@@ -302,7 +250,49 @@ int main(int argc, char** argv)
free_vector_of_problem_data(ci);
break;
}
- case OPT_REPORT:
+ case OPT_list_events: /* -L[PREFIX] */
+ {
+ /* 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)
+ return 1; /* error msg is already logged */
+ fputs(events, stdout);
+ free(events);
+ break;
+ }
+ 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);
+ 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_report:
{
struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
if (!dd)
@@ -327,43 +317,18 @@ int main(int argc, char** argv)
error_msg_and_die("Crash '%s' not found", dump_dir_name);
break;
}
- case OPT_DELETE:
+ case OPT_delete:
{
exitcode = delete_dump_dir_possibly_using_abrtd(dump_dir_name);
break;
}
- case OPT_INFO:
+ case OPT_info:
{
/* 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");
-
- if (full && analyze_events_as_lines && *analyze_events_as_lines)
- {
- dd_close(dd);
-
- GList *list_analyze_events = str_to_glist(analyze_events_as_lines, '\n');
- free(analyze_events_as_lines);
-
- char *event = select_event_option(list_analyze_events);
- list_free_with_free(list_analyze_events);
-
- int analyzer_result = run_analyze_event(dump_dir_name, event);
- free(event);
-
- if (analyzer_result != 0)
- return 1;
-
- /* Reload problem_data from (possibly updated by analyze) dump dir */
- dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
- if (!dd)
- return -1;
- } else
- free(analyze_events_as_lines);
-
problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
dd_close(dd);
diff --git a/src/cli/report.c b/src/cli/report.c
index 96bf0062..7f722480 100644
--- a/src/cli/report.c
+++ b/src/cli/report.c
@@ -422,6 +422,31 @@ static bool set_echo(bool enable)
return true;
}
+/* 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
*/
@@ -584,12 +609,12 @@ char *select_event_option(GList *list_options)
if (!list_options)
return NULL;
- unsigned count = g_list_length(list_options) - 1;
- if (!count)
- return NULL;
+ unsigned count = g_list_length(list_options);
+ if (count == 1)
+ return xstrdup((char*)list_options->data);
- int pos = -1;
- fprintf(stdout, _("Select how you would like to analyze the problem:\n"));
+ 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;
@@ -605,14 +630,9 @@ char *select_event_option(GList *list_options)
unsigned ii;
for (ii = 0; ii < 3; ++ii)
{
- fprintf(stdout, _("Choose option [0 - %u]: "), count);
- fflush(NULL);
-
char answer[16];
- if (!fgets(answer, sizeof(answer), stdin))
- continue;
- answer[strlen(answer) - 1] = '\0';
+ read_from_stdin(_("Select analyzer: "), answer, sizeof(answer));
if (!*answer)
continue;
@@ -620,6 +640,7 @@ char *select_event_option(GList *list_options)
if (picked > count)
{
fprintf(stdout, _("You have chosen number out of range"));
+ fprintf(stdout, "\n");
continue;
}
@@ -629,7 +650,7 @@ char *select_event_option(GList *list_options)
if (ii == 3)
error_msg_and_die(_("Invalid input, program exiting..."));
- GList *choosen = g_list_nth(list_options, picked);
+ GList *choosen = g_list_nth(list_options, picked - 1);
return xstrdup((char*)choosen->data);
}
@@ -661,7 +682,7 @@ int report(const char *dump_dir_name, int flags)
/* 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;
+ return -1;
char *analyze_events_as_lines = list_possible_events(dd, NULL, "analyze");
dd_close(dd);
@@ -684,7 +705,7 @@ int report(const char *dump_dir_name, int flags)
/* Load problem_data from (possibly updated by analyze) dump dir */
dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
- return -1;
+ return -1;
char *report_events_as_lines = list_possible_events(dd, NULL, "report");
problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
@@ -744,30 +765,33 @@ int report(const char *dump_dir_name, int flags)
else
{
const char *rating_str = get_problem_item_content_or_NULL(problem_data, FILENAME_RATING);
- unsigned rating = rating_str ? xatou(rating_str) : 4;
+ unsigned i, rating = rating_str ? xatou(rating_str) : 4;
+ GList *li;
+ char wanted_reporters[255];
- /* For every reporter, ask if user really wants to report using it. */
- for (GList *li = report_events; li; li = li->next)
+ 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);
- char question[255];
- char *show_reporter_name;
- if (config)
- show_reporter_name = (config->screen_name) ? config->screen_name : reporter_name;
- else
- show_reporter_name = reporter_name;
- snprintf(question, sizeof(question), _("Report using %s?"), show_reporter_name);
+ printf(" %d) %s\n", i, (config && config->screen_name) ? config->screen_name : reporter_name);
+ }
+
+ read_from_stdin(_("Select reporter(s): "), wanted_reporters, sizeof(wanted_reporters));
+
+ 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);
if (!config)
VERB1 log("No configuration file found for '%s' reporter", reporter_name);
-
- if (!ask_yesno(question))
- {
- puts(_("Skipping..."));
+
+ /* Was this reporter requested? */
+ if (!is_number_in_string(i, wanted_reporters))
continue;
- }
/* TODO: npajkovs; not implemented yet */
//const char *rating_required = get_map_string_item_or_NULL(single_plugin_settings, "RatingRequired");