Add PID information as a new type of bugreport
[platform/core/system/crash-worker.git] / src / bugreport-service / diagnostics / diagnostics_dump.c
index 9e5e32e..ff35141 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, 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;
@@ -228,6 +228,8 @@ static bool write_crash_info(int fd, long time_from, long time_to, bool as_json)
        if (list == NULL) {
                if (as_json)
                        dprintf(fd, "{\"error\": \"Internal error.\"}");
+               else
+                       dprintf(fd, "Internal error\n");
                return false;
        }
 
@@ -298,6 +300,94 @@ static struct report_file *find_report_file(const char *ident, struct report_fil
        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);
@@ -309,6 +399,8 @@ static bool write_single_file(int fd, enum BUGREPORT_REPORT_TYPE report_type, co
        if (list == NULL) {
                if (report_type == BR_CRASHINFO_JSON)
                        dprintf(fd, "{\"error\": \"Internal error.\"}");
+               else
+                       dprintf(fd, "Internal error\n");
                return false;
        }
 
@@ -335,6 +427,9 @@ static bool write_single_file(int fd, enum BUGREPORT_REPORT_TYPE report_type, co
        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;
@@ -348,7 +443,9 @@ static bool write_single_file(int fd, enum BUGREPORT_REPORT_TYPE report_type, co
                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;
@@ -381,7 +478,58 @@ static void diagnostics_print_help(int out_fd)
        );
 }
 
-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);
@@ -411,7 +559,7 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
        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;
@@ -423,7 +571,9 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
                                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;
@@ -451,8 +601,15 @@ static bool diagnostics_call_parse_options(int out_fd, char **params, int params
                }
        }
 
-       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;
 }
@@ -467,23 +624,23 @@ static void diagnostics_callback(diagnostics_data_h data, char **params, int par
        }
        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) {
@@ -502,9 +659,15 @@ static void diagnostics_callback(diagnostics_data_h data, char **params, int par
        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()