#include "shared/log.h"
#include "shared/util.h"
-enum BUGREPORT_REPORT_TYPE { BR_UNKNOWN, BR_BUGREPORT, BR_CRASHINFO, BR_CRASHINFO_JSON, BR_COREDUMP_TAR, BR_FULLREPORT };
+enum BUGREPORT_REPORT_TYPE { BR_UNKNOWN, BR_BUGREPORT, BR_CRASHINFO, BR_CRASHINFO_JSON, BR_COREDUMP_TAR, BR_FULLREPORT, BR_PID };
struct report_file {
char *file_name;
if (list == NULL) {
if (as_json)
dprintf(fd, "{\"error\": \"Internal error.\"}");
+ else
+ dprintf(fd, "Internal error\n");
return false;
}
return NULL;
}
+static bool parse_pid_from_report_file(int report_fd, char *str)
+{
+ FILE *fp;
+ char buff[1024];
+ int pid = -1;
+
+ fp = fdopen(report_fd, "r");
+
+ while (fgets(buff, sizeof(buff), fp)) {
+ if (sscanf(buff, "PID = %d", &pid) == 1)
+ break;
+ }
+ if (pid < 0)
+ return false;
+
+ sprintf(str, "%d", pid);
+
+ return true;
+}
+
+static bool write_pid(int fd, int in_fd)
+{
+ char pid[10];
+
+ if (!parse_pid_from_report_file(in_fd, pid)) {
+ dprintf(fd, "Internal error\n");
+ return false;
+ }
+
+ if (write(fd, pid, strlen(pid)) < 0) {
+ dprintf(fd, "Internal error: %m\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool write_blank(int fd)
+{
+ if (write(fd, " ", 1) < 0) {
+ dprintf(fd, "Internal error: %m\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool write_pids(int fd, long time_from, long time_to)
+{
+ bool result = true;
+ size_t list_count = 0;
+ struct report_file *list = get_reports_from_range(time_from, time_to, &list_count);
+ if (list == NULL) {
+ dprintf(fd, "Internal error\n");
+ return false;
+ }
+
+ for (int i = 0; i < list_count; i++) {
+ int nfd = diagnostics_report_get_file(list[i].file_path, INFO_FILE);
+ if (nfd <= 0) {
+ _I("No INFO_FILE in %s file", list[i].file_path);
+ dprintf(nfd, "No INFO_FILE in %s\n", list[i].file_path);
+ continue;
+ }
+
+ if (!write_pid(fd, nfd)) {
+ _E("write_pid error");
+ close(nfd);
+ result = false;
+ break;
+ }
+
+ close(nfd);
+
+ if (!write_blank(fd)) {
+ _E("write_blank error");
+ result = false;
+ break;
+ }
+ }
+
+ for (int i = 0; i < list_count; i++)
+ free_record(&list[i]);
+ free(list);
+
+ return result;
+}
+
static bool write_single_file(int fd, enum BUGREPORT_REPORT_TYPE report_type, const char *ident)
{
assert(fd >= 0);
if (list == NULL) {
if (report_type == BR_CRASHINFO_JSON)
dprintf(fd, "{\"error\": \"Internal error.\"}");
+ else
+ dprintf(fd, "Internal error\n");
return false;
}
case BR_FULLREPORT:
report_entry = FULL_REPORT;
break;
+ case BR_PID:
+ report_entry = INFO_PID;
+ break;
default:
_E("Unsupported report type: %d", report_type);
result = false;
goto out;
}
- if (copy_bytes(fd, in_fd, NULL) == -1) {
+ if (report_entry == INFO_PID)
+ write_pid(fd, in_fd);
+ else if (copy_bytes(fd, in_fd, NULL) == -1) {
_E("Copy data error");
result = false;
goto out;
);
}
-static bool diagnostics_call_parse_options(int out_fd, char **params, int params_size, struct diagnostics_call_options *dco)
+static bool get_file_from_ctx(diagnostics_ctx_h ctx, char **report_file)
+{
+ assert(report_file);
+
+ if (ctx == NULL)
+ return false;
+
+ bool result = false;
+ char *event_name = NULL;
+ bundle *event_data = NULL;
+
+ int ret = diagnostics_get_event_name(ctx, &event_name);
+ if (ret != DIAGNOSTICS_ERROR_NONE) {
+ _E("Get event name error: %d", ret);
+ goto out;
+ }
+ if (strcmp(event_name, "BugreportCreated") != 0) {
+ _E("Unknown context: %s", event_name);
+ goto out;
+ }
+
+ ret = diagnostics_get_event_data(ctx, &event_data);
+ if (ret != DIAGNOSTICS_ERROR_NONE) {
+ _E("Get event data error: %d", ret);
+ goto out;
+ }
+
+ char *tmp_report_file;
+ ret = bundle_get_str(event_data, "report_file", &tmp_report_file);
+ if (ret != BUNDLE_ERROR_NONE) {
+ _E("Can not get report_file from event data: %d", ret);
+ goto out;
+ }
+
+ *report_file = strdup(tmp_report_file);
+ if (*report_file == NULL) {
+ _E("Out of memory: %m");
+ goto out;
+ }
+ _D("Report file from event data: %s", *report_file);
+
+ result = true;
+out:
+ if (event_name != NULL)
+ free(event_name);
+ if (event_data != NULL)
+ bundle_free(event_data);
+
+ return result;
+}
+
+static bool diagnostics_call_parse_options(int out_fd, char **params, int params_size, diagnostics_ctx_h ctx, struct diagnostics_call_options *dco)
{
struct timespec cur_time;
clock_gettime(CLOCK_REALTIME, &cur_time);
memcpy(&nparams[1], params, params_size*sizeof(char*));
nparams[0] = "n";
while ((opt = getopt_long_only(params_size+1, nparams, "", long_options, NULL)) != -1) {
- switch(opt) {
+ switch (opt) {
case PN_TYPE:
if (strcmp(optarg, "bugreport") == 0) {
dco->report_type = BR_BUGREPORT;
dco->report_type = BR_COREDUMP_TAR;
} else if (strcmp(optarg, "fullreport") == 0) {
dco->report_type = BR_FULLREPORT;
- } else {
+ } else if (strcmp(optarg, "pid") == 0) {
+ dco->report_type = BR_PID;
+ }else {
_E("Incorrect report type: %s", optarg);
dprintf(out_fd, "Incorrect report type: %s\n", optarg);
return false;
}
}
- if (optind < params_size+1)
- dco->arg = nparams[optind];
+ if (optind < params_size+1) {
+ dco->arg = strdup(nparams[optind]);
+ if (dco->arg == NULL) {
+ _E("Out of memory: %m");
+ return false;
+ }
+ } else {
+ get_file_from_ctx(ctx, &dco->arg);
+ }
return true;
}
}
struct diagnostics_call_options dco;
- if (!diagnostics_call_parse_options(fd, params, params_size, &dco))
+ if (!diagnostics_call_parse_options(fd, params, params_size, ctx, &dco))
return;
if ((dco.last_set && (dco.from_set || dco.to_set)) || (dco.to_set && !dco.from_set)) {
_E("Incorrect parameters set");
dprintf(fd, "Incorrect parameters set.\n");
- return;
+ goto out;
}
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;
+ goto out;
}
write_single_file(fd, dco.report_type, dco.arg);
- return;
+ goto out;
}
switch(dco.report_type) {
case BR_FULLREPORT:
dprintf(fd, "Report type \"fullreport\" requires a specific report with report_ident argument.\n");
break;
+ case BR_PID:
+ write_pids(fd, dco.from, dco.to);
+ break;
default:
_E("Unknown report type\n");
}
+out:
+ if (dco.arg != NULL)
+ free(dco.arg);
}
bool diagnostics_init()