summaryrefslogtreecommitdiffstats
path: root/src/CLI
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2009-10-20 15:54:05 +0200
committerKarel Klic <kklic@redhat.com>2009-10-20 15:54:05 +0200
commit9e8a1ba0c9ddfa0108050f6fedc88de63b4b7c3f (patch)
tree93e418dedf9864edbdfcfbe69ba5b444d9704812 /src/CLI
parentb7f40a3f601e60fc342cad87cf40849ee4e2c153 (diff)
downloadabrt-9e8a1ba0c9ddfa0108050f6fedc88de63b4b7c3f.tar.gz
abrt-9e8a1ba0c9ddfa0108050f6fedc88de63b4b7c3f.tar.xz
abrt-9e8a1ba0c9ddfa0108050f6fedc88de63b4b7c3f.zip
Initial implementation of crash report editor. Splitted CLI.cpp into multiple files for clarity.
Diffstat (limited to 'src/CLI')
-rw-r--r--src/CLI/CLI.cpp226
-rw-r--r--src/CLI/Makefile.am9
-rw-r--r--src/CLI/dbus.cpp130
-rw-r--r--src/CLI/dbus.h34
-rw-r--r--src/CLI/report.cpp344
-rw-r--r--src/CLI/report.h24
-rw-r--r--src/CLI/run-command.cpp87
-rw-r--r--src/CLI/run-command.h23
8 files changed, 657 insertions, 220 deletions
diff --git a/src/CLI/CLI.cpp b/src/CLI/CLI.cpp
index d4e2bb4b..a782a59a 100644
--- a/src/CLI/CLI.cpp
+++ b/src/CLI/CLI.cpp
@@ -21,17 +21,19 @@
#include "abrtlib.h"
#include "abrt_dbus.h"
#include "DBusCommon.h"
+#include "report.h"
+#include "dbus.h"
#if HAVE_CONFIG_H
- #include <config.h>
+#include <config.h>
#endif
#if HAVE_LOCALE_H
- #include <locale.h>
+#include <locale.h>
#endif
#if ENABLE_NLS
- #include <libintl.h>
- #define _(S) gettext(S)
+#include <libintl.h>
+#define _(S) gettext(S)
#else
- #define _(S) (S)
+#define _(S) (S)
#endif
/* Program options */
@@ -46,8 +48,6 @@ enum
OPT_DELETE
};
-static DBusConnection* s_dbus_conn;
-
static void print_crash_infos(vector_crash_infos_t& pCrashInfos, int pMode)
{
unsigned int ii;
@@ -85,218 +85,6 @@ static void print_crash_infos(vector_crash_infos_t& pCrashInfos, int pMode)
}
}
-/* Saves the crash report to a file.
- * Fp must be opened before write_crash_report is called.
- * Returned Value:
- * If the report is successfully stored to the file, a zero value is returned.
- * On failure, nonzero value is returned.
- */
-static int write_crash_report(const map_crash_report_t& report, FILE *fp)
-{
- for (map_crash_report_t::const_iterator it = report.begin(); it != report.end(); it++)
- {
- if (it->second[CD_TYPE] == CD_SYS)
- continue;
-
- fprintf(fp, "\n%s\n-----\n%s\n", it->first.c_str(), it->second[CD_CONTENT].c_str());
- }
-
- return 0;
-}
-
-static void print_crash_report(const map_crash_report_t& pCrashReport)
-{
- map_crash_report_t::const_iterator it = pCrashReport.begin();
- for (; it != pCrashReport.end(); it++)
- {
- if (it->second[CD_TYPE] != CD_SYS)
- {
- printf("\n%s\n"
- "-----\n"
- "%s\n", it->first.c_str(), it->second[CD_CONTENT].c_str());
- }
- }
-}
-
-/*
- * DBus member calls
- */
-
-/* helpers */
-static DBusMessage* new_call_msg(const char* method)
-{
- DBusMessage* msg = dbus_message_new_method_call(CC_DBUS_NAME, CC_DBUS_PATH, CC_DBUS_IFACE, method);
- if (!msg)
- die_out_of_memory();
- return msg;
-}
-
-static DBusMessage* send_get_reply_and_unref(DBusMessage* msg)
-{
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply = dbus_connection_send_with_reply_and_block(s_dbus_conn, msg, /*timeout*/ -1, &err);
- if (reply == NULL)
- {
- //TODO: analyse err
- error_msg_and_die("Error sending DBus message");
- }
- dbus_message_unref(msg);
- return reply;
-}
-
-static vector_crash_infos_t call_GetCrashInfos()
-{
- DBusMessage* msg = new_call_msg("GetCrashInfos");
- DBusMessage *reply = send_get_reply_and_unref(msg);
-
- vector_crash_infos_t argout;
- DBusMessageIter in_iter;
- dbus_message_iter_init(reply, &in_iter);
- 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", "GetCrashInfos");
- dbus_message_unref(reply);
- return argout;
-}
-
-static map_crash_report_t call_CreateReport(const char* uuid)
-{
- /* Yes, call name is not "CreateReport" but "GetJobResult".
- * We need to clean up the names one day. */
- DBusMessage* msg = new_call_msg("GetJobResult");
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &uuid,
- DBUS_TYPE_INVALID);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
-
- map_crash_report_t argout;
- DBusMessageIter in_iter;
- dbus_message_iter_init(reply, &in_iter);
- 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", "GetJobResult");
- dbus_message_unref(reply);
- return argout;
-}
-
-static void call_Report(const map_crash_report_t& report)
-{
- DBusMessage* msg = new_call_msg("Report");
- DBusMessageIter out_iter;
- dbus_message_iter_init_append(msg, &out_iter);
- store_val(&out_iter, report);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
- //it returns a single value of report_status_t type,
- //but we don't use it (yet?)
-
- dbus_message_unref(reply);
- return;
-}
-
-static void call_DeleteDebugDump(const char* uuid)
-{
- DBusMessage* msg = new_call_msg("DeleteDebugDump");
- dbus_message_append_args(msg,
- DBUS_TYPE_STRING, &uuid,
- DBUS_TYPE_INVALID);
-
- DBusMessage *reply = send_get_reply_and_unref(msg);
- //it returns a single boolean value,
- //but we don't use it (yet?)
-
- dbus_message_unref(reply);
- return;
-}
-
-static 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",
- CC_DBUS_NAME);
-}
-
-int launch_editor(const char *path, const char *report, char **output)
-{
- const char *editor, *terminal;
-
- editor = getenv("VISUAL");
- if (!editor)
- editor = getenv("EDITOR");
-
- terminal = getenv("TERM");
- if (!editor && (!terminal || !strcmp(terminal, "dumb")))
- {
- error_msg(_("Terminal is dumb but no VISUAL nor EDITOR defined."));
- return 1;
- }
-
- if (!editor)
- editor = "vi";
-
- return 0;
-}
-
-/* Reports the crash with corresponding uuid over DBus. */
-int report(const char *uuid, bool always)
-{
- map_crash_report_t cr = call_CreateReport(uuid);
-
- if (always)
- {
- call_Report(cr);
- return 0;
- }
-
- print_crash_report(cr);
-
- /* Open a temporary file and write the crash report to it. */
- char filename[] = "/tmp/abrt-report.XXXXXX";
- int fd = mkstemp(filename);
- if (fd == -1)
- {
- error_msg("could not generate temporary file name");
- return 1;
- }
-
- FILE *fp = fdopen(fd, "w");
- if (!fp)
- {
- error_msg("could not open '%s' to save the crash report", filename);
- return 1;
- }
-
- write_crash_report(cr, fp);
-
- if (fclose(fp))
- {
- error_msg("could not close '%s'", filename);
- return 2;
- }
-
- printf(_("\nDo you want to send the report? [y/n]: "));
- fflush(NULL);
- char answer[16] = "n";
- fgets(answer, sizeof(answer), stdin);
- if (answer[0] == 'Y' || answer[0] == 'y')
- {
- call_Report(cr);
- }
-
- return 0;
-}
-
static const struct option longopts[] =
{
/* name, has_arg, flag, val */
diff --git a/src/CLI/Makefile.am b/src/CLI/Makefile.am
index 68109534..7b10bfb8 100644
--- a/src/CLI/Makefile.am
+++ b/src/CLI/Makefile.am
@@ -2,7 +2,14 @@ bin_PROGRAMS = abrt-cli
abrt_cli_SOURCES = \
CLI.cpp \
- ABRTSocket.h ABRTSocket.cpp
+ ABRTSocket.h \
+ ABRTSocket.cpp \
+ run-command.h \
+ run-command.cpp \
+ report.h \
+ report.cpp \
+ dbus.h \
+ dbus.cpp
abrt_cli_CPPFLAGS = \
-I$(srcdir)/../../inc \
diff --git a/src/CLI/dbus.cpp b/src/CLI/dbus.cpp
new file mode 100644
index 00000000..3a2999e2
--- /dev/null
+++ b/src/CLI/dbus.cpp
@@ -0,0 +1,130 @@
+/*
+ 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 "DBusCommon.h"
+
+DBusConnection* s_dbus_conn;
+
+/*
+ * DBus member calls
+ */
+
+/* helpers */
+DBusMessage* new_call_msg(const char* method)
+{
+ DBusMessage* msg = dbus_message_new_method_call(CC_DBUS_NAME, CC_DBUS_PATH, CC_DBUS_IFACE, method);
+ if (!msg)
+ die_out_of_memory();
+ return msg;
+}
+
+DBusMessage* send_get_reply_and_unref(DBusMessage* msg)
+{
+ DBusError err;
+ dbus_error_init(&err);
+ DBusMessage *reply;
+ reply = dbus_connection_send_with_reply_and_block(s_dbus_conn,
+ msg, /*timeout*/ -1, &err);
+ if (reply == NULL)
+ {
+ //TODO: analyse err
+ error_msg_and_die("Error sending DBus message");
+ }
+ dbus_message_unref(msg);
+ return reply;
+}
+
+vector_crash_infos_t call_GetCrashInfos()
+{
+ DBusMessage* msg = new_call_msg("GetCrashInfos");
+ DBusMessage *reply = send_get_reply_and_unref(msg);
+
+ vector_crash_infos_t argout;
+ DBusMessageIter in_iter;
+ dbus_message_iter_init(reply, &in_iter);
+ 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", "GetCrashInfos");
+ dbus_message_unref(reply);
+ return argout;
+}
+
+map_crash_report_t call_CreateReport(const char* uuid)
+{
+ /* Yes, call name is not "CreateReport" but "GetJobResult".
+ * We need to clean up the names one day. */
+ DBusMessage* msg = new_call_msg("GetJobResult");
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ DBusMessage *reply = send_get_reply_and_unref(msg);
+
+ map_crash_report_t argout;
+ DBusMessageIter in_iter;
+ dbus_message_iter_init(reply, &in_iter);
+ 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", "GetJobResult");
+ dbus_message_unref(reply);
+ return argout;
+}
+
+void call_Report(const map_crash_report_t& report)
+{
+ DBusMessage* msg = new_call_msg("Report");
+ DBusMessageIter out_iter;
+ dbus_message_iter_init_append(msg, &out_iter);
+ store_val(&out_iter, report);
+
+ DBusMessage *reply = send_get_reply_and_unref(msg);
+ //it returns a single value of report_status_t type,
+ //but we don't use it (yet?)
+
+ dbus_message_unref(reply);
+}
+
+void call_DeleteDebugDump(const char* uuid)
+{
+ DBusMessage* msg = new_call_msg("DeleteDebugDump");
+ dbus_message_append_args(msg,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ DBusMessage *reply = send_get_reply_and_unref(msg);
+ //it returns a single boolean value,
+ //but we don't use it (yet?)
+
+ dbus_message_unref(reply);
+}
+
+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",
+ CC_DBUS_NAME);
+}
diff --git a/src/CLI/dbus.h b/src/CLI/dbus.h
new file mode 100644
index 00000000..febcb942
--- /dev/null
+++ b/src/CLI/dbus.h
@@ -0,0 +1,34 @@
+/*
+ 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 "CrashTypes.h"
+
+extern DBusConnection* s_dbus_conn;
+
+extern DBusMessage* new_call_msg(const char* method);
+extern DBusMessage* send_get_reply_and_unref(DBusMessage* msg);
+extern vector_crash_infos_t call_GetCrashInfos();
+extern map_crash_report_t call_CreateReport(const char* uuid);
+extern void call_Report(const map_crash_report_t& report);
+extern void call_DeleteDebugDump(const char* uuid);
+extern void handle_dbus_err(bool error_flag, DBusError *err);
+
+#endif
diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp
new file mode 100644
index 00000000..6f2ba6a2
--- /dev/null
+++ b/src/CLI/report.cpp
@@ -0,0 +1,344 @@
+/*
+ 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 "report.h"
+#include "run-command.h"
+#include "dbus.h"
+#include "abrtlib.h"
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(S) gettext(S)
+#else
+#define _(S) (S)
+#endif
+
+#define FIELD_SEP "%----"
+
+/* Escapes the field content string to avoid confusion with file comments.
+ Returned field must be free()d by caller. */
+static char *escape(const char *str)
+{
+ // Determine the size of resultant string.
+ // Count the required number of escape characters.
+ // 1. NEWLINE followed by #
+ // 2. NEWLINE followed by \# (escaped version)
+ const char *ptr = str;
+ bool newline = true;
+ int count = 0;
+ while (*ptr)
+ {
+ if (newline)
+ {
+ if (*ptr == '#')
+ ++count;
+ if (*ptr == '\\' && *(ptr + 1) == '#')
+ ++count;
+ }
+
+ newline = (*ptr == '\n');
+ ++ptr;
+ }
+
+ // Copy the input string to the resultant string, and escape all
+ // occurences of \# and #.
+ char *result = (char*)malloc(strlen(str) + 1 + count);
+ if (!result)
+ error_msg_and_die("Memory error while escaping a field.");
+
+ const char *src = str;
+ char *dest = result;
+ newline = true;
+ while (*src)
+ {
+ if (newline)
+ {
+ if (*src == '#')
+ *dest++ = '\\';
+ else if (*src == '\\' && *(src + 1) == '#')
+ *dest++ = '\\';
+ }
+
+ newline = (*src == '\n');
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+ return result;
+}
+
+/* Removes all comment lines, and unescapes the string previously escaped
+ by escape(). Works in-place. */
+static char *remove_comments_and_unescape(char *str)
+{
+ char *src = str, *dest = str;
+ bool newline = true;
+ while (*src)
+ {
+ if (newline)
+ {
+ if (*src == '#')
+ { // Skip the comment line!
+ while (*src && *src != '\n')
+ ++src;
+
+ if (*src == '\0')
+ break;
+
+ ++src;
+ continue;
+ }
+ else if (*src == '\\' &&
+ (*(src + 1) == '#' ||
+ (*(src + 1) == '\\' && *(src + 2) == '#')))
+ {
+ ++src; // Unescape escaped char.
+ }
+ }
+
+ newline = (*src == '\n');
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+}
+
+/* Writes a field of crash report to a file.
+ * Field must be writable.
+ */
+static void write_crash_report_field(FILE *fp, const map_crash_report_t &report,
+ const char *field, const char *description)
+{
+ const map_crash_report_t::const_iterator it = report.find(field);
+ if (it == report.end())
+ {
+ error_msg("Field %s not found.\n", field);
+ return;
+ }
+
+ if (it->second[CD_TYPE] == CD_SYS)
+ {
+ error_msg("Cannot write field %s because it is a system value\n", field);
+ return;
+ }
+
+ fprintf(fp, "%s%s\n", FIELD_SEP, it->first.c_str());
+
+ bool readonly = (it->second[CD_EDITABLE] != CD_ISEDITABLE);
+ fprintf(fp, readonly ? _("# %s (read only)\n") : "# %s\n", description);
+
+ char *escaped_content = escape(it->second[CD_CONTENT].c_str());
+ fprintf(fp, "%s\n", escaped_content);
+ free(escaped_content);
+}
+
+/* Saves the crash report to a file.
+ * Fp must be opened before write_crash_report is called.
+ * Returned Value:
+ * If the report is successfully stored to the file, a zero value is returned.
+ * On failure, nonzero value is returned.
+ */
+static int write_crash_report(const map_crash_report_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");
+
+ write_crash_report_field(fp, report, "Comment",
+ _("Describe the circumstances of this crash below."));
+ write_crash_report_field(fp, report, "How to reproduce",
+ _("How to reproduce the crash?"));
+ write_crash_report_field(fp, report, "backtrace",
+ _("Backtrace. Check that it does not contain any sensitive data such as passwords."));
+ write_crash_report_field(fp, report, "UUID", "UUID");
+ write_crash_report_field(fp, report, "architecture", "Architecture");
+ write_crash_report_field(fp, report, "cmdline", "Command line");
+ write_crash_report_field(fp, report, "component", "Component");
+ write_crash_report_field(fp, report, "coredump", "Core dump");
+ write_crash_report_field(fp, report, "executable", "Executable");
+ write_crash_report_field(fp, report, "kernel", "Kernel");
+ write_crash_report_field(fp, report, "package", "Package");
+ write_crash_report_field(fp, report, "reason", "Reason");
+ write_crash_report_field(fp, report, "release", "Release");
+
+ return 0;
+}
+
+/*
+ * Updates appropriate field in the report from the text. The text can
+ * contain multiple fields.
+ */
+static void read_crash_report_field(const char *text, map_crash_report_t &report,
+ const char *field)
+{
+ char separator[strlen("\n" FIELD_SEP) + strlen(field) + 2]; // 2 = '\n\0'
+ sprintf(separator, "\n%s%s\n", FIELD_SEP, field);
+ const char *textfield = strstr(text, separator);
+ if (!textfield)
+ return;
+
+ textfield += strlen(separator);
+ int length = 0;
+ const char *end = strstr(textfield, "\n" FIELD_SEP);
+ if (!end)
+ length = strlen(textfield);
+ else
+ length = end - textfield;
+
+ const map_crash_report_t::iterator it = report.find(field);
+ if (it == report.end())
+ {
+ error_msg("Field %s not found.\n", field);
+ return;
+ }
+
+ if (it->second[CD_TYPE] == CD_SYS)
+ {
+ error_msg("Cannot update field %s because it is a system value.\n", field);
+ return;
+ }
+
+ if (it->second[CD_EDITABLE] == CD_ISEDITABLE)
+ it->second[CD_CONTENT].assign(textfield, length);
+}
+
+/*
+ * Updates the crash report 'report' from the text. The text must not contain
+ * any comments.
+ */
+static int read_crash_report(map_crash_report_t &report, const char *text)
+{
+ read_crash_report_field(text, report, "Comment");
+ read_crash_report_field(text, report, "How to reproduce");
+ read_crash_report_field(text, report, "backtrace");
+ read_crash_report_field(text, report, "UUID");
+ read_crash_report_field(text, report, "architecture");
+ read_crash_report_field(text, report, "cmdline");
+ read_crash_report_field(text, report, "component");
+ read_crash_report_field(text, report, "coredump");
+ read_crash_report_field(text, report, "executable");
+ read_crash_report_field(text, report, "kernel");
+ read_crash_report_field(text, report, "package");
+ read_crash_report_field(text, report, "reason");
+ read_crash_report_field(text, report, "release");
+
+ return 0;
+}
+
+/* Runs external editor. */
+int launch_editor(const char *path)
+{
+ const char *editor, *terminal;
+
+ editor = getenv("ABRT_EDITOR");
+ if (!editor)
+ editor = getenv("VISUAL");
+ if (!editor)
+ editor = getenv("EDITOR");
+
+ terminal = getenv("TERM");
+ if (!editor && (!terminal || !strcmp(terminal, "dumb")))
+ {
+ error_msg(_("Terminal is dumb but no VISUAL nor EDITOR defined."));
+ return 1;
+ }
+
+ if (!editor)
+ editor = "vi";
+
+ const char *args[6];
+ args[0] = editor;
+ args[1] = path;
+ run_command(args);
+
+ return 0;
+}
+
+/* Reports the crash with corresponding uuid over DBus. */
+int report(const char *uuid, bool always)
+{
+ map_crash_report_t cr = call_CreateReport(uuid);
+
+ if (always)
+ {
+ call_Report(cr);
+ return 0;
+ }
+
+ /* Open a temporary file and write the crash report to it. */
+ char filename[] = "/tmp/abrt-report.XXXXXX";
+ int fd = mkstemp(filename);
+ if (fd == -1)
+ {
+ error_msg("could not generate temporary file name");
+ return 1;
+ }
+
+ FILE *fp = fdopen(fd, "w");
+ if (!fp)
+ {
+ error_msg("could not open '%s' to save the crash report", filename);
+ return 1;
+ }
+
+ write_crash_report(cr, fp);
+
+ if (fclose(fp))
+ {
+ error_msg("could not close '%s'", filename);
+ return 2;
+ }
+
+ launch_editor(filename);
+
+ fp = fopen(filename, "r");
+ if (!fp)
+ {
+ error_msg("could not open '%s' to read the crash report", filename);
+ return 1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ long size = ftell(fp);
+ printf("%d", size);
+ fseek(fp, 0, SEEK_SET);
+
+ char *text = (char*)malloc(size + 1);
+ if (fread(text, 1, size, fp) != size)
+ {
+ error_msg("could not read '%s'", filename);
+ return 1;
+ }
+ text[size] = '\0';
+ fclose(fp);
+
+ remove_comments_and_unescape(text);
+ read_crash_report(cr, text);
+ free(text);
+
+ /*int result = */unlink(filename);
+
+ printf(_("\nReport has been updated.\nDo you want to send the report? [y/n]: "));
+ fflush(NULL);
+ char answer[16] = "n";
+ fgets(answer, sizeof(answer), stdin);
+ if (answer[0] == 'Y' || answer[0] == 'y')
+ {
+ call_Report(cr);
+ }
+
+ return 0;
+}
diff --git a/src/CLI/report.h b/src/CLI/report.h
new file mode 100644
index 00000000..888babf3
--- /dev/null
+++ b/src/CLI/report.h
@@ -0,0 +1,24 @@
+/*
+ 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_REPORT_H
+#define ABRT_CLI_REPORT_H
+
+/* Reports the crash with corresponding uuid over DBus. */
+extern int report(const char *uuid, bool always);
+
+#endif
diff --git a/src/CLI/run-command.cpp b/src/CLI/run-command.cpp
new file mode 100644
index 00000000..df29b0e1
--- /dev/null
+++ b/src/CLI/run-command.cpp
@@ -0,0 +1,87 @@
+/*
+ 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 "run-command.h"
+#include "abrtlib.h"
+
+/*
+ Inspired by git code.
+ http://git.kernel.org/?p=git/git.git;a=blob;f=run-command.c;hb=HEAD
+*/
+
+struct child_process
+{
+ const char **argv;
+ pid_t pid;
+};
+
+static int start_command(struct child_process *cmd)
+{
+ cmd->pid = fork();
+ if (cmd->pid == 0)
+ { // new process
+ execvp(cmd->argv[0], (char *const*)cmd->argv);
+ exit(127);
+ }
+ if (cmd->pid < 0)
+ {
+ error_msg_and_die("Unable to fork for %s: %s", cmd->argv[0], strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int finish_command(struct child_process *cmd)
+{
+ pid_t waiting;
+ int status, code = -1;
+ while ((waiting = waitpid(cmd->pid, &status, 0)) < 0 && errno == EINTR)
+ ; /* nothing */
+
+ if (waiting < 0)
+ error_msg_and_die("waitpid for %s failed: %s", cmd->argv[0], strerror(errno));
+ else if (waiting != cmd->pid)
+ error_msg_and_die("waitpid is confused (%s)", cmd->argv[0]);
+ else if (WIFSIGNALED(status))
+ {
+ code = WTERMSIG(status);
+ error_msg("%s died of signal %d", cmd->argv[0], code);
+ }
+ else if (WIFEXITED(status))
+ {
+ code = WEXITSTATUS(status);
+ if (code == 127)
+ {
+ code = -1;
+ error_msg_and_die("cannot run %s: %s", cmd->argv[0], strerror(ENOENT));
+ }
+ }
+ else
+ error_msg_and_die("waitpid is confused (%s)", cmd->argv[0]);
+
+ return code;
+}
+
+int run_command(const char **argv)
+{
+ struct child_process cmd;
+ cmd.argv = argv;
+ int code = start_command(&cmd);
+ if (code)
+ return code;
+ return finish_command(&cmd);
+}
diff --git a/src/CLI/run-command.h b/src/CLI/run-command.h
new file mode 100644
index 00000000..45a85af5
--- /dev/null
+++ b/src/CLI/run-command.h
@@ -0,0 +1,23 @@
+/*
+ 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_RUN_COMMAND_H
+#define ABRT_CLI_RUN_COMMAND_H
+
+int run_command(const char **argv);
+
+#endif