summaryrefslogtreecommitdiffstats
path: root/src/cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli')
-rw-r--r--src/cli/CLI.cpp358
-rw-r--r--src/cli/Makefile.am14
-rw-r--r--src/cli/dbus.cpp282
-rw-r--r--src/cli/dbus.h68
-rw-r--r--src/cli/report.cpp531
-rw-r--r--src/cli/report.h7
6 files changed, 523 insertions, 737 deletions
diff --git a/src/cli/CLI.cpp b/src/cli/CLI.cpp
index 44271329..5ece3171 100644
--- a/src/cli/CLI.cpp
+++ b/src/cli/CLI.cpp
@@ -19,30 +19,73 @@
# include <locale.h>
#endif
#include <getopt.h>
-#include "abrt_exception.h"
#include "abrtlib.h"
#include "abrt_dbus.h"
-#include "dbus_common.h"
#include "report.h"
-#include "dbus.h"
/** Creates a localized string from crash time. */
static char *localize_crash_time(const char *timestr)
{
long time = xatou(timestr);
char timeloc[256];
- int success = strftime(timeloc, 128, "%c", localtime(&time));
+ int success = strftime(timeloc, sizeof(timeloc), "%c", localtime(&time));
if (!success)
- error_msg_and_die("Error while converting time to string");
- return xasprintf("%s", timeloc);
+ error_msg_and_die("Error while converting time '%s' to string", timestr);
+ return xstrdup(timeloc);
+}
+
+static crash_data_t *FillCrashInfo(const char *dump_dir_name)
+{
+ int sv_logmode = logmode;
+ logmode = 0; /* suppress EPERM/EACCES errors in opendir */
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ DD_OPEN_READONLY);
+ logmode = sv_logmode;
+
+ if (!dd)
+ return NULL;
+
+ crash_data_t *crash_data = create_crash_data_from_dump_dir(dd);
+ dd_close(dd);
+ add_to_crash_data_ext(crash_data, CD_DUMPDIR, dump_dir_name, CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE);
+
+ return crash_data;
+}
+
+static void GetCrashInfos(vector_of_crash_data_t *retval, const char *dir_name)
+{
+ VERB1 log("Loading dumps from '%s'", dir_name);
+
+ DIR *dir = opendir(dir_name);
+ if (dir != NULL)
+ {
+ struct dirent *dent;
+ while ((dent = readdir(dir)) != NULL)
+ {
+ if (dot_or_dotdot(dent->d_name))
+ continue; /* skip "." and ".." */
+
+ char *dump_dir_name = concat_path_file(dir_name, dent->d_name);
+
+ struct stat statbuf;
+ if (stat(dump_dir_name, &statbuf) == 0
+ && S_ISDIR(statbuf.st_mode)
+ ) {
+ crash_data_t *crash_data = FillCrashInfo(dump_dir_name);
+ if (crash_data)
+ g_ptr_array_add(retval, crash_data);
+ }
+ free(dump_dir_name);
+ }
+ closedir(dir);
+ }
}
/** Prints basic information about a crash to stdout. */
-static void print_crash(const map_crash_data_t &crash)
+static void print_crash(crash_data_t *crash_data)
{
/* Create a localized string from crash time. */
- const char *timestr = get_crash_data_item_content(crash, FILENAME_TIME).c_str();
- const char *timeloc = localize_crash_time(timestr);
+ const char *timestr = get_crash_item_content_or_die(crash_data, FILENAME_TIME);
+ char *timeloc = localize_crash_time(timestr);
printf(_("\tCrash dump : %s\n"
"\tUID : %s\n"
@@ -50,17 +93,18 @@ static void print_crash(const map_crash_data_t &crash)
"\tExecutable : %s\n"
"\tCrash Time : %s\n"
"\tCrash Count: %s\n"),
- get_crash_data_item_content(crash, CD_DUMPDIR).c_str(),
- get_crash_data_item_content(crash, FILENAME_UID).c_str(),
- get_crash_data_item_content(crash, FILENAME_PACKAGE).c_str(),
- get_crash_data_item_content(crash, FILENAME_EXECUTABLE).c_str(),
+ get_crash_item_content_or_NULL(crash_data, CD_DUMPDIR),
+ get_crash_item_content_or_NULL(crash_data, FILENAME_UID),
+ get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE),
+ get_crash_item_content_or_NULL(crash_data, FILENAME_EXECUTABLE),
timeloc,
- get_crash_data_item_content(crash, FILENAME_COUNT).c_str());
+ get_crash_item_content_or_NULL(crash_data, FILENAME_COUNT)
+ );
- free((void *)timeloc);
+ free(timeloc);
/* Print the hostname if it's available. */
- const char *hostname = get_crash_data_item_content_or_NULL(crash, FILENAME_HOSTNAME);
+ const char *hostname = get_crash_item_content_or_NULL(crash_data, FILENAME_HOSTNAME);
if (hostname)
printf(_("\tHostname : %s\n"), hostname);
}
@@ -70,14 +114,14 @@ static void print_crash(const map_crash_data_t &crash)
* @param include_reported
* Do not skip entries marked as already reported.
*/
-static void print_crash_list(const vector_map_crash_data_t& crash_list, bool include_reported)
+static void print_crash_list(vector_of_crash_data_t *crash_list, bool include_reported)
{
- for (unsigned i = 0; i < crash_list.size(); ++i)
+ for (unsigned i = 0; i < crash_list->len; ++i)
{
- const map_crash_data_t& crash = crash_list[i];
+ crash_data_t *crash = get_crash_data(crash_list, i);
if (!include_reported)
{
- const char *msg = get_crash_data_item_content_or_NULL(crash, FILENAME_MESSAGE);
+ const char *msg = get_crash_item_content_or_NULL(crash, FILENAME_MESSAGE);
if (!msg || !msg[0])
continue;
}
@@ -90,10 +134,10 @@ static void print_crash_list(const vector_map_crash_data_t& crash_list, bool inc
/**
* Prints full information about a crash
*/
-static void print_crash_info(const map_crash_data_t& crash, bool show_backtrace)
+static void print_crash_info(crash_data_t *crash_data, bool show_backtrace)
{
- const char *timestr = get_crash_data_item_content(crash, FILENAME_TIME).c_str();
- const char *timeloc = localize_crash_time(timestr);
+ const char *timestr = get_crash_item_content_or_die(crash_data, FILENAME_TIME);
+ char *timeloc = localize_crash_time(timestr);
printf(_("Dump directory: %s\n"
"Last crash: %s\n"
@@ -104,91 +148,56 @@ static void print_crash_info(const map_crash_data_t& crash, bool show_backtrace)
"Executable: %s\n"
"System: %s, kernel %s\n"
"Reason: %s\n"),
- get_crash_data_item_content(crash, CD_DUMPDIR).c_str(),
+ get_crash_item_content_or_die(crash_data, CD_DUMPDIR),
timeloc,
- get_crash_data_item_content(crash, FILENAME_ANALYZER).c_str(),
- get_crash_data_item_content(crash, FILENAME_COMPONENT).c_str(),
- get_crash_data_item_content(crash, FILENAME_PACKAGE).c_str(),
- get_crash_data_item_content(crash, FILENAME_CMDLINE).c_str(),
- get_crash_data_item_content(crash, FILENAME_EXECUTABLE).c_str(),
- get_crash_data_item_content(crash, FILENAME_RELEASE).c_str(),
- get_crash_data_item_content(crash, FILENAME_KERNEL).c_str(),
- get_crash_data_item_content(crash, FILENAME_REASON).c_str());
-
- free((void *)timeloc);
+ get_crash_item_content_or_die(crash_data, FILENAME_ANALYZER),
+ get_crash_item_content_or_die(crash_data, FILENAME_COMPONENT),
+ get_crash_item_content_or_die(crash_data, FILENAME_PACKAGE),
+ get_crash_item_content_or_die(crash_data, FILENAME_CMDLINE),
+ get_crash_item_content_or_die(crash_data, FILENAME_EXECUTABLE),
+ get_crash_item_content_or_die(crash_data, FILENAME_OS_RELEASE),
+ get_crash_item_content_or_die(crash_data, FILENAME_KERNEL),
+ get_crash_item_content_or_die(crash_data, FILENAME_REASON)
+ );
+
+ free(timeloc);
/* Print optional fields only if they are available */
/* Coredump is not present in kerneloopses and Python exceptions. */
- const char *coredump = get_crash_data_item_content_or_NULL(crash, FILENAME_COREDUMP);
+ const char *coredump = get_crash_item_content_or_NULL(crash_data, FILENAME_COREDUMP);
if (coredump)
printf(_("Coredump file: %s\n"), coredump);
- const char *rating = get_crash_data_item_content_or_NULL(crash, FILENAME_RATING);
+ const char *rating = get_crash_item_content_or_NULL(crash_data, FILENAME_RATING);
if (rating)
printf(_("Rating: %s\n"), rating);
/* Crash function is not present in kerneloopses, and before the full report is created.*/
- const char *crash_function = get_crash_data_item_content_or_NULL(crash, FILENAME_CRASH_FUNCTION);
+ const char *crash_function = get_crash_item_content_or_NULL(crash_data, FILENAME_CRASH_FUNCTION);
if (crash_function)
printf(_("Crash function: %s\n"), crash_function);
- const char *hostname = get_crash_data_item_content_or_NULL(crash, FILENAME_HOSTNAME);
+ const char *hostname = get_crash_item_content_or_NULL(crash_data, FILENAME_HOSTNAME);
if (hostname)
printf(_("Hostname: %s\n"), hostname);
- const char *reproduce = get_crash_data_item_content_or_NULL(crash, FILENAME_REPRODUCE);
+ const char *reproduce = get_crash_item_content_or_NULL(crash_data, FILENAME_REPRODUCE);
if (reproduce)
printf(_("\nHow to reproduce:\n%s\n"), reproduce);
- const char *comment = get_crash_data_item_content_or_NULL(crash, FILENAME_COMMENT);
+ const char *comment = get_crash_item_content_or_NULL(crash_data, FILENAME_COMMENT);
if (comment)
printf(_("\nComment:\n%s\n"), comment);
if (show_backtrace)
{
- const char *backtrace = get_crash_data_item_content_or_NULL(crash, FILENAME_BACKTRACE);
+ const char *backtrace = get_crash_item_content_or_NULL(crash_data, FILENAME_BACKTRACE);
if (backtrace)
printf(_("\nBacktrace:\n%s\n"), backtrace);
}
}
-/**
- * Converts crash reference from user's input to crash dump dir name.
- * The returned string must be released by caller.
- */
-static char *guess_crash_id(const char *str)
-{
- vector_map_crash_data_t ci = call_GetCrashInfos();
- unsigned num_crashinfos = ci.size();
- if (str[0] == '@') /* "--report @N" syntax */
- {
- unsigned position = xatoi_u(str + 1);
- if (position >= num_crashinfos)
- error_msg_and_die("There are only %u crash infos", num_crashinfos);
- map_crash_data_t& info = ci[position];
- return xstrdup(get_crash_data_item_content(info, CD_DUMPDIR).c_str());
- }
-
- unsigned len = strlen(str);
- unsigned ii;
- char *result = NULL;
- for (ii = 0; ii < num_crashinfos; ii++)
- {
- map_crash_data_t& info = ci[ii];
- const char *this_dir = get_crash_data_item_content(info, CD_DUMPDIR).c_str();
- if (strncmp(str, this_dir, len) == 0)
- {
- if (result)
- error_msg_and_die("Crash prefix '%s' is not unique", str);
- result = xstrdup(this_dir);
- }
- }
- if (!result)
- error_msg_and_die("Crash dump directory '%s' not found", str);
- return result;
-}
-
/* Program options */
enum
{
@@ -210,6 +219,7 @@ 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' },
@@ -234,36 +244,42 @@ static const char *progname(const char *argv0)
* Prints abrt-cli version and some help text.
* Then exits the program with return value 1.
*/
-static void usage(char *argv0)
+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 [OPTION]\n\n"
- "Startup:\n"
- " -V, --version display the version of %s and exit\n"
- " -?, --help print this help\n\n"
- "Actions:\n"
- " -l, --list print a list of all crashes which are not yet reported\n"
- " -f, --full print a list of all crashes, including the already reported ones\n"
- " -r, --report CRASH_ID create and send a report\n"
- " -y, --always create and send a report without asking\n"
- " -d, --delete CRASH_ID remove a crash\n"
- " -i, --info CRASH_ID print detailed information about a crash\n"
- " -b, --backtrace print detailed information about a crash including backtrace\n"
- "CRASH_ID can be:\n"
- " a name of dump directory, or\n"
- " @N - N'th crash (as displayed by --list --full) will be acted upon\n"
+ 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 crashes\n"
+ " -f, --full List all crashes\n"
+ " -D BASE_DIR Directory to list crashes 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"
+ " -b, --backtrace ...including backtrace\n"
+ " -d, --delete Remove CRASH_DIR\n"
+ "\n"
+ " -V, --version Display version and exit\n"
+ " -v, --verbose Be verbose\n"
),
- name, name);
-
+ name, name, name, name,
+ DEBUG_DUMPS_DIR
+ );
exit(1);
}
int main(int argc, char** argv)
{
- const char* crash_id = NULL;
+ GList *D_list = NULL;
+ char *dump_dir_name = NULL;
int op = -1;
bool full = false;
bool always = false;
@@ -278,19 +294,18 @@ int main(int argc, char** argv)
while (1)
{
/* Do not use colons, arguments are handled after parsing all options. */
- int c = getopt_long_only(argc, argv, "?Vrdlfyib",
- longopts, NULL);
+ int c = getopt_long(argc, argv, "?Vvrdlfyib", longopts, NULL);
-#define SET_OP(newop) \
- if (op != -1 && op != newop) \
- { \
- error_msg(_("You must specify exactly one operation")); \
- return 1; \
- } \
- op = newop;
+#define SET_OP(newop) \
+ do { \
+ if (op != -1 && op != newop) \
+ error_msg_and_die(_("You must specify exactly one operation")); \
+ op = newop; \
+ } while (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;
@@ -298,34 +313,44 @@ int main(int argc, char** argv)
case 'f': full = true; break;
case 'y': always = true; break;
case 'b': backtrace = true; break;
- case -1: /* end of options */ break;
- default: /* some error */
- case '?':
- usage(argv[0]); /* exits app */
+ 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
- if (c == -1)
- break;
+ }
+ end_of_arg_parsing: ;
+
+ if (!D_list)
+ {
+ char *home = getenv("HOME");
+ if (home)
+ D_list = g_list_append(D_list, concat_path_file(home, ".abrt/spool"));
+ D_list = g_list_append(D_list, (void*)DEBUG_DUMPS_DIR);
}
/* Handle option arguments. */
- int arg_count = argc - optind;
- switch (arg_count)
+ argc -= optind;
+ switch (argc)
{
case 0:
if (op == OPT_REPORT || op == OPT_DELETE || op == OPT_INFO)
- usage(argv[0]);
+ print_usage_and_die(argv[0]);
break;
case 1:
if (op != OPT_REPORT && op != OPT_DELETE && op != OPT_INFO)
- usage(argv[0]);
- crash_id = argv[optind];
+ print_usage_and_die(argv[0]);
+ dump_dir_name = argv[optind];
break;
default:
- usage(argv[0]);
+ print_usage_and_die(argv[0]);
}
/* Check if we have an operation.
@@ -336,89 +361,72 @@ int main(int argc, char** argv)
(backtrace && op != OPT_INFO) ||
op == -1)
{
- usage(argv[0]);
- return 1;
+ print_usage_and_die(argv[0]);
}
- DBusError err;
- dbus_error_init(&err);
- s_dbus_conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
- handle_dbus_err(s_dbus_conn == NULL, &err);
-
/* Do the selected operation. */
int exitcode = 0;
switch (op)
{
case OPT_GET_LIST:
{
- vector_map_crash_data_t ci = call_GetCrashInfos();
+ vector_of_crash_data_t *ci = new_vector_of_crash_data();
+ while (D_list)
+ {
+ char *dir = (char *)D_list->data;
+ GetCrashInfos(ci, dir);
+ D_list = g_list_remove(D_list, dir);
+ }
print_crash_list(ci, full);
+ free_vector_of_crash_data(ci);
break;
}
case OPT_REPORT:
{
- int flags = CLI_REPORT_SILENT_IF_NOT_FOUND;
- if (always)
- flags |= CLI_REPORT_BATCH;
- exitcode = report(crash_id, flags);
- if (exitcode == -1) /* no such crash_id */
+ struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY);
+ if (!dd)
+ break;
+ int readonly = !dd->locked;
+ dd_close(dd);
+ if (readonly)
{
- crash_id = guess_crash_id(crash_id);
- exitcode = report(crash_id, always ? CLI_REPORT_BATCH : 0);
- if (exitcode == -1)
+ log("'%s' is not writable", dump_dir_name);
+ /* D_list can't be NULL here */
+ struct dump_dir *dd_copy = steal_directory((char *)D_list->data, dump_dir_name);
+ if (dd_copy)
{
- error_msg("Crash '%s' not found", crash_id);
- free((void *)crash_id);
- xfunc_die();
+ delete_dump_dir_possibly_using_abrtd(dump_dir_name);
+ dump_dir_name = xstrdup(dd_copy->dd_dirname);
+ dd_close(dd_copy);
}
-
- free((void *)crash_id);
}
+
+ exitcode = report(dump_dir_name, (always ? CLI_REPORT_BATCH : 0));
+ if (exitcode == -1)
+ error_msg_and_die("Crash '%s' not found", dump_dir_name);
break;
}
case OPT_DELETE:
{
- exitcode = call_DeleteDebugDump(crash_id);
- if (exitcode == ENOENT)
- {
- crash_id = guess_crash_id(crash_id);
- exitcode = call_DeleteDebugDump(crash_id);
- if (exitcode == ENOENT)
- {
- error_msg("Crash '%s' not found", crash_id);
- free((void *)crash_id);
- xfunc_die();
- }
-
- free((void *)crash_id);
- }
- if (exitcode != 0)
- error_msg_and_die("Can't delete debug dump '%s'", crash_id);
+ exitcode = delete_dump_dir_possibly_using_abrtd(dump_dir_name);
break;
}
case OPT_INFO:
{
- int old_logmode = logmode;
- logmode = 0;
-
- map_crash_data_t crashData = call_CreateReport(crash_id);
- if (crashData.empty()) /* no such crash_id */
- {
- crash_id = guess_crash_id(crash_id);
- crashData = call_CreateReport(crash_id);
- if (crashData.empty())
- {
- error_msg("Crash '%s' not found", crash_id);
- free((void *)crash_id);
- xfunc_die();
- }
-
- free((void *)crash_id);
- }
-
- logmode = old_logmode;
-
- print_crash_info(crashData, backtrace);
+ if (run_analyze_event(dump_dir_name) != 0)
+ return 1;
+
+ /* 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);
+ dd_close(dd);
+ add_to_crash_data_ext(crash_data, CD_DUMPDIR, dump_dir_name,
+ CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE);
+
+ print_crash_info(crash_data, backtrace);
+ free_crash_data(crash_data);
break;
}
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am
index 3584fd6c..0a5c6e1a 100644
--- a/src/cli/Makefile.am
+++ b/src/cli/Makefile.am
@@ -3,20 +3,20 @@ bin_PROGRAMS = abrt-cli
abrt_cli_SOURCES = \
CLI.cpp \
run-command.h run-command.c \
- report.h report.cpp \
- dbus.h dbus.cpp
-
+ report.h report.cpp
abrt_cli_CPPFLAGS = \
- -I$(srcdir)/../include \
+ -I$(srcdir)/../include/report -I$(srcdir)/../include \
-I$(srcdir)/../lib \
-DVAR_RUN=\"$(VAR_RUN)\" \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
$(ENABLE_SOCKET_OR_DBUS) \
$(DBUS_CFLAGS) $(GLIB_CFLAGS) \
- -D_GNU_SOURCE
+ -D_GNU_SOURCE \
+ -Wall -Werror
# $(GTK_CFLAGS)
-
abrt_cli_LDADD = \
- ../lib/libabrt.la \
+ ../lib/libreport.la \
../lib/libabrt_dbus.la \
$(GLIB_LIBS)
diff --git a/src/cli/dbus.cpp b/src/cli/dbus.cpp
deleted file mode 100644
index 7565d5bc..00000000
--- a/src/cli/dbus.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- Copyright (C) 2009 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 "dbus.h"
-#include "dbus_common.h"
-
-DBusConnection* s_dbus_conn;
-
-/*
- * DBus member calls
- */
-
-/* helpers */
-static DBusMessage* new_call_msg(const char* method)
-{
- DBusMessage* msg = dbus_message_new_method_call(ABRTD_DBUS_NAME, ABRTD_DBUS_PATH, ABRTD_DBUS_IFACE, method);
- if (!msg)
- die_out_of_memory();
- return msg;
-}
-
-static DBusMessage* send_get_reply_and_unref(DBusMessage* msg)
-{
- dbus_uint32_t serial;
- if (TRUE != dbus_connection_send(s_dbus_conn, msg, &serial))
- error_msg_and_die("Error sending DBus message");
- dbus_message_unref(msg);
-
- while (true)
- {
- DBusMessage *received = dbus_connection_pop_message(s_dbus_conn);
- if (!received)
- {
- if (FALSE == dbus_connection_read_write(s_dbus_conn, -1))
- error_msg_and_die("dbus connection closed");
- continue;
- }
-
- int tp = dbus_message_get_type(received);
- const char *error_str = dbus_message_get_error_name(received);
-#if 0
- /* Debugging */
- printf("type:%u (CALL:%u, RETURN:%u, ERROR:%u, SIGNAL:%u)\n", tp,
- DBUS_MESSAGE_TYPE_METHOD_CALL,
- DBUS_MESSAGE_TYPE_METHOD_RETURN,
- DBUS_MESSAGE_TYPE_ERROR,
- DBUS_MESSAGE_TYPE_SIGNAL
- );
- const char *sender = dbus_message_get_sender(received);
- if (sender)
- printf("sender: %s\n", sender);
- const char *path = dbus_message_get_path(received);
- if (path)
- printf("path: %s\n", path);
- const char *member = dbus_message_get_member(received);
- if (member)
- printf("member: %s\n", member);
- const char *interface = dbus_message_get_interface(received);
- if (interface)
- printf("interface: %s\n", interface);
- const char *destination = dbus_message_get_destination(received);
- if (destination)
- printf("destination: %s\n", destination);
- if (error_str)
- printf("error: '%s'\n", error_str);
-#endif
-
- DBusError err;
- dbus_error_init(&err);
-
- if (dbus_message_is_signal(received, ABRTD_DBUS_IFACE, "Update"))
- {
- const char *update_msg;
- if (!dbus_message_get_args(received, &err,
- DBUS_TYPE_STRING, &update_msg,
- DBUS_TYPE_INVALID))
- {
- error_msg_and_die("dbus Update message: arguments mismatch");
- }
- printf(">> %s\n", update_msg);
- }
- else if (dbus_message_is_signal(received, ABRTD_DBUS_IFACE, "Warning"))
- {
- const char *warning_msg;
- if (!dbus_message_get_args(received, &err,
- DBUS_TYPE_STRING, &warning_msg,
- DBUS_TYPE_INVALID))
- {
- error_msg_and_die("dbus Warning message: arguments mismatch");
- }
- log(">! %s\n", warning_msg);
- }
- else
- if (tp == DBUS_MESSAGE_TYPE_METHOD_RETURN
- && dbus_message_get_reply_serial(received) == serial
- ) {
- return received;
- }
- else
- if (tp == DBUS_MESSAGE_TYPE_ERROR
- && dbus_message_get_reply_serial(received) == serial
- ) {
- error_msg_and_die("dbus call returned error: '%s'", error_str);
- }
-
- dbus_message_unref(received);
- }
-}
-
-vector_map_crash_data_t call_GetCrashInfos()
-{
- 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);
-
- vector_map_crash_data_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;
-}
-
-map_crash_data_t call_CreateReport(const char* crash_id)
-{
- DBusMessage* msg = new_call_msg(__func__ + 5);
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &crash_id,
- DBUS_TYPE_INVALID);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
-
- DBusMessageIter in_iter;
- dbus_message_iter_init(reply, &in_iter);
-
- map_crash_data_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;
-}
-
-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);
- DBusMessageIter out_iter;
- dbus_message_iter_init_append(msg, &out_iter);
-
- /* parameter #1: report data */
- store_val(&out_iter, report);
- /* parameter #2: reporters to use */
- store_val(&out_iter, reporters);
- /* parameter #3 (opt): plugin config */
- if (!plugins.empty())
- store_val(&out_iter, plugins);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
-
- DBusMessageIter in_iter;
- dbus_message_iter_init(reply, &in_iter);
-
- report_status_t result;
- int r = load_val(&in_iter, result);
- 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 result;
-}
-
-int32_t call_DeleteDebugDump(const char* crash_id)
-{
- DBusMessage* msg = new_call_msg(__func__ + 5);
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &crash_id,
- DBUS_TYPE_INVALID);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
-
- DBusMessageIter in_iter;
- dbus_message_iter_init(reply, &in_iter);
-
- int32_t result;
- int r = load_val(&in_iter, result);
- 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 result;
-}
-
-map_map_string_t call_GetPluginsInfo()
-{
- 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;
-}
-
-map_plugin_settings_t call_GetPluginSettings(const char *name)
-{
- DBusMessage *msg = new_call_msg(__func__ + 5);
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
-
- DBusMessageIter in_iter;
- dbus_message_iter_init(reply, &in_iter);
-
- 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;
-}
-
-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))
- {
- error_msg("dbus error: %s", err->message);
- /* dbus_error_free(&err); */
- error_flag = true;
- }
- if (!error_flag)
- return;
- error_msg_and_die(
- "error requesting DBus name %s, possible reasons: "
- "abrt run by non-root; dbus config is incorrect; "
- "or dbus daemon needs to be restarted to reload dbus config",
- ABRTD_DBUS_NAME);
-}
diff --git a/src/cli/dbus.h b/src/cli/dbus.h
deleted file mode 100644
index 9c99c662..00000000
--- a/src/cli/dbus.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- Copyright (C) 2009 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.
-*/
-#ifndef ABRT_CLI_DBUS_H
-#define ABRT_CLI_DBUS_H
-
-#include "abrt_dbus.h"
-#include "abrt_crash_dump.h"
-
-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 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();
-
-/** Gets default plugin settings.
- * @param name
- * Corresponds to name obtained from 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 78a38916..6b2bf2e2 100644
--- a/src/cli/report.cpp
+++ b/src/cli/report.cpp
@@ -15,11 +15,8 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <termios.h>
-#include <glib.h>
#include "report.h"
#include "run-command.h"
-#include "dbus.h"
#include "abrtlib.h"
/* Field separator for the crash report file that is edited by user. */
@@ -35,13 +32,10 @@ static char *trim(char *str)
return NULL;
// Remove leading spaces.
- char *ibuf;
- ibuf = skip_whitespace(str);
- int i = strlen(ibuf);
- if (str != ibuf)
- memmove(str, ibuf, i + 1);
+ overlapping_strcpy(str, skip_whitespace(str));
// Remove trailing spaces.
+ int i = strlen(str);
while (--i >= 0)
{
if (!isspace(str[i]))
@@ -142,30 +136,24 @@ static void remove_comments_and_unescape(char *str)
* Writes a field of crash report to a file.
* Field must be writable.
*/
-static void write_crash_report_field(FILE *fp, const map_crash_data_t &report,
+static void write_crash_report_field(FILE *fp, crash_data_t *crash_data,
const char *field, const char *description)
{
- const map_crash_data_t::const_iterator it = report.find(field);
- if (it == report.end())
+ const struct crash_item *value = get_crash_data_item_or_NULL(crash_data, field);
+ if (!value)
{
// exit silently, all fields are optional for now
//error_msg("Field %s not found", field);
return;
}
- if (it->second[CD_TYPE] == CD_SYS)
- {
- error_msg("Cannot update field %s because it is a system value", field);
- return;
- }
-
- fprintf(fp, "%s%s\n", FIELD_SEP, it->first.c_str());
+ fprintf(fp, "%s%s\n", FIELD_SEP, field);
fprintf(fp, "%s\n", description);
- if (it->second[CD_EDITABLE] != CD_ISEDITABLE)
+ if (!(value->flags & CD_FLAG_ISEDITABLE))
fprintf(fp, _("# This field is read only\n"));
- char *escaped_content = escape(it->second[CD_CONTENT].c_str());
+ char *escaped_content = escape(value->content);
fprintf(fp, "%s\n", escaped_content);
free(escaped_content);
}
@@ -177,7 +165,7 @@ static void write_crash_report_field(FILE *fp, const map_crash_data_t &report,
* If the report is successfully stored to the file, a zero value is returned.
* On failure, nonzero value is returned.
*/
-static void write_crash_report(const map_crash_data_t &report, FILE *fp)
+static void write_crash_report(crash_data_t *report, FILE *fp)
{
fprintf(fp, "# Please check this report. Lines starting with '#' will be ignored.\n"
"# Lines starting with '%%----' separate fields, please do not delete them.\n\n");
@@ -197,7 +185,7 @@ static void write_crash_report(const map_crash_data_t &report, FILE *fp)
write_crash_report_field(fp, report, FILENAME_KERNEL, _("# Kernel version"));
write_crash_report_field(fp, report, FILENAME_PACKAGE, _("# Package"));
write_crash_report_field(fp, report, FILENAME_REASON, _("# Reason of crash"));
- write_crash_report_field(fp, report, FILENAME_RELEASE, _("# Release string of the operating system"));
+ write_crash_report_field(fp, report, FILENAME_OS_RELEASE, _("# Release string of the operating system"));
}
/*
@@ -208,7 +196,7 @@ static void write_crash_report(const map_crash_data_t &report, FILE *fp)
* 1 if the field was changed.
* Changes to read-only fields are ignored.
*/
-static int read_crash_report_field(const char *text, map_crash_data_t &report,
+static int read_crash_report_field(const char *text, crash_data_t *report,
const char *field)
{
char separator[sizeof("\n" FIELD_SEP)-1 + strlen(field) + 2]; // 2 = '\n\0'
@@ -225,21 +213,15 @@ static int read_crash_report_field(const char *text, map_crash_data_t &report,
else
length = end - textfield;
- const map_crash_data_t::iterator it = report.find(field);
- if (it == report.end())
+ struct crash_item *value = get_crash_data_item_or_NULL(report, field);
+ if (!value)
{
error_msg("Field %s not found", field);
return 0;
}
- if (it->second[CD_TYPE] == CD_SYS)
- {
- error_msg("Cannot update field %s because it is a system value", field);
- return 0;
- }
-
// Do not change noneditable fields.
- if (it->second[CD_EDITABLE] != CD_ISEDITABLE)
+ if (!(value->flags & CD_FLAG_ISEDITABLE))
return 0;
// Compare the old field contents with the new field contents.
@@ -248,16 +230,16 @@ static int read_crash_report_field(const char *text, map_crash_data_t &report,
newvalue[length] = '\0';
trim(newvalue);
- char oldvalue[it->second[CD_CONTENT].length() + 1];
- strcpy(oldvalue, it->second[CD_CONTENT].c_str());
+ char oldvalue[strlen(value->content) + 1];
+ strcpy(oldvalue, value->content);
trim(oldvalue);
// Return if no change in the contents detected.
- int cmp = strcmp(newvalue, oldvalue);
- if (!cmp)
+ if (strcmp(newvalue, oldvalue) == 0)
return 0;
- it->second[CD_CONTENT].assign(newvalue);
+ free(value->content);
+ value->content = xstrdup(newvalue);
return 1;
}
@@ -269,7 +251,7 @@ static int read_crash_report_field(const char *text, map_crash_data_t &report,
* 1 if any field was changed.
* Changes to read-only fields are ignored.
*/
-static int read_crash_report(map_crash_data_t &report, const char *text)
+static int read_crash_report(crash_data_t *report, const char *text)
{
int result = 0;
result |= read_crash_report_field(text, report, FILENAME_COMMENT);
@@ -284,7 +266,7 @@ static int read_crash_report(map_crash_data_t &report, const char *text)
result |= read_crash_report_field(text, report, FILENAME_KERNEL);
result |= read_crash_report_field(text, report, FILENAME_PACKAGE);
result |= read_crash_report_field(text, report, FILENAME_REASON);
- result |= read_crash_report_field(text, report, FILENAME_RELEASE);
+ result |= read_crash_report_field(text, report, FILENAME_OS_RELEASE);
return result;
}
@@ -292,13 +274,13 @@ static int read_crash_report(map_crash_data_t &report, const char *text)
* Ensures that the fields needed for editor are present in the crash data.
* Fields: comments, how to reproduce.
*/
-static void create_fields_for_editor(map_crash_data_t &crash_data)
+static void create_fields_for_editor(crash_data_t *crash_data)
{
- if (crash_data.find(FILENAME_COMMENT) == crash_data.end())
- add_to_crash_data_ext(crash_data, FILENAME_COMMENT, CD_TXT, CD_ISEDITABLE, "");
+ if (!get_crash_data_item_or_NULL(crash_data, FILENAME_COMMENT))
+ add_to_crash_data_ext(crash_data, FILENAME_COMMENT, "", CD_FLAG_TXT + CD_FLAG_ISEDITABLE);
- if (crash_data.find(FILENAME_REPRODUCE) == crash_data.end())
- add_to_crash_data_ext(crash_data, FILENAME_REPRODUCE, CD_TXT, CD_ISEDITABLE, "1. \n2. \n3. \n");
+ if (!get_crash_data_item_or_NULL(crash_data, FILENAME_REPRODUCE))
+ add_to_crash_data_ext(crash_data, FILENAME_REPRODUCE, "1. \n2. \n3. \n", CD_FLAG_TXT + CD_FLAG_ISEDITABLE);
}
/**
@@ -342,7 +324,7 @@ static int launch_editor(const char *path)
* 2 on failure, unable to create, open, or close temporary file
* 3 on failure, cannot launch text editor
*/
-static int run_report_editor(map_crash_data_t &cr)
+static int run_report_editor(crash_data_t *crash_data)
{
/* Open a temporary file and write the crash report to it. */
char filename[] = "/tmp/abrt-report.XXXXXX";
@@ -356,15 +338,14 @@ static int run_report_editor(map_crash_data_t &cr)
FILE *fp = fdopen(fd, "w");
if (!fp) /* errno is set */
{
- perror_msg("can't open '%s' to save the crash report", filename);
- return 2;
+ die_out_of_memory();
}
- write_crash_report(cr, fp);
+ write_crash_report(crash_data, fp);
if (fclose(fp)) /* errno is set */
{
- perror_msg("can't close '%s'", filename);
+ perror_msg("can't write '%s'", filename);
return 2;
}
@@ -381,21 +362,18 @@ static int run_report_editor(map_crash_data_t &cr)
}
fseek(fp, 0, SEEK_END);
- long size = ftell(fp);
+ unsigned long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *text = (char*)xmalloc(size + 1);
if (fread(text, 1, size, fp) != size)
{
error_msg("can't read '%s'", filename);
+ fclose(fp);
return 2;
}
text[size] = '\0';
- if (fclose(fp) != 0) /* errno is set */
- {
- perror_msg("can't close '%s'", filename);
- return 2;
- }
+ fclose(fp);
// Delete the tempfile.
if (unlink(filename) == -1) /* errno is set */
@@ -405,7 +383,7 @@ static int run_report_editor(map_crash_data_t &cr)
remove_comments_and_unescape(text);
// Updates the crash report from the file text.
- int report_changed = read_crash_report(cr, text);
+ int report_changed = read_crash_report(crash_data, text);
free(text);
if (report_changed)
puts(_("\nThe report has been updated"));
@@ -435,25 +413,6 @@ static void read_from_stdin(const char *question, char *result, int result_size)
strchrnul(result, '\n')[0] = '\0';
}
-/** Splits a string into substrings using chosen delimiters.
- * @param delim
- * Specifies a set of characters that delimit the
- * tokens in the parsed string
- */
-static GList *split(const char *s, const char delim)
-{
- GList *elems = NULL;
- while (1)
- {
- const char *end = strchrnul(s, delim);
- elems = g_list_append(elems, xstrndup(s, end - s));
- if (*end == '\0')
- break;
- s = end + 1;
- }
- return elems;
-}
-
/**
* Asks a [y/n] question on stdin/stdout.
* Returns true if the answer is yes, false otherwise.
@@ -467,97 +426,128 @@ static bool ask_yesno(const char *question)
fflush(NULL);
char answer[16];
- fgets(answer, sizeof(answer), stdin);
+ if (!fgets(answer, sizeof(answer), stdin))
+ return false;
/* Use strncmp here because the answer might contain a newline as
the last char. */
return 0 == strncmp(answer, yes, strlen(yes));
}
/* Returns true if echo has been changed from another state. */
-static bool set_echo(bool enabled)
+static bool set_echo(bool enable)
{
- if (isatty(STDIN_FILENO) == 0)
- {
- /* Clean errno, which is set by isatty. */
- errno = 0;
- return false;
- }
-
struct termios t;
if (tcgetattr(STDIN_FILENO, &t) < 0)
return false;
- /* No change needed. */
- if ((bool)(t.c_lflag & ECHO) == enabled)
+ /* No change needed? */
+ if ((bool)(t.c_lflag & ECHO) == enable)
return false;
- if (enabled)
- t.c_lflag |= ECHO;
- else
- t.c_lflag &= ~ECHO;
-
+ t.c_lflag ^= ECHO;
if (tcsetattr(STDIN_FILENO, TCSANOW, &t) < 0)
perror_msg_and_die("tcsetattr");
return true;
}
+
/**
* Gets reporter plugin settings.
- * @param reporters
- * List of reporter names. Settings of these reporters are handled.
- * @param settings
+ * @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 void get_reporter_plugin_settings(const vector_string_t& reporters,
- map_map_string_t &settings)
+static void get_plugin_system_settings(GHashTable *settings)
{
- /* First of all, load system-wide report plugin settings. */
- for (vector_string_t::const_iterator it = reporters.begin(); it != reporters.end(); ++it)
+ DIR *dir = opendir(PLUGINS_CONF_DIR);
+ if (!dir)
+ return;
+
+ struct dirent *dent;
+ while ((dent = readdir(dir)) != NULL)
{
- 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->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. */
+ * the system-wide settings. */
struct passwd* pw = getpwuid(geteuid());
const char* homedir = pw ? pw->pw_dir : NULL;
if (homedir)
{
- map_map_string_t::const_iterator itend = settings.end();
- for (map_map_string_t::iterator it = settings.begin(); it != itend; ++it)
+ GHashTableIter iter;
+ char *plugin_name;
+ 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))
{
- map_string_t single_plugin_settings;
- std::string path = std::string(homedir) + "/.abrt/"
- + it->first + ".conf";
- /* 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
- enter it every time he reports. */
- bool success = LoadPluginSettings(path.c_str(), single_plugin_settings, false);
+ /* 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/foo.conf, but he prefers to
+ * enter it every time he reports. */
+ map_string_h *single_plugin_settings = new_map_string();
+ char *path = xasprintf("%s/.abrt/%s.conf", homedir, plugin_name);
+ bool success = load_conf_file(path, single_plugin_settings, /*skip key w/o values:*/ false);
+ free(path);
if (!success)
+ {
+ free_map_string(single_plugin_settings);
continue;
- // Merge user's plugin settings into already loaded settings.
- map_string_t::const_iterator valit, valitend = single_plugin_settings.end();
- for (valit = single_plugin_settings.begin(); valit != valitend; ++valit)
- it->second[valit->first] = valit->second;
+ }
+
+ /* Merge user's plugin settings into already loaded 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))
+ g_hash_table_replace(plugin_settings, xstrdup(key), xstrdup(value));
+
+ free_map_string(single_plugin_settings);
}
}
+ return settings;
}
/**
* 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;
@@ -567,7 +557,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)
{
@@ -578,129 +568,266 @@ 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 with corresponding crash_id over DBus. */
-int report(const char *crash_id, int flags)
+
+struct logging_state {
+ char *last_line;
+};
+static char *do_log_and_save_line(char *log_line, void *param)
{
- int old_logmode = logmode;
- if (flags & CLI_REPORT_SILENT_IF_NOT_FOUND)
- logmode = 0;
- // Ask for an initial report.
- map_crash_data_t cr = call_CreateReport(crash_id);
- logmode = old_logmode;
- if (cr.size() == 0)
+ 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 == 0 && run_state->children_count == 0)
+ {
+ l_state.last_line = xasprintf("Error: no processing is specified for event '%s'", event.c_str());
+ r = -1;
+ }
+ 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))
{
- return -1;
+ 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)
+{
+ 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);
+ return res;
+}
- const char *rating_str = get_crash_data_item_content_or_NULL(cr, FILENAME_RATING);
- unsigned rating = rating_str ? xatou(rating_str) : 4;
- /* Open text editor and give a chance to review the backtrace etc. */
+/* Report the crash */
+int report(const char *dump_dir_name, int flags)
+{
+ if (run_analyze_event(dump_dir_name) != 0)
+ return 1;
+
+ /* 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);
+
if (!(flags & CLI_REPORT_BATCH))
{
- create_fields_for_editor(cr);
- int result = run_report_editor(cr);
+ /* 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)
- return result;
+ {
+ free_crash_data(crash_data);
+ 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_data_item_content_or_NULL(cr, CD_EVENTS);
- vector_string_t reporters;
- if (events) while (*events)
+ /* Get possible reporters associated with this particular crash */
+ vector_string_t report_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);
- reporters.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 */
- map_map_string_t reporters_settings;
- get_reporter_plugin_settings(reporters, reporters_settings);
+ 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(cr, reporters, 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 = reporters.begin(); it != reporters.end(); ++it)
+ for (vector_string_t::const_iterator it = report_events.begin(); it != report_events.end(); ++it)
{
char question[255];
- snprintf(question, 255, _("Report using %s?"), it->c_str());
+ snprintf(question, sizeof(question), _("Report using %s?"), it->c_str());
if (!ask_yesno(question))
{
puts(_("Skipping..."));
continue;
}
- map_map_string_t::iterator settings = reporters_settings.find(it->c_str());
- if (settings != reporters_settings.end())
+//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->second.find("RatingRequired");
- if (rating_setting != settings->second.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_data_item_content_or_NULL(cr, FILENAME_PACKAGE);
- if (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->second);
-
- vector_string_t cur_reporter(1, *it);
- 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());
+ vector_string_t cur_event(1, *it);
+ errors += run_events(dump_dir_name, cur_event, map_map_settings);
plugins++;
- if (v[REPORT_STATUS_IDX_FLAG] == "0")
- errors++;
}
}
+ 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;
}
diff --git a/src/cli/report.h b/src/cli/report.h
index 8a851b8e..80c0b9f2 100644
--- a/src/cli/report.h
+++ b/src/cli/report.h
@@ -18,11 +18,12 @@
#ifndef ABRT_CLI_REPORT_H
#define ABRT_CLI_REPORT_H
-/* Reports the crash with corresponding uuid over DBus. */
+int run_analyze_event(const char *dump_dir_name);
+
+/* Report the crash */
enum {
CLI_REPORT_BATCH = 1 << 0,
- CLI_REPORT_SILENT_IF_NOT_FOUND = 1 << 1,
};
-int report(const char *uuid, int flags);
+int report(const char *dump_dir_name, int flags);
#endif