#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;
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;
}
}
- 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);
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) {
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;
}
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;
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},
};
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);
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;
}
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);
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");
}