From d9cd2ab6ef3ebe4bb7883690efeb1b8dcb4c3c65 Mon Sep 17 00:00:00 2001 From: Nikola Pajkovsky Date: Fri, 11 Mar 2011 13:18:03 +0100 Subject: CLI.cpp -> cli.c Signed-off-by: Nikola Pajkovsky --- src/cli/CLI.cpp | 432 ---------------------------------------------------- src/cli/Makefile.am | 2 +- src/cli/cli.c | 432 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cli/report.h | 8 + 4 files changed, 441 insertions(+), 433 deletions(-) delete mode 100644 src/cli/CLI.cpp create mode 100644 src/cli/cli.c (limited to 'src/cli') diff --git a/src/cli/CLI.cpp b/src/cli/CLI.cpp deleted file mode 100644 index 49c08279..00000000 --- a/src/cli/CLI.cpp +++ /dev/null @@ -1,432 +0,0 @@ -/* - Copyright (C) 2009, 2010 Red Hat, 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. -*/ -#if HAVE_LOCALE_H -# include -#endif -#include -#include "abrtlib.h" -#include "abrt_dbus.h" -#include "report.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, sizeof(timeloc), "%c", localtime(&time)); - if (!success) - 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(crash_data_t *crash_data) -{ - /* Create a localized string from crash time. */ - 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" - "\tPackage : %s\n" - "\tExecutable : %s\n" - "\tCrash Time : %s\n" - "\tCrash Count: %s\n"), - 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_item_content_or_NULL(crash_data, FILENAME_COUNT) - ); - - free(timeloc); - - /* Print the hostname if it's available. */ - const char *hostname = get_crash_item_content_or_NULL(crash_data, FILENAME_HOSTNAME); - if (hostname) - printf(_("\tHostname : %s\n"), hostname); -} - -/** - * Prints a list containing "crashes" to stdout. - * @param include_reported - * Do not skip entries marked as already reported. - */ -static void print_crash_list(vector_of_crash_data_t *crash_list, bool include_reported) -{ - for (unsigned i = 0; i < crash_list->len; ++i) - { - crash_data_t *crash = get_crash_data(crash_list, i); - if (!include_reported) - { - const char *msg = get_crash_item_content_or_NULL(crash, FILENAME_MESSAGE); - if (!msg || !msg[0]) - continue; - } - - printf("%u.\n", i); - print_crash(crash); - } -} - -/** - * Prints full information about a crash - */ -static void print_crash_info(crash_data_t *crash_data, bool show_backtrace) -{ - 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" - "Analyzer: %s\n" - "Component: %s\n" - "Package: %s\n" - "Command: %s\n" - "Executable: %s\n" - "System: %s, kernel %s\n" - "Reason: %s\n"), - get_crash_item_content_or_die(crash_data, CD_DUMPDIR), - 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_item_content_or_NULL(crash_data, FILENAME_COREDUMP); - if (coredump) - printf(_("Coredump file: %s\n"), coredump); - - 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_item_content_or_NULL(crash_data, FILENAME_CRASH_FUNCTION); - if (crash_function) - printf(_("Crash function: %s\n"), crash_function); - - const char *hostname = get_crash_item_content_or_NULL(crash_data, FILENAME_HOSTNAME); - if (hostname) - printf(_("Hostname: %s\n"), hostname); - - 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_item_content_or_NULL(crash_data, FILENAME_BACKTRACE); - if (backtrace) - printf(_("\nBacktrace:\n%s\n"), backtrace); - } -} - -/* Program options */ -enum -{ - OPT_GET_LIST, - OPT_REPORT, - OPT_DELETE, - OPT_INFO -}; - -/** - * Long options. - * Do not use the has_arg field. Arguments are handled after parsing all options. - * The reason is that we want to use all the following combinations: - * --report ID - * --report ID --always - * --report --always ID - */ -static const struct option longopts[] = -{ - /* name, has_arg, flag, val */ - { "help" , no_argument, NULL, '?' }, - { "verbose" , no_argument, NULL, 'v' }, - { "version" , no_argument, NULL, 'V' }, - { "list" , no_argument, NULL, 'l' }, - { "full" , no_argument, NULL, 'f' }, - { "always" , no_argument, NULL, 'y' }, - { "report" , no_argument, NULL, 'r' }, - { "delete" , no_argument, NULL, 'd' }, - { "info" , no_argument, NULL, 'i' }, - { "backtrace", no_argument, NULL, 'b' }, - { 0, 0, 0, 0 } /* prevents crashes for unknown options*/ -}; - -/* Gets the program name from the first command line argument. */ -static const char *progname(const char *argv0) -{ - const char* name = strrchr(argv0, '/'); - if (name) - return ++name; - return argv0; -} - -/** - * Prints abrt-cli version and some help text. - * Then exits the program with return value 1. - */ -static void print_usage_and_die(char *argv0) -{ - const char *name = progname(argv0); - printf("%s "VERSION"\n\n", name); - - /* Message has embedded tabs. */ - printf(_( - "Usage: %s -l[f] [-D BASE_DIR]...]\n" - " or: %s -r[y] CRASH_DIR\n" - " or: %s -i[b] CRASH_DIR\n" - " or: %s -d CRASH_DIR\n" - "\n" - " -l, --list List not yet reported 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, - DEBUG_DUMPS_DIR - ); - exit(1); -} - -int main(int argc, char** argv) -{ - GList *D_list = NULL; - char *dump_dir_name = NULL; - int op = -1; - bool full = false; - bool always = false; - bool backtrace = false; - - setlocale(LC_ALL, ""); -#if ENABLE_NLS - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); -#endif - - while (1) - { - /* Do not use colons, arguments are handled after parsing all options. */ - int c = getopt_long(argc, argv, "?Vvrdlfyib", longopts, NULL); - -#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; - case 'i': SET_OP(OPT_INFO); break; - case 'f': full = true; break; - case 'y': always = true; break; - case 'b': backtrace = true; break; - case 'v': g_verbose++; break; - case 'D': - D_list = g_list_append(D_list, optarg); - break; - case 'V': - printf("%s "VERSION"\n", progname(argv[0])); - return 0; - case '?': - default: /* some error */ - print_usage_and_die(argv[0]); /* exits app */ - } -#undef SET_OP - } - 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. */ - argc -= optind; - switch (argc) - { - case 0: - if (op == OPT_REPORT || op == OPT_DELETE || op == OPT_INFO) - print_usage_and_die(argv[0]); - break; - case 1: - if (op != OPT_REPORT && op != OPT_DELETE && op != OPT_INFO) - print_usage_and_die(argv[0]); - dump_dir_name = argv[optind]; - break; - default: - print_usage_and_die(argv[0]); - } - - /* Check if we have an operation. - * Limit --full and --always to certain operations. - */ - if ((full && op != OPT_GET_LIST) || - (always && op != OPT_REPORT) || - (backtrace && op != OPT_INFO) || - op == -1) - { - print_usage_and_die(argv[0]); - } - - /* Do the selected operation. */ - int exitcode = 0; - switch (op) - { - case OPT_GET_LIST: - { - 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: - { - struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY); - if (!dd) - break; - int readonly = !dd->locked; - dd_close(dd); - if (readonly) - { - 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) - { - delete_dump_dir_possibly_using_abrtd(dump_dir_name); - dump_dir_name = xstrdup(dd_copy->dd_dirname); - dd_close(dd_copy); - } - } - - 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 = delete_dump_dir_possibly_using_abrtd(dump_dir_name); - break; - } - case OPT_INFO: - { - 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; - } - } - - return exitcode; -} diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index 345598d0..ff6cd590 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -1,7 +1,7 @@ bin_PROGRAMS = abrt-cli abrt_cli_SOURCES = \ - CLI.cpp \ + cli.c \ run-command.h run-command.c \ report.h report.cpp abrt_cli_CPPFLAGS = \ diff --git a/src/cli/cli.c b/src/cli/cli.c new file mode 100644 index 00000000..49c08279 --- /dev/null +++ b/src/cli/cli.c @@ -0,0 +1,432 @@ +/* + Copyright (C) 2009, 2010 Red Hat, 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. +*/ +#if HAVE_LOCALE_H +# include +#endif +#include +#include "abrtlib.h" +#include "abrt_dbus.h" +#include "report.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, sizeof(timeloc), "%c", localtime(&time)); + if (!success) + 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(crash_data_t *crash_data) +{ + /* Create a localized string from crash time. */ + 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" + "\tPackage : %s\n" + "\tExecutable : %s\n" + "\tCrash Time : %s\n" + "\tCrash Count: %s\n"), + 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_item_content_or_NULL(crash_data, FILENAME_COUNT) + ); + + free(timeloc); + + /* Print the hostname if it's available. */ + const char *hostname = get_crash_item_content_or_NULL(crash_data, FILENAME_HOSTNAME); + if (hostname) + printf(_("\tHostname : %s\n"), hostname); +} + +/** + * Prints a list containing "crashes" to stdout. + * @param include_reported + * Do not skip entries marked as already reported. + */ +static void print_crash_list(vector_of_crash_data_t *crash_list, bool include_reported) +{ + for (unsigned i = 0; i < crash_list->len; ++i) + { + crash_data_t *crash = get_crash_data(crash_list, i); + if (!include_reported) + { + const char *msg = get_crash_item_content_or_NULL(crash, FILENAME_MESSAGE); + if (!msg || !msg[0]) + continue; + } + + printf("%u.\n", i); + print_crash(crash); + } +} + +/** + * Prints full information about a crash + */ +static void print_crash_info(crash_data_t *crash_data, bool show_backtrace) +{ + 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" + "Analyzer: %s\n" + "Component: %s\n" + "Package: %s\n" + "Command: %s\n" + "Executable: %s\n" + "System: %s, kernel %s\n" + "Reason: %s\n"), + get_crash_item_content_or_die(crash_data, CD_DUMPDIR), + 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_item_content_or_NULL(crash_data, FILENAME_COREDUMP); + if (coredump) + printf(_("Coredump file: %s\n"), coredump); + + 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_item_content_or_NULL(crash_data, FILENAME_CRASH_FUNCTION); + if (crash_function) + printf(_("Crash function: %s\n"), crash_function); + + const char *hostname = get_crash_item_content_or_NULL(crash_data, FILENAME_HOSTNAME); + if (hostname) + printf(_("Hostname: %s\n"), hostname); + + 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_item_content_or_NULL(crash_data, FILENAME_BACKTRACE); + if (backtrace) + printf(_("\nBacktrace:\n%s\n"), backtrace); + } +} + +/* Program options */ +enum +{ + OPT_GET_LIST, + OPT_REPORT, + OPT_DELETE, + OPT_INFO +}; + +/** + * Long options. + * Do not use the has_arg field. Arguments are handled after parsing all options. + * The reason is that we want to use all the following combinations: + * --report ID + * --report ID --always + * --report --always ID + */ +static const struct option longopts[] = +{ + /* name, has_arg, flag, val */ + { "help" , no_argument, NULL, '?' }, + { "verbose" , no_argument, NULL, 'v' }, + { "version" , no_argument, NULL, 'V' }, + { "list" , no_argument, NULL, 'l' }, + { "full" , no_argument, NULL, 'f' }, + { "always" , no_argument, NULL, 'y' }, + { "report" , no_argument, NULL, 'r' }, + { "delete" , no_argument, NULL, 'd' }, + { "info" , no_argument, NULL, 'i' }, + { "backtrace", no_argument, NULL, 'b' }, + { 0, 0, 0, 0 } /* prevents crashes for unknown options*/ +}; + +/* Gets the program name from the first command line argument. */ +static const char *progname(const char *argv0) +{ + const char* name = strrchr(argv0, '/'); + if (name) + return ++name; + return argv0; +} + +/** + * Prints abrt-cli version and some help text. + * Then exits the program with return value 1. + */ +static void print_usage_and_die(char *argv0) +{ + const char *name = progname(argv0); + printf("%s "VERSION"\n\n", name); + + /* Message has embedded tabs. */ + printf(_( + "Usage: %s -l[f] [-D BASE_DIR]...]\n" + " or: %s -r[y] CRASH_DIR\n" + " or: %s -i[b] CRASH_DIR\n" + " or: %s -d CRASH_DIR\n" + "\n" + " -l, --list List not yet reported 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, + DEBUG_DUMPS_DIR + ); + exit(1); +} + +int main(int argc, char** argv) +{ + GList *D_list = NULL; + char *dump_dir_name = NULL; + int op = -1; + bool full = false; + bool always = false; + bool backtrace = false; + + setlocale(LC_ALL, ""); +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + + while (1) + { + /* Do not use colons, arguments are handled after parsing all options. */ + int c = getopt_long(argc, argv, "?Vvrdlfyib", longopts, NULL); + +#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; + case 'i': SET_OP(OPT_INFO); break; + case 'f': full = true; break; + case 'y': always = true; break; + case 'b': backtrace = true; break; + case 'v': g_verbose++; break; + case 'D': + D_list = g_list_append(D_list, optarg); + break; + case 'V': + printf("%s "VERSION"\n", progname(argv[0])); + return 0; + case '?': + default: /* some error */ + print_usage_and_die(argv[0]); /* exits app */ + } +#undef SET_OP + } + 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. */ + argc -= optind; + switch (argc) + { + case 0: + if (op == OPT_REPORT || op == OPT_DELETE || op == OPT_INFO) + print_usage_and_die(argv[0]); + break; + case 1: + if (op != OPT_REPORT && op != OPT_DELETE && op != OPT_INFO) + print_usage_and_die(argv[0]); + dump_dir_name = argv[optind]; + break; + default: + print_usage_and_die(argv[0]); + } + + /* Check if we have an operation. + * Limit --full and --always to certain operations. + */ + if ((full && op != OPT_GET_LIST) || + (always && op != OPT_REPORT) || + (backtrace && op != OPT_INFO) || + op == -1) + { + print_usage_and_die(argv[0]); + } + + /* Do the selected operation. */ + int exitcode = 0; + switch (op) + { + case OPT_GET_LIST: + { + 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: + { + struct dump_dir *dd = dd_opendir(dump_dir_name, DD_OPEN_READONLY); + if (!dd) + break; + int readonly = !dd->locked; + dd_close(dd); + if (readonly) + { + 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) + { + delete_dump_dir_possibly_using_abrtd(dump_dir_name); + dump_dir_name = xstrdup(dd_copy->dd_dirname); + dd_close(dd_copy); + } + } + + 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 = delete_dump_dir_possibly_using_abrtd(dump_dir_name); + break; + } + case OPT_INFO: + { + 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; + } + } + + return exitcode; +} diff --git a/src/cli/report.h b/src/cli/report.h index 80c0b9f2..58b8c25e 100644 --- a/src/cli/report.h +++ b/src/cli/report.h @@ -18,6 +18,10 @@ #ifndef ABRT_CLI_REPORT_H #define ABRT_CLI_REPORT_H +#ifdef __cplusplus +extern "C" { +#endif + int run_analyze_event(const char *dump_dir_name); /* Report the crash */ @@ -26,4 +30,8 @@ enum { }; int report(const char *dump_dir_name, int flags); +#ifdef __cplusplus +} +#endif + #endif -- cgit