bugreport-service: Add the ability to get coredump file from a report 88/256188/5
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Tue, 30 Mar 2021 16:32:19 +0000 (18:32 +0200)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Thu, 15 Apr 2021 13:58:38 +0000 (15:58 +0200)
This commit adds two more report types that can be obtained:

  coredumptar  - tared coredump file
  fullreport   - zipped report

New types can only be used with a specified report, the identifier of
which must be given as the call argument.

Change-Id: I5c769224c5f5ef89c5d1cc5070a7a4af8a7e0b8a

src/bugreport-service/diagnostics/diagnostics.c
src/bugreport-service/diagnostics/diagnostics.h
src/bugreport-service/diagnostics/diagnostics_dump.c

index ebce15f..f20b357 100644 (file)
@@ -44,6 +44,7 @@
 #define INFO_FILE_EXT     ".info"
 #define LOG_FILE_EXT      ".log"
 #define ZIP_FILE_EXT      ".zip"
+#define COREDUMPTAR_FILE_EXT      "coredump.tar"
 
 enum diagnostics_type {
        BT_UNKNOWN,
@@ -51,6 +52,7 @@ enum diagnostics_type {
        BT_INFO_JSON,
        BT_INFO_FILE,
        BT_LOG,
+       BT_COREDUMP_TAR,
        BT_DIR
 };
 
@@ -64,6 +66,8 @@ static char *type_to_str(enum diagnostics_entry entry) {
                return "INFO_FILE";
        case LOG_FILE:
                return "LOG_FILE";
+       case COREDUMP_TAR:
+               return "COREDUMP_TAR";
        default:
                return "UKNOWN";
        }
@@ -136,6 +140,11 @@ static enum diagnostics_type check_report_type(const char *path)
                return BT_FULL_REPORT;
        }
 
+       if (strstr(path, COREDUMPTAR_FILE_EXT) == &path[strlen(path) - strlen(COREDUMPTAR_FILE_EXT)]) {
+               _D("Report type of %s is COREDUMP_TAR\n", path);
+               return BT_COREDUMP_TAR;
+       }
+
        struct stat file_stat;
        if (stat(path, &file_stat) == -1) {
                _E("stat() for %s error: %m\n", path);
@@ -176,6 +185,8 @@ static bool file_match(const char *file_name, enum diagnostics_entry entry)
                return ends_with(file_name, INFO_FILE_EXT);
        case LOG_FILE:
                return ends_with(file_name, LOG_FILE_EXT);
+       case COREDUMP_TAR:
+               return ends_with(file_name, COREDUMPTAR_FILE_EXT);
        default:
                return false;
        }
index 376ac54..8835ce1 100644 (file)
@@ -28,6 +28,7 @@ enum diagnostics_entry {
        INFO_JSON,
        INFO_FILE,
        LOG_FILE,
+       COREDUMP_TAR,
 };
 
 enum diagnostics_metadata {
index 2b91ac7..9e5e32e 100644 (file)
@@ -33,7 +33,7 @@
 #include "shared/log.h"
 #include "shared/util.h"
 
-enum BUGREPORT_REPORT_TYPE { BR_UNKNOWN, BR_BUGREPORT, BR_CRASHINFO, BR_CRASHINFO_JSON };
+enum BUGREPORT_REPORT_TYPE { BR_UNKNOWN, BR_BUGREPORT, BR_CRASHINFO, BR_CRASHINFO_JSON, BR_COREDUMP_TAR, BR_FULLREPORT };
 
 struct report_file {
        char *file_name;
@@ -132,8 +132,10 @@ static int ctime_compare(const void *a, const void *b)
        return ((struct report_file*)a)->ctime.tv_sec - ((struct report_file*)b)->ctime.tv_sec;
 }
 
-static struct report_file* get_reports(long time_from, long time_to, size_t *count)
+static struct report_file* get_reports(size_t *count)
 {
+       assert(count);
+
        struct report_file *list = NULL;
        *count = 0;
 
@@ -149,12 +151,18 @@ static struct report_file* get_reports(long time_from, long time_to, size_t *cou
                }
        }
 
-       filter_time(list, count, time_from, time_to);
-
        qsort(list, *count, sizeof(struct report_file), ctime_compare);
        return list;
 }
 
+static struct report_file* get_reports_from_range(long time_from, long time_to, size_t *count)
+{
+       struct report_file *list = get_reports(count);
+
+       filter_time(list, count, time_from, time_to);
+       return list;
+}
+
 static void write_bugreport_log_file(int out_fd, const char *report_path)
 {
        int in_fd = diagnostics_report_get_file(report_path, LOG_FILE);
@@ -184,11 +192,9 @@ static bool write_bugreport(int fd, long time_from, long time_to)
        size_t list_count = 0;
        bool result = true;
 
-       struct report_file *list = get_reports(time_from, time_to, &list_count);
-       if (list == NULL) {
-               dprintf(fd, "Internal error.\n");
+       struct report_file *list = get_reports_from_range(time_from, time_to, &list_count);
+       if (list == NULL)
                return false;
-       }
 
        for (int i = 0; i < list_count; i++) {
                if (dprintf(fd, "%sBegin bugreport <%s>\n", (i > 0) ? "\n" : "", list[i].file_path) == -1) {
@@ -218,9 +224,10 @@ static bool write_crash_info(int fd, long time_from, long time_to, bool as_json)
        bool result = true;
        size_t list_count = 0;
 
-       struct report_file *list = get_reports(time_from, time_to, &list_count);
+       struct report_file *list = get_reports_from_range(time_from, time_to, &list_count);
        if (list == NULL) {
-               dprintf(fd, "Internal error.\n");
+               if (as_json)
+                       dprintf(fd, "{\"error\": \"Internal error.\"}");
                return false;
        }
 
@@ -276,12 +283,104 @@ out:
        return result;
 }
 
+static struct report_file *find_report_file(const char *ident, struct report_file *list, size_t list_count)
+{
+       assert(ident);
+       assert(list);
+
+       for (size_t i = 0; i < list_count; i++) {
+               char *dot = rindex(list[i].file_name, '.');
+               if (dot == NULL)
+                       continue;
+               if (strncmp(ident, list[i].file_name, dot - list[i].file_name) == 0)
+                       return &list[i];
+       }
+       return NULL;
+}
+
+static bool write_single_file(int fd, enum BUGREPORT_REPORT_TYPE report_type, const char *ident)
+{
+       assert(fd >= 0);
+       assert(ident);
+
+       bool result = true;
+       size_t list_count = 0;
+       struct report_file *list = get_reports(&list_count);
+       if (list == NULL) {
+               if (report_type == BR_CRASHINFO_JSON)
+                       dprintf(fd, "{\"error\": \"Internal error.\"}");
+               return false;
+       }
+
+       struct report_file *report = find_report_file(ident, list, list_count);
+       if (report == NULL) {
+               result = false;
+               goto out;
+       }
+
+       enum diagnostics_entry report_entry = INFO_FILE;
+       switch (report_type) {
+       case BR_BUGREPORT:
+               report_entry = LOG_FILE;
+               break;
+       case BR_CRASHINFO:
+               report_entry = INFO_FILE;
+               break;
+       case BR_CRASHINFO_JSON:
+               report_entry = INFO_JSON;
+               break;
+       case BR_COREDUMP_TAR:
+               report_entry = COREDUMP_TAR;
+               break;
+       case BR_FULLREPORT:
+               report_entry = FULL_REPORT;
+               break;
+       default:
+               _E("Unsupported report type: %d", report_type);
+               result = false;
+               goto out;
+       }
+
+       int in_fd = diagnostics_report_get_file(report->file_path, report_entry);
+       if (in_fd < 0) {
+               _E("Can not get report type: %d from: %s (report ident: %s)", report_type, report->file_path, ident);
+               result = false;
+               goto out;
+       }
+
+       if (copy_bytes(fd, in_fd, NULL) == -1) {
+               _E("Copy data error");
+               result = false;
+               goto out;
+       }
+out:
+       for (size_t i = 0; i < list_count; i++)
+               free_record(&list[i]);
+       free(list);
+       return result;
+}
+
 struct diagnostics_call_options {
        enum BUGREPORT_REPORT_TYPE report_type;
        long from, to;
        bool last_set, from_set, to_set;
+       char *arg;
 };
 
+static void diagnostics_print_help(int out_fd)
+{
+       dprintf(out_fd, "Usage:\n\n"
+       "  dumpsys org.tizen.bugreport-service [--type=<report_type>] [[--last <seconds> |--from <timestamp> [--to <timestamp>]]|[report_ident]]\n\n"
+       "  --type <report_type>    Specify the type of report. Available types: bugreport, crash-info, crash-info-json. Additional types are available\n"
+       "                          if single report is specified by <report_ident>: fullreport, coredumptar (default: bugreport).\n"
+       "  --last <seconds>        Get reports generated in the last <seconds>.\n"
+       "  --from <timestamp>      Get reports generated after specified time.\n"
+       "  --to <timestamp>        Get reports generated before specified time (default: current time).\n"
+       "  report_ident            Get a specified report.\n\n"
+       "  If no time range or report_ident is specified, all reports will be returned.\n\n"
+       );
+}
+
 static bool diagnostics_call_parse_options(int out_fd, char **params, int params_size, struct diagnostics_call_options *dco)
 {
        struct timespec cur_time;
@@ -292,14 +391,16 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
        dco->last_set = false;
        dco->from_set = false;
        dco->to_set = false;
+       dco->arg = NULL;
 
-       enum PARAM_NAME { PN_TYPE = 1, PN_LAST, PN_TO, PN_FROM };
+       enum PARAM_NAME { PN_TYPE = 1, PN_LAST, PN_TO, PN_FROM, PN_HELP };
 
        struct option long_options[] = {
                {"type", required_argument, NULL, PN_TYPE},
                {"last", required_argument, NULL, PN_LAST},
                {"to", required_argument, NULL, PN_TO},
                {"from", required_argument, NULL, PN_FROM},
+               {"help", no_argument, NULL, PN_HELP},
                {0, 0, 0, 0},
        };
 
@@ -318,6 +419,10 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
                                dco->report_type = BR_CRASHINFO;
                        } else if (strcmp(optarg, "crash-info-json") == 0) {
                                dco->report_type = BR_CRASHINFO_JSON;
+                       } else if (strcmp(optarg, "coredumptar") == 0) {
+                               dco->report_type = BR_COREDUMP_TAR;
+                       } else if (strcmp(optarg, "fullreport") == 0) {
+                               dco->report_type = BR_FULLREPORT;
                        } else {
                                _E("Incorrect report type: %s", optarg);
                                dprintf(out_fd, "Incorrect report type: %s\n", optarg);
@@ -336,13 +441,19 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
                        dco->to_set = true;
                        dco->to = strtol(optarg, NULL, 10);
                        break;
+               case PN_HELP:
+                       diagnostics_print_help(out_fd);
+                       return false;
                default:
-                       _E("Incorrect option: %s", (optind > 0 && optind + 1 < params_size) ? params[optind-1] : "<unknown>");
-                       dprintf(out_fd, "Incorrect option: %s\n", (optind > 0 && optind + 1 < params_size) ? params[optind-1] : "<unknown>");
+                       _E("Incorrect option: %s", (optind > 0 && optind - 1 < params_size + 1) ? nparams[optind-1] : "<unknown>");
+                       dprintf(out_fd, "Incorrect option: %s\n", (optind > 0 && optind - 1 < params_size + 1) ? nparams[optind-1] : "<unknown>");
                        return false;
                }
        }
 
+       if (optind < params_size+1)
+               dco->arg = nparams[optind];
+
        return true;
 }
 
@@ -365,6 +476,16 @@ static void diagnostics_callback(diagnostics_data_h data, char **params, int par
                return;
        }
 
+       if (dco.arg != NULL) {
+               if (dco.last_set || dco.from_set || dco.to_set) {
+                       _E("Incorrect parameters set.");
+                       dprintf(fd, "Incorrect parameters set.\n");
+                       return;
+               }
+               write_single_file(fd, dco.report_type, dco.arg);
+               return;
+       }
+
        switch(dco.report_type) {
        case BR_CRASHINFO:
                write_crash_info(fd, dco.from, dco.to, false);
@@ -375,6 +496,12 @@ static void diagnostics_callback(diagnostics_data_h data, char **params, int par
        case BR_BUGREPORT:
                write_bugreport(fd, dco.from, dco.to);
                break;
+       case BR_COREDUMP_TAR:
+               dprintf(fd, "Report type \"coredumptar\" requires a specific report with report_ident argument.\n");
+               break;
+       case BR_FULLREPORT:
+               dprintf(fd, "Report type \"fullreport\" requires a specific report with report_ident argument.\n");
+               break;
        default:
                _E("Unknown report type\n");
        }