diff options
| author | Nikola Pajkovsky <npajkovs@redhat.com> | 2009-10-21 16:45:34 +0200 |
|---|---|---|
| committer | Nikola Pajkovsky <npajkovs@redhat.com> | 2009-10-21 16:45:34 +0200 |
| commit | 1821d3811b019c3c7ffaaf875cdfe52d33954cb9 (patch) | |
| tree | 5ae9593044b3deabd2bbf4c0ec5a9aabe530108a /src | |
| parent | 4bebcf3bae780d5de960ae8279d93cf90447e729 (diff) | |
| parent | 3588b74b1445c33071edac67577599bc6915ab23 (diff) | |
| download | abrt-1821d3811b019c3c7ffaaf875cdfe52d33954cb9.tar.gz abrt-1821d3811b019c3c7ffaaf875cdfe52d33954cb9.tar.xz abrt-1821d3811b019c3c7ffaaf875cdfe52d33954cb9.zip | |
Merge branch 'master' into experimental
Diffstat (limited to 'src')
| -rw-r--r-- | src/CLI/ABRTSocket.cpp | 9 | ||||
| -rw-r--r-- | src/CLI/ABRTSocket.h | 2 | ||||
| -rw-r--r-- | src/CLI/CLI.cpp | 256 | ||||
| -rw-r--r-- | src/CLI/Makefile.am | 19 | ||||
| -rw-r--r-- | src/CLI/abrt-cli.1 | 16 | ||||
| -rw-r--r-- | src/CLI/abrt-cli.bash | 34 | ||||
| -rw-r--r-- | src/CLI/dbus.cpp | 130 | ||||
| -rw-r--r-- | src/CLI/dbus.h | 32 | ||||
| -rw-r--r-- | src/CLI/report.cpp | 423 | ||||
| -rw-r--r-- | src/CLI/report.h | 24 | ||||
| -rw-r--r-- | src/CLI/run-command.cpp | 87 | ||||
| -rw-r--r-- | src/CLI/run-command.h | 23 | ||||
| -rw-r--r-- | src/Daemon/Makefile.am | 5 | ||||
| -rw-r--r-- | src/Daemon/MiddleWare.cpp | 2 | ||||
| -rwxr-xr-x | src/Daemon/abrt-debuginfo-install | 224 | ||||
| -rw-r--r-- | src/Daemon/org.fedoraproject.abrt.policy | 4 | ||||
| -rw-r--r-- | src/Gui/ABRTExceptions.py | 4 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/Gui/abrt-gui | 2 |
18 files changed, 1096 insertions, 200 deletions
diff --git a/src/CLI/ABRTSocket.cpp b/src/CLI/ABRTSocket.cpp index 1f90f63..d31c7a4 100644 --- a/src/CLI/ABRTSocket.cpp +++ b/src/CLI/ABRTSocket.cpp @@ -8,13 +8,12 @@ #include <sys/un.h> #include <string.h> -CABRTSocket::CABRTSocket() : - m_nSocket(-1) +CABRTSocket::CABRTSocket() : m_nSocket(-1) {} CABRTSocket::~CABRTSocket() { - DisConnect(); + Disconnect(); } void CABRTSocket::Send(const std::string& pMessage) @@ -91,12 +90,10 @@ void CABRTSocket::Connect(const std::string& pPath) } } -void CABRTSocket::DisConnect() +void CABRTSocket::Disconnect() { if (m_nSocket != -1) - { close(m_nSocket); - } } vector_crash_infos_t CABRTSocket::GetCrashInfos() diff --git a/src/CLI/ABRTSocket.h b/src/CLI/ABRTSocket.h index d476411..5d5383f 100644 --- a/src/CLI/ABRTSocket.h +++ b/src/CLI/ABRTSocket.h @@ -18,7 +18,7 @@ class CABRTSocket ~CABRTSocket(); void Connect(const std::string& pPath); - void DisConnect(); + void Disconnect(); vector_crash_infos_t GetCrashInfos(); map_crash_report_t CreateReport(const std::string& pUUID); diff --git a/src/CLI/CLI.cpp b/src/CLI/CLI.cpp index 33272df..18e99dc 100644 --- a/src/CLI/CLI.cpp +++ b/src/CLI/CLI.cpp @@ -21,8 +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> +#endif +#if ENABLE_NLS +#include <libintl.h> +#define _(S) gettext(S) +#else +#define _(S) (S) #endif /* Program options */ @@ -37,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; @@ -47,148 +56,35 @@ static void print_crash_infos(vector_crash_infos_t& pCrashInfos, int pMode) map_crash_info_t& info = pCrashInfos[ii]; if (pMode == OPT_GET_LIST_FULL || info.find(CD_REPORTED)->second[CD_CONTENT] != "1") { - printf("%u.\n" - "\tUID : %s\n" - "\tUUID : %s\n" - "\tPackage : %s\n" - "\tExecutable: %s\n" - "\tCrash time: %s\n" - "\tCrash Rate: %s\n", - ii, - info[CD_UID][CD_CONTENT].c_str(), - info[CD_UUID][CD_CONTENT].c_str(), - info[CD_PACKAGE][CD_CONTENT].c_str(), - info[CD_EXECUTABLE][CD_CONTENT].c_str(), - info[CD_TIME][CD_CONTENT].c_str(), - info[CD_COUNT][CD_CONTENT].c_str() - ); + const char *timestr = info[CD_TIME][CD_CONTENT].c_str(); + long time = strtol(timestr, 0, 10); + if (time == 0) + error_msg_and_die("Error while converting time string."); + + char timeloc[256]; + int success = strftime(timeloc, 128, "%c", localtime(&time)); + if (!success) + error_msg_and_die("Error while converting time to string."); + + printf(_("%u.\n" + "\tUID : %s\n" + "\tUUID : %s\n" + "\tPackage : %s\n" + "\tExecutable : %s\n" + "\tCrash Time : %s\n" + "\tCrash Count: %s\n"), + ii, + info[CD_UID][CD_CONTENT].c_str(), + info[CD_UUID][CD_CONTENT].c_str(), + info[CD_PACKAGE][CD_CONTENT].c_str(), + info[CD_EXECUTABLE][CD_CONTENT].c_str(), + timeloc, + info[CD_COUNT][CD_CONTENT].c_str() + ); } } } -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); -} - static const struct option longopts[] = { /* name, has_arg, flag, val */ @@ -202,7 +98,7 @@ static const struct option longopts[] = { 0, 0, 0, 0 } /* prevents crashes for unknown options*/ }; -/* Gets program name from command line argument. */ +/* Gets the program name from the first command line argument. */ static char *progname(char *argv0) { char* name = strrchr(argv0, '/'); @@ -212,11 +108,36 @@ static char *progname(char *argv0) return argv0; } +/* Prints abrt-cli version and some help text. */ +static void usage(char *argv0) +{ + 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" + " --get-list print list of crashes which are not reported yet\n" + " --get-list-full print list of all crashes\n" + " --report UUID create and send a report\n" + " --report-always UUID create and send a report without asking\n" + " --delete UUID remove crash\n"), + name, name); +} + int main(int argc, char** argv) { char* uuid = NULL; int op = -1; - char *name; + + setlocale(LC_ALL,""); +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif while (1) { @@ -233,7 +154,7 @@ int main(int argc, char** argv) case OPT_GET_LIST_FULL: if (op == -1) break; - error_msg("You must specify exactly one operation."); + error_msg(_("You must specify exactly one operation.")); return 1; case -1: /* end of options */ if (op != -1) /* if some operation was specified... */ @@ -242,25 +163,12 @@ int main(int argc, char** argv) default: case '?': case OPT_HELP: - name = progname(argv[0]); - printf("%s " VERSION "\n\n", name); - /* note: 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" - " --get-list print list of crashes which are not reported yet\n" - " --get-list-full print list of all crashes\n" - " --report UUID create and send a report\n" - " --report-always UUID create and send a report without asking\n" - " --delete UUID remove crash\n", - name, name); - return 1; + usage(argv[0]); + return 1; case 'V': case OPT_VERSION: - printf("%s " VERSION "\n", progname(argv[0])); - return 0; + printf("%s " VERSION "\n", progname(argv[0])); + return 0; } if (c == -1) break; @@ -276,6 +184,7 @@ int main(int argc, char** argv) CABRTSocket ABRTDaemon; ABRTDaemon.Connect(VAR_RUN"/abrt.socket"); #endif + switch (op) { case OPT_GET_LIST: @@ -286,33 +195,20 @@ int main(int argc, char** argv) break; } case OPT_REPORT: - { - map_crash_report_t cr = call_CreateReport(uuid); - print_crash_report(cr); - 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); - } - break; - } + report(uuid, false); + break; case OPT_REPORT_ALWAYS: - { - map_crash_report_t cr = call_CreateReport(uuid); - call_Report(cr); - break; - } + report(uuid, true); + break; case OPT_DELETE: { call_DeleteDebugDump(uuid); break; } } + #if ENABLE_SOCKET - ABRTDaemon.DisConnect(); + ABRTDaemon.Disconnect(); #endif return 0; diff --git a/src/CLI/Makefile.am b/src/CLI/Makefile.am index 9447791..7b10bfb 100644 --- a/src/CLI/Makefile.am +++ b/src/CLI/Makefile.am @@ -2,7 +2,15 @@ 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 \ -I$(srcdir)/../../lib/Utils \ @@ -11,5 +19,14 @@ abrt_cli_CPPFLAGS = \ $(DBUS_CFLAGS) \ -D_GNU_SOURCE # $(GTK_CFLAGS) + abrt_cli_LDADD = \ ../../lib/Utils/libABRTUtils.la + +man_MANS = abrt-cli.1 +EXTRA_DIST = $(man_MANS) + +completiondir = $(sysconfdir)/bash_completion.d +completion_DATA = abrt-cli.bash + +DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ diff --git a/src/CLI/abrt-cli.1 b/src/CLI/abrt-cli.1 index fb0a7c8..4fe4bb4 100644 --- a/src/CLI/abrt-cli.1 +++ b/src/CLI/abrt-cli.1 @@ -2,12 +2,12 @@ .SH NAME abrt\-cli \- a command line interface to abrt .SH SYNOPSIS -.B abrt\-cli +.B abrt\-cli [option] .SH DESCRIPTION .I abrt\-cli is a command line tool that manages application crashes catched by -.I abrtd +.I abrtd daemon. It enables access to crash data, and allows to report crashes depending on active abrt plugins. .SH OPTIONS @@ -24,11 +24,17 @@ Prints list of crashes which are not reported yet. .IP "\-\-get-list-full" Prints list of all crashes. .IP "\-\-report \fIUUID\fR" -Creates and sends a report. +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 "\-\-report-always \fIUUID\fR" -Creates and sends a report without asking. +Creates and sends the crash report without asking. .IP "\-\-delete \fIUUID\fR" -Removes crash. +Removes data about particular crash. +.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), diff --git a/src/CLI/abrt-cli.bash b/src/CLI/abrt-cli.bash new file mode 100644 index 0000000..10b086a --- /dev/null +++ b/src/CLI/abrt-cli.bash @@ -0,0 +1,34 @@ +# bash-completion add-on for abrt-cli(1) +# http://bash-completion.alioth.debian.org/ + +_abrt_cli() +{ + local cur prev opts + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + opts="--help --version --get-list --get-list-full --report --report-always --delete" + + # + # Complete the arguments to some of the basic commands. + # + case "${prev}" in + --report|--report-always|--delete) + local uuids=$(abrt-cli --get-list | grep UUID | awk '{print $3}') + COMPREPLY=( $(compgen -W "${uuids}" -- ${cur}) ) + return 0 + ;; + esac + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 +} +complete -F _abrt_cli abrt-cli + +# Local variables: +# mode: shell-script +# sh-basic-offset: 4 +# sh-indent-comment: t +# indent-tabs-mode: nil +# End: +# ex: ts=4 sw=4 et filetype=sh
\ No newline at end of file diff --git a/src/CLI/dbus.cpp b/src/CLI/dbus.cpp new file mode 100644 index 0000000..420fe70 --- /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 */ +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; + 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 0000000..c6cb82a --- /dev/null +++ b/src/CLI/dbus.h @@ -0,0 +1,32 @@ +/* + 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 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 0000000..b9a1391 --- /dev/null +++ b/src/CLI/report.cpp @@ -0,0 +1,423 @@ +/* + 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" +#include "DebugDump.h" // FILENAME_* defines +#if HAVE_CONFIG_H +#include <config.h> +#endif +#if ENABLE_NLS +#include <libintl.h> +#define _(S) gettext(S) +#else +#define _(S) (S) +#endif + +/* Field separator for the crash report file that is edited by user. */ +#define FIELD_SEP "%----" + +/* + * Trims whitespace characters both from left and right side of a string. + * Modifies the string in-place. Returns the trimmed string. + */ +char *trim(char *str) +{ + if (!str) + return NULL; + + // Remove leading spaces. + char *ibuf; + for (ibuf = str; *ibuf && isspace(*ibuf); ++ibuf) + ; + if (str != ibuf) + memmove(str, ibuf, ibuf - str); + + // Remove trailing spaces. + int i = strlen(str); + while (--i >= 0) + { + if (!isspace(str[i])) + break; + } + str[++i] = NULL; + return str; +} + +/* + * 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 void 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()) + { + // exit silently, all fields are optional for now + //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()); + + fprintf(fp, "%s\n", description); + if (it->second[CD_EDITABLE] != CD_ISEDITABLE) + fprintf(fp, _("# This field is read only.\n")); + + 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. + * Parameter '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, CD_COMMENT, + _("# Describe the circumstances of this crash below.")); + write_crash_report_field(fp, report, CD_REPRODUCE, + _("# How to reproduce the crash?")); + write_crash_report_field(fp, report, "backtrace", + _("# Stack trace: a list of active stack frames at the time the crash occurred\n# Check that it does not contain any sensitive data such as passwords.")); + write_crash_report_field(fp, report, CD_UUID, _("# UUID")); + write_crash_report_field(fp, report, FILENAME_ARCHITECTURE, _("# Architecture")); + write_crash_report_field(fp, report, "cmdline", _("# Command line")); + write_crash_report_field(fp, report, FILENAME_COMPONENT, _("# Component")); + write_crash_report_field(fp, report, "coredump", _("# Core dump")); + write_crash_report_field(fp, report, FILENAME_EXECUTABLE, _("# Executable")); + 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")); + + return 0; +} + +/* + * Updates appropriate field in the report from the text. The text can + * contain multiple fields. + * Returns: + * 0 if no change to the field was detected. + * 1 if the field was changed. + * Changes to read-only fields are ignored. + */ +static int 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 0; // exit silently because all fields are optional + + 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 0; + } + + if (it->second[CD_TYPE] == CD_SYS) + { + error_msg("Cannot update field %s because it is a system value.\n", field); + return 0; + } + + // Do not change noneditable fields. + if (it->second[CD_EDITABLE] != CD_ISEDITABLE) + return 0; + + // Compare the old field contents with the new field contents. + char newvalue[length + 1]; + strncpy(newvalue, textfield, length); + newvalue[length] = '\0'; + trim(newvalue); + + char oldvalue[it->second[CD_CONTENT].length() + 1]; + strcpy(oldvalue, it->second[CD_CONTENT].c_str()); + trim(oldvalue); + + // Return if no change in the contents detected. + int cmp = strcmp(newvalue, oldvalue); + if (!cmp) + return 0; + + it->second[CD_CONTENT].assign(newvalue); + return 1; +} + +/* + * Updates the crash report 'report' from the text. The text must not contain + * any comments. + * Returns: + * 0 if no field was changed. + * 1 if any field was changed. + * Changes to read-only fields are ignored. + */ +static int read_crash_report(map_crash_report_t &report, const char *text) +{ + int result = 0; + result |= read_crash_report_field(text, report, CD_COMMENT); + result |= read_crash_report_field(text, report, CD_REPRODUCE); + result |= read_crash_report_field(text, report, "backtrace"); + result |= read_crash_report_field(text, report, CD_UUID); + result |= read_crash_report_field(text, report, FILENAME_ARCHITECTURE); + result |= read_crash_report_field(text, report, "cmdline"); + result |= read_crash_report_field(text, report, FILENAME_COMPONENT); + result |= read_crash_report_field(text, report, "coredump"); + result |= read_crash_report_field(text, report, FILENAME_EXECUTABLE); + 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); + return result; +} + +/* 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) +{ + // Ask for an initial report. + map_crash_report_t cr = call_CreateReport(uuid); + + if (always) + { + // Send the report immediately. + 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; + } + + // Start a text editor on the temporary file. + launch_editor(filename); + + // Read the file back and update the report from the file. + 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); + 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); + // Updates the crash report from the file text. + int report_changed = read_crash_report(cr, text); + if (report_changed) + puts(_("\nThe report has been updated.")); + else + puts(_("\nNo changes were detected in the report.")); + + free(text); + + if (unlink(filename) != 0) // Delete the tempfile. + error_msg("could not unlink %s: %s", filename, strerror(errno)); + + // Report only if the user is sure. + printf(_("Do 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') + { + puts(_("Reporting...")); + call_Report(cr); + puts(_("Crash report was successfully sent.")); + } + else + puts(_("Crash report was not sent.")); + + return 0; +} diff --git a/src/CLI/report.h b/src/CLI/report.h new file mode 100644 index 0000000..888babf --- /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 0000000..80184cf --- /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 0000000..45a85af --- /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 diff --git a/src/Daemon/Makefile.am b/src/Daemon/Makefile.am index 29c7f1b..0067e5d 100644 --- a/src/Daemon/Makefile.am +++ b/src/Daemon/Makefile.am @@ -1,3 +1,5 @@ +bin_SCRIPTS = abrt-debuginfo-install + sbin_PROGRAMS = abrtd abrtd_SOURCES = \ @@ -43,7 +45,8 @@ comredhatabrtservicedir = ${datadir}/dbus-1/system-services dist_comredhatabrtservice_DATA = com.redhat.abrt.service man_MANS = abrtd.8 abrt.conf.5 -EXTRA_DIST = $(man_MANS) + +EXTRA_DIST = $(man_MANS) abrt-debuginfo-install DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@ diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp index 05abc9b..9060d79 100644 --- a/src/Daemon/MiddleWare.cpp +++ b/src/Daemon/MiddleWare.cpp @@ -499,7 +499,7 @@ void LoadOpenGPGPublicKey(const char* key) * @return It return results of operation. See mw_result_t. */ static mw_result_t SavePackageDescriptionToDebugDump(const std::string& pExecutable, - const std::string& pDebugDumpDir) + const std::string& pDebugDumpDir) { std::string package; std::string packageName; diff --git a/src/Daemon/abrt-debuginfo-install b/src/Daemon/abrt-debuginfo-install new file mode 100755 index 0000000..fc5380b --- /dev/null +++ b/src/Daemon/abrt-debuginfo-install @@ -0,0 +1,224 @@ +#!/bin/sh +# Called by abrtd before producing a backtrace. +# The task of this script is to install debuginfos. +# +# Just using [pk-]debuginfo-install does not work well. +# - they can't install more than one version of debuginfo +# for a package +# - their output is unsuitable for scripting +# - debuginfo-install aborts if yum lock is busy +# - pk-debuginfo-install was observed to hang +# +# Usage: abrt-debuginfo-install CORE TEMPDIR [CACHEDIR] +# If CACHEDIR is specified, debuginfos should be installed there. +# If not, debuginfos should be installed into TEMPDIR. +# +# Currently, we are called with CACHEDIR set to "/", but in the future +# it may be omitted or set to something else. script must be ready +# for those cases too. +# +# Output goes to GUI as debuginfo install log. The script should be careful +# to give useful, but not overly cluttered info to stdout. +# Additionally, abrt daemon handles "MISSING:xxxx" messages specially: +# xxxx will be prepended to backtrace. This is used to inform about +# missing debuginfos. +# +# Exitcodes: +# 0 - all debuginfos are installed +# 1 - not all debuginfos are installed +# 2+ - serious problem +# +# Algorithm: +# - Create TEMPDIR +# - Extract build-ids from coredump +# - For every build-id, check /usr/lib/debug/.build-id/XX/XXXX.debug +# and CACHEDIR/usr/lib/debug/.build-id/XX/XXXX.debug +# - If they all exist, exit 0 +# - Using "yum provides /usr/lib/debug/.build-id/XX/XXXX.debug", +# figure out which debuginfo packages are needed +# - Download them using "yumdownloader PACKAGE..." +# - Unpack them with rpm2cpio | cpio to TEMPDIR +# - If CACHEDIR is specified, copy usr/lib/debug/.build-id/XX/XXXX.debug +# to CACHEDIR/usr/lib/debug/.build-id/XX/XXXX.debug and delete TEMPDIR +# - Report which XX/XXXX.debug are still missing. +# +# For better debuggability, eu_unstrip.OUT, yum_provides.OUT etc files +# are saved in TEMPDIR, and TEMPDIR is not deleted if we exit with exitcode 2 +# ("serious problem"). +# +# In the future, we may want to use a separate CACHEDIR (say, /var/cache/abrt-di) +# and use it with this gdb command: +# set debug-file-directory /usr/lib/debug/.build-id:CACHEDIR/usr/lib/debug/.build-id +# but current gdb can't handle DIR1:DIR2. +# So, currently we are called with CACHEDIR set to "/", and don't pass +# "set debug-file-directory" to gdb. +# This is ugly, since it messes up /usr/lib/debug/.build-id over time +# by piling up debuginfos there without any means to control their amount, +# but it's the only way to make it work with current gdb. + + +core=$1 +tempdir=$2 +cachedir=$3 +debug=false + +count_words() { + echo $# +} + +exec 2>&1 + +test -f "$core" || exit 2 +# cachedir is optional +test x"$cachedir" = x"" || test -d "$cachedir" || exit 2 +# tempdir must not exist +test -e "$tempdir" && exit 2 + +mkdir "$tempdir" || exit 2 +cd "$tempdir" || exit 2 +$debug && echo "Installing rpms to $tempdir" + +# eu-unstrip output example: +# 0x400000+0x209000 23c77451cf6adff77fc1f5ee2a01d75de6511dda@0x40024c - - [exe] +# or +# 0x400000+0x20d000 233aa1a57e9ffda65f53efdaf5e5058657a39993@0x40024c /usr/libexec/im-settings-daemon /usr/lib/debug/usr/libexec/im-settings-daemon.debug [exe] +# 0x7fff5cdff000+0x1000 0d3eb4326fd7489fcf9b598269f1edc420e2c560@0x7fff5cdff2f8 . - linux-vdso.so.1 +# 0x3d15600000+0x208000 20196628d1bc062279622615cc9955554e5bb227@0x3d156001a0 /usr/lib64/libnotify.so.1.1.3 /usr/lib/debug/usr/lib64/libnotify.so.1.1.3.debug libnotify.so.1 +# 0x7fd8ae931000+0x62d000 dd49f44f958b5a11a1635523b2f09cb2e45c1734@0x7fd8ae9311a0 /usr/lib64/libgtk-x11-2.0.so.0.1600.6 /usr/lib/debug/usr/lib64/libgtk-x11-2.0.so.0.1600.6.debug +echo "Getting list of build IDs" +eu_unstrip_OUT=`eu-unstrip "--core=$core" -n 2>&1` +err=$? +printf "%s\nexitcode:%s\n" "$eu_unstrip_OUT" $err >eu_unstrip.OUT +test $err = 0 || exit 2 + +# Get space-separated list of all build-ids +# There can be duplicates (observed in real world) +build_ids=`printf "%s\n" "$eu_unstrip_OUT" \ +| while read junk1 build_id binary_file di_file lib_name junk2; do + build_id=${build_id%%@*} + + # This filters out linux-vdso.so, among others + test x"$lib_name" != x"[exe]" && test x"${binary_file:0:1}" != x"/" && continue + # Sanitize build_id: must be longer than 2 chars + test ${#build_id} -le 2 && continue + # Sanitize build_id: must have only hex digits + test x"${build_id//[0-9a-f]/}" != x"" && continue + + echo "$build_id" +done | sort | uniq | xargs` +$debug && echo "build_ids:$build_ids" + +# Which debuginfo files are missing? +missing_debuginfo_files=`for build_id in $build_ids; do + build_id1=${build_id:0:2} + build_id2=${build_id:2} + + file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug" + if test x"$cachedir" != x"" && test x"$cachedir" != x"/" ; then + test -f "$cachedir/$file" && continue + if test -f "/$file"; then + mkdir -p "$cachedir/usr/lib/debug/.build-id/$build_id1" + # Note: this does not preserve symlinks. This is intentional + $debug && echo Copying "$file" to "$cachedir/$file" >&2 + cp "$file" "$cachedir/$file" + continue + fi + fi + test -f "/$file" && continue + echo -n "/$file " +done` +$debug && echo "missing_debuginfo_files:$missing_debuginfo_files" + +test x"$missing_debuginfo_files" = x"" && exit 0 + +# We'll run something like: +# yum --enablerepo='*debuginfo*' --quiet provides \ +# /usr/lib/debug/.build-id/bb/11528d59940983f495e9cb099cafb0cb206051.debug \ +# /usr/lib/debug/.build-id/c5/b84c0ad3676509dc30bfa7d42191574dac5b06.debug ... +echo "Determining list of packages for `count_words $missing_debuginfo_files` missing debuginfos" +yum_provides_OUT=`yum --enablerepo='*debuginfo*' --quiet provides $missing_debuginfo_files 2>&1` +err=$? +printf "%s\nexitcode:%s\n" "$yum_provides_OUT" $err >yum_provides.OUT +test $err = 0 || exit 2 + +# The output is pretty machine-unfriendly: +# glibc-debuginfo-2.10.90-24.x86_64 : Debug information for package glibc +# Repo : rawhide-debuginfo +# Matched from: +# Filename : /usr/lib/debug/.build-id/5b/c784c8d63f87dbdeb747a773940956a18ecd2f.debug +# +# 1:dbus-debuginfo-1.2.12-2.fc11.x86_64 : Debug information for package dbus +# Repo : updates-debuginfo +# Matched from: +# Filename : /usr/lib/debug/.build-id/bc/da7d09eb6c9ee380dae0ed3d591d4311decc31.debug +# Need to massage it a lot. +# There can be duplicates (one package may provide many debuginfos). +packages=`printf "%s\n" "$yum_provides_OUT" \ +| grep -- -debuginfo- \ +| sed 's/^[0-9]*://' \ +| sed -e 's/ .*//' -e 's/:.*//' \ +| sort | uniq | xargs` +$debug && echo "packages:$packages" + +# yum may return "" here if it found no packages (say, if coredump is from a new, +# unreleased package fresh from koji). +test x"$packages" = x"" && exit 1 + +# Redirecting, since progress bar stuff only messes up our output +echo "Downloading `count_words $packages` packages" +yumdownloader --enablerepo='*debuginfo*' --quiet $packages >yumdownloader.OUT 2>&1 +err=$? +echo "exitcode:$err" >>yumdownloader.OUT +test $err = 0 || exit 2 + +for f in *.rpm; do + # Happens if no .rpm's were downloaded (yumdownloader problem) + # In this case, $f is the literal "*.rpm" string + test -f "$f" || exit 2 + echo "Unpacking: $f" + echo "Processing: $f" >>unpack.OUT + rpm2cpio <"$f" 2>>unpack.OUT | cpio -id >>unpack.OUT 2>&1 +done + +# Which debuginfo files are still missing, including those we just unpacked? +missing_build_ids=`for build_id in $build_ids; do + build_id1=${build_id:0:2} + build_id2=${build_id:2} + + file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug" + + test -f "/$file" && continue + test x"$cachedir" != x"" \ + && test x"$cachedir" != x"/" \ + && test -f "$cachedir/$file" && continue + + if test -f "$file"; then + # file is one of those we just installed. + # Cache it if cachedir is specified. + if test x"$cachedir" != x"" && test -d "$cachedir"; then + mkdir -p "$cachedir/usr/lib/debug/.build-id/$build_id1" + # Note: this does not preserve symlinks. This is intentional + $debug && echo Copying "$file" to "$cachedir/$file" >&2 + cp --remove-destination "$file" "$cachedir/$file" + fi + continue + fi + echo -n "$build_id " +done` +$debug && echo "missing_build_ids:$missing_build_ids" + +# If cachedir is specified, tempdir is just a staging area. Delete it +if test x"$cachedir" != x""; then + $debug && echo "Removing $tempdir" + rm -rf "$tempdir" +fi + +test x"$missing_build_ids" = x"" && exit 0 + +for missing in $missing_build_ids; do + echo "MISSING:$missing" +done + +echo "`count_words $missing_build_ids` debuginfos can't be found" + +exit 1 diff --git a/src/Daemon/org.fedoraproject.abrt.policy b/src/Daemon/org.fedoraproject.abrt.policy index 1c2c0bb..9261acd 100644 --- a/src/Daemon/org.fedoraproject.abrt.policy +++ b/src/Daemon/org.fedoraproject.abrt.policy @@ -30,9 +30,9 @@ Copyright (c) 2009 Red Hat inc. <description>Install debuginfos</description> <message>Installing debuginfos requires authentication</message> <defaults> - <allow_any>no</allow_any> + <allow_any>yes</allow_any> <allow_active>yes</allow_active> - <allow_inactive>no</allow_inactive> + <allow_inactive>yes</allow_inactive> </defaults> </action> </policyconfig> diff --git a/src/Gui/ABRTExceptions.py b/src/Gui/ABRTExceptions.py index 3049638..0d357a3 100644 --- a/src/Gui/ABRTExceptions.py +++ b/src/Gui/ABRTExceptions.py @@ -14,11 +14,11 @@ class WrongData(Exception): def __str__(self): return self.what - + class ConfBackendInitError(Exception): def __init__(self, msg): Exception.__init__(self) self.what = msg - + def __str__(self): return self.what diff --git a/src/Gui/abrt-gui b/src/Gui/abrt-gui index dd0897c..85bdebb 100644..100755 --- a/src/Gui/abrt-gui +++ b/src/Gui/abrt-gui @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh export PYTHONPATH=/usr/share/abrt export XLOGNAME=$LOGNAME exec /usr/bin/python /usr/share/abrt/CCMainWindow.py "$@" |
