Fix svace issues
[platform/core/system/crash-worker.git] / src / crash-manager / crash-manager.c
1 /*
2  * crash-manager
3  *
4  * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <assert.h>
20 #include <ctype.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <gio/gio.h>
25 #include <iniparser.h>
26 #include <inttypes.h>
27 #include <libgen.h>
28 #include <limits.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/file.h>
33 #include <sys/mman.h>
34 #include <sys/prctl.h>
35 #include <sys/procfs.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 #include <sys/ptrace.h>
40 #include <sys/vfs.h>
41 #include <unistd.h>
42 #include <diagnostics.h>
43
44 #include <pkgmgr-info.h>
45 #include <tzplatform_config.h>
46
47 #undef LOG_TAG
48 #define LOG_TAG "CRASH_MANAGER"
49
50 #include "defs.h"
51 #include "shared/log.h"
52 #include "shared/config.h"
53 #include "shared/spawn.h"
54 #include "shared/util.h"
55 #include "so-info.h"
56 #include "crash-manager.h"
57
58 /* Parsing */
59 #define KEY_MAX              255
60
61 #define WAIT_FOR_OPT_TIMEOUT_SEC 60
62 #define SPACE_REQUIRED_KB        1024
63 #define HASH_LEN_MAX             0x100
64 #define HASH_SEP                 '='
65
66 #define MINICOREDUMPER_TIMEOUT_MS  DEFAULT_COMMAND_TIMEOUT_MS
67 #define LIVEDUMPER_TIMEOUT_MS      DEFAULT_COMMAND_TIMEOUT_MS
68 #define CRASH_STACK_TIMEOUT_MS     DEFAULT_COMMAND_TIMEOUT_MS
69 #define ZIP_TIMEOUT_MS             DEFAULT_COMMAND_TIMEOUT_MS
70
71 #define SYSTEM_REPORT_NAME   "system"
72
73 enum {
74         RET_EXCEED = 1,
75         NUM_EXCEED,
76         USAGE_EXCEED
77 };
78
79 struct file_info {
80         bool   isdir;
81         size_t size;
82         time_t mtime;
83         char   *path;
84 };
85
86 /* Configuration variables */
87 config_t config;
88 static char* crash_dump_path;
89 static char* crash_temp_path;
90
91 /* pkgmgrinfo filter list function for getting application ID */
92 static int appinfo_get_appid_func(pkgmgrinfo_appinfo_h handle,
93                 void *user_data)
94 {
95         char *str = NULL;
96
97         int ret = pkgmgrinfo_appinfo_get_appid(handle, &str);
98         if (ret == PMINFO_R_OK && str)
99                 (*(char **)user_data) = strdup(str);
100
101         return ret;
102 }
103
104 static bool get_appid(char *exepath, char **appid)
105 {
106         pkgmgrinfo_appinfo_filter_h handle = NULL;
107         bool have_appid = false;
108
109         if (pkgmgrinfo_appinfo_filter_create(&handle) != PMINFO_R_OK)
110                 return false;
111
112         if (pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_EXEC, exepath) != PMINFO_R_OK)
113                 goto out_free;
114
115         int count = 0;
116         if (pkgmgrinfo_appinfo_filter_count(handle, &count) || count < 1)
117                 goto out_free;
118
119         char *aid = NULL;
120         if (pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appinfo_get_appid_func, &aid) != PMINFO_R_OK)
121                 goto out_free;
122
123         have_appid = aid != NULL;
124         if (have_appid)
125                 *appid = strdup(aid);
126
127 out_free:
128         pkgmgrinfo_appinfo_filter_destroy(handle);
129         return have_appid && *appid != NULL;
130 }
131
132 static bool get_pkgid(char *appid, char **pkgid)
133 {
134         pkgmgrinfo_appinfo_h handle = NULL;
135
136         if (pkgmgrinfo_appinfo_get_appinfo(appid, &handle) != PMINFO_R_OK)
137                 return false;
138
139         bool have_pkgid = false;
140         char *p = NULL;
141         if (pkgmgrinfo_appinfo_get_pkgid(handle, &p) != PMINFO_R_OK)
142                 goto out_free;
143
144         have_pkgid = p != NULL;
145         if (have_pkgid)
146                 *pkgid = strdup(p);
147
148 out_free:
149         pkgmgrinfo_appinfo_destroy_appinfo(handle);
150         return have_pkgid && *pkgid != NULL;
151 }
152
153 static char *get_app_root_path(const char *pkgid)
154 {
155         char *root_path = NULL;
156         pkgmgrinfo_pkginfo_h handle;
157         int ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgid, &handle);
158         if (ret != PMINFO_R_OK)
159                 return NULL;
160
161         ret = pkgmgrinfo_pkginfo_get_root_path(handle, &root_path);
162         if (ret != PMINFO_R_OK) {
163                 _E("Unable to get app root path for %s", pkgid);
164                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
165                 return NULL;
166         }
167
168         char *path = root_path ? strdup(root_path) : NULL;
169         if (path == NULL && root_path != NULL)
170                 _E("Failed to get app root path for %s. strdup() error: %m", pkgid);
171
172         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
173
174         return path;
175 }
176
177 static bool set_appinfo(char *exepath, char **appid, char **pkgid)
178 {
179         char *a = NULL, *p = NULL;
180
181         if (get_appid(exepath, &a)) {
182                 *appid = a;
183                 *pkgid = get_pkgid(a, &p) ? p : strdup(a);
184                 return true;
185         }
186
187         char *bn = basename(exepath);
188         *appid = strdup(bn);
189         *pkgid = strdup(bn);
190         return false;
191 }
192
193 static int check_disk_available(const char *path, int check_size)
194 {
195         struct statfs lstatfs;
196
197         if (!path)
198                 return false;
199
200         if (statfs(path, &lstatfs) < 0) {
201                 _E("Error when checking free space (%d): %m", errno);
202                 return false;
203         }
204         int avail_size = (int)(lstatfs.f_bavail * (lstatfs.f_bsize / 1024));
205
206         if (check_size > avail_size) {
207                 _E("Available disk space (%d) is less than (%d)", avail_size, check_size);
208                 return false;
209         }
210
211         return true;
212 }
213
214 static int prepare_paths(struct crash_info* cinfo)
215 {
216         int tmp_len;
217         const char *crash_subdir = cinfo->livedump ? LIVE_PATH_SUBDIR : CRASH_PATH_SUBDIR;
218
219         if (cinfo->output_path) {
220                 free(config.crash_root_path);
221                 config.crash_root_path = strdup(cinfo->output_path);
222                 if (!config.crash_root_path) {
223                         _E("strdup() error: %m");
224                         return 0;
225                 }
226         }
227
228         tmp_len = strlen(config.crash_root_path) + strlen(crash_subdir);
229         crash_dump_path = (char*)malloc(tmp_len + 1);
230         if (crash_dump_path == NULL) {
231                 _E("Couldn't allocate memory for crash_dump_path: %m\n");
232                 return 0;
233         }
234         snprintf(crash_dump_path, tmp_len + 1, "%s%s", config.crash_root_path, crash_subdir);
235
236         tmp_len = strlen(config.crash_root_path) + strlen(CRASH_TEMP_SUBDIR);
237         crash_temp_path = (char*)malloc(tmp_len + 1);
238         if (crash_temp_path == NULL) {
239                 _E("Couldn't allocate memory for crash_temp_path: %m\n");
240                 return 0;
241         }
242         snprintf(crash_temp_path, tmp_len + 1, "%s%s", config.crash_root_path, CRASH_TEMP_SUBDIR);
243         return 1;
244 }
245
246 static bool make_dump_dir(void)
247 {
248         const char *dirs[] = {crash_dump_path, crash_temp_path};
249
250         for (size_t i = 0; i < ARRAY_SIZE(dirs); i++) {
251                 if (!make_dir(dirs[i], DEFAULT_CRASH_DIR_PERM))
252                         return false;
253         }
254
255         return true;
256 }
257
258 void get_proc_name(const char *cmd_line, char *buff, size_t buff_len)
259 {
260         assert(buff != NULL);
261         char *space = strchr(cmd_line, ' ');
262         size_t name_len;
263
264         if (space == NULL)
265                 name_len = strlen(cmd_line);
266         else
267                 name_len = space - cmd_line;
268
269         if (name_len > buff_len - 1)
270                 name_len = buff_len - 1;
271
272         // cmdline is valid only if it contains characters that can be used to
273         // to generate "valid" crash report name. Characters > 127 are rejected.
274         for (size_t z = 0; z < name_len; z++) {
275                 if (!isgraph(cmd_line[z])) {
276                         strncpy(buff, "nonascii_cmdline", buff_len);
277                         return;
278                 }
279         }
280
281         strncpy(buff, cmd_line, name_len);
282         buff[name_len] = '\0';
283 }
284
285 static bool get_cmd_info(struct crash_info *cinfo)
286 {
287         assert(cinfo);
288
289         if (cinfo->pid_info <= 0) {
290                 cinfo->cmd_line = strdup(SYSTEM_REPORT_NAME);
291                 cinfo->comm = strdup(SYSTEM_REPORT_NAME);
292                 if (cinfo->cmd_line == NULL || cinfo->comm == NULL) {
293                         _E("Couldn't allocate memory\n");
294                         return false;
295                 }
296                 return true;
297         }
298
299         char buf[PATH_MAX];
300         char proc_name[PATH_MAX];
301
302         if (!read_proc_file(cinfo->pid_info, "cmdline", buf, sizeof(buf), NULL))
303                 goto err;
304         get_proc_name(buf, proc_name, sizeof(proc_name));
305         cinfo->cmd_line = strdup(proc_name);
306         if (!cinfo->cmd_line)
307                 return false;
308
309         if (!read_proc_file(cinfo->tid_info, "comm", buf, sizeof(buf), filter_drop_trailing_whitespace))
310                 goto err;
311
312         cinfo->comm = strdup(buf);
313         if (!cinfo->comm)
314                 goto err;
315
316         if (!get_exe_path(cinfo->pid_info, buf, sizeof(buf)))
317                 goto err;
318
319         cinfo->cmd_path = strdup(buf);
320         if (!cinfo->cmd_path)
321                 goto err;
322
323         return true;
324
325 err:
326         free(cinfo->cmd_line);
327         cinfo->cmd_line = NULL;
328         free(cinfo->comm);
329         cinfo->comm = NULL;
330         return false;
331 }
332
333 static int set_prstatus(struct crash_info *cinfo)
334 {
335         int ret;
336         char prstatus_name[NAME_MAX+1];
337
338         ret = snprintf(prstatus_name, NAME_MAX, "/%d.prstatus", cinfo->pid_info);
339         if (ret < 0) {
340                 _E("Failed to snprintf for prstatus path");
341                 goto close_fd;
342         }
343
344         cinfo->prstatus_fd = shm_open(prstatus_name, O_RDWR | O_CREAT, 0600);
345         if (cinfo->prstatus_fd < 0) {
346                 _E("shm_open: %m");
347                 goto close_fd;
348         }
349
350         ret = shm_unlink(prstatus_name);
351         if (ret < 0) {
352                 _E("shm_unlink: %m");
353                 goto close_fd;
354         }
355
356         ret = fcntl(cinfo->prstatus_fd, F_GETFD);
357         if (ret < 0) {
358                 _E("fcntl(): %m");
359                 goto close_fd;
360         }
361
362         ret = fcntl(cinfo->prstatus_fd, F_SETFD, ret & ~FD_CLOEXEC);
363         if (ret < 0) {
364                 _E("fcntl(): %m");
365                 goto close_fd;
366         }
367
368         ret = ftruncate(cinfo->prstatus_fd, sizeof(struct elf_prstatus));
369         if (ret < 0) {
370                 _E("ftruncate(): %m");
371                 goto close_fd;
372         }
373
374         return 0;
375
376 close_fd:
377         if (cinfo->prstatus_fd >= 0)
378                 close(cinfo->prstatus_fd);
379         return -1;
380 }
381
382 static void set_crash_info_defaults(struct crash_info *cinfo)
383 {
384         if (cinfo->livedump) {
385                 cinfo->sig_info = cinfo->kill ? SIGKILL : 0;
386         } else if (cinfo->tid_info == -1)
387                 cinfo->tid_info = find_crash_tid(cinfo->pid_info);
388
389         if (cinfo->tid_info == -1) {
390                 _W("TID not known. Assuming TID = PID (%d).", cinfo->pid_info);
391                 cinfo->tid_info = cinfo->pid_info;
392         }
393 }
394
395 static int dump_filter(const struct dirent *de)
396 {
397         assert(de);
398
399         if (de->d_name[0] == '.')
400                 return 0;
401         return 1;
402 }
403
404 /* We treat all errors as if the file was locked. This function is used to check
405  * if we can remove the temporary directory. We don't want to remove that
406  * directory if an error has occurred, because the deletion will probably also
407  * fail */
408 static bool is_locked(const char *dir_name)
409 {
410         assert(dir_name);
411
412         char lock_file[PATH_MAX];
413         if (snprintf(lock_file, sizeof(lock_file), "%s", dir_name) == -1) {
414                 _E("Unable to check locking status for %s: %m", dir_name);
415                 return true;
416         }
417
418         int fd = open(lock_file, O_RDONLY | O_DIRECTORY);
419         if (fd == -1) {
420                 _E("Unable to open file %s to check if it's blocked: %m", lock_file);
421                 return true;
422         }
423
424         bool result = flock(fd, LOCK_EX | LOCK_NB) == -1;
425
426         close(fd);
427         return result;
428 }
429
430 static bool clean_temp(const char *temp_dir)
431 {
432         bool result = true;
433         assert(temp_dir);
434
435         struct dirent **scan_list = NULL;
436         int scan_num;
437
438         if ((scan_num = scandir(temp_dir, &scan_list, &dump_filter, NULL)) < 0)
439                 return false;
440
441         for (int i = 0; i < scan_num; i++) {
442                 char dir_name[PATH_MAX];
443
444                 if (snprintf(dir_name, sizeof(dir_name), "%s/%s", temp_dir, scan_list[i]->d_name) == -1) {
445                         _E("Unable to clean temp for %s: %m", dir_name);
446                         result = false;
447                         continue;
448                 }
449
450                 if (is_locked(dir_name))
451                         _D("Temporary directory %s is locked", dir_name);
452                 else if (!remove_dir(dir_name, true))
453                         _W("Can not remove temporary directory: %s", dir_name);
454                 else
455                         _D("Temporary directory %s removed", dir_name);
456         }
457
458         return result;
459 }
460
461 /* Note: caller of this function is responsible for cleaning up the cinfo on failure */
462 bool set_crash_info(struct crash_info *cinfo)
463 {
464         bool system_dump = cinfo->pid_info <= 0;
465         bool zip_report = system_dump || config.allow_zip;
466
467         set_crash_info_defaults(cinfo);
468
469         if (!get_cmd_info(cinfo)) {
470                 _E("Failed to get command info");
471                 return false;
472         }
473
474         char date[16];
475         struct tm loc_tm;
476         cinfo->time_info = time(NULL);
477         localtime_r(&cinfo->time_info, &loc_tm);
478         strftime(date, sizeof(date), "%Y%m%d%H%M%S", &loc_tm);
479
480         if (asprintf(&cinfo->temp_dir, "%s/crash.XXXXXX", crash_temp_path) == -1)
481                 goto out_oom;
482
483         if (mkdtemp(cinfo->temp_dir) == NULL || access(cinfo->temp_dir, F_OK)) {
484                 _E("Failed to create temporary directory %s: %m", cinfo->temp_dir);
485                 return false;
486         }
487
488         const char *suffix = (system_dump || config.report_type >= REP_TYPE_FULL) ? (zip_report ? ".zip" : "") : ".info";
489         bool is_app = set_appinfo(cinfo->cmd_line, &cinfo->appid, &cinfo->pkgid);
490         if (!cinfo->appid || !cinfo->pkgid)
491                 goto out_oom;
492
493         if (-1 == asprintf(&cinfo->name,        "%s_%d_%s",        is_app ? cinfo->pkgid : basename(cinfo->cmd_line), cinfo->pid_info, date)
494          || -1 == asprintf(&cinfo->pfx,         "%s/%s",           cinfo->temp_dir, cinfo->name)
495          || -1 == asprintf(&cinfo->info_path,   "%s/%s.info",      cinfo->pfx, cinfo->name)
496          || -1 == asprintf(&cinfo->info_json,   "%s/%s.info.json", cinfo->pfx, cinfo->name)
497          || -1 == asprintf(&cinfo->core_path,   "%s/%s.coredump",  cinfo->pfx, cinfo->name)
498          || -1 == asprintf(&cinfo->log_path,    "%s/%s.log",       cinfo->pfx, cinfo->name)
499          || -1 == asprintf(&cinfo->zip_path,    "%s/report.zip",   cinfo->temp_dir)
500          || -1 == asprintf(&cinfo->result_path, "%s/%s%s",         crash_dump_path, cinfo->name, suffix))
501                 goto out_oom;
502
503         if (is_app)
504                 cinfo->app_root_path = get_app_root_path(cinfo->pkgid);
505
506         if (mkdir(cinfo->pfx, 0775) < 0) {
507                 _E("Failed to mkdir %s: %m", cinfo->pfx);
508                 goto out_rm_temp;
509         }
510
511         if (set_prstatus(cinfo) < 0)
512                 goto out_rm_temp;
513
514         return true;
515
516 out_rm_temp:
517         unlock_dir(cinfo->lock_fd);
518         remove_dir(cinfo->temp_dir, true);
519         clean_temp(crash_temp_path);
520         return false;
521
522 out_oom:
523         _E("Out of memory");
524         return false;
525 }
526
527 static void launch_crash_popup(struct crash_info *cinfo)
528 {
529         assert(cinfo);
530
531         char *av[] = { CRASH_POPUP_BIN_PATH,
532                         "--cmdline", cinfo->cmd_line,
533                         "--cmdpath", cinfo->cmd_path,
534                         NULL };
535
536         spawn_param_s param = { .fn = spawn_nullstdfds };
537         spawn(av, NULL, &param, NULL, NULL);
538 }
539
540 static bool dump_system_state(const struct crash_info *cinfo, pid_t *pid)
541 {
542         char *av[] = {DUMP_SYSTEMSTATE_BIN_PATH, "-d", "-k", "-j", "-p", "-e", "-f", cinfo->log_path, "-b", NULL};
543         spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
544         return spawn(av, NULL, &param, pid, NULL);
545 }
546
547 static void save_so_info(const struct crash_info *cinfo)
548 {
549         char maps_path[PATH_MAX];
550         char so_info_path[PATH_MAX];
551         snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps",
552                  cinfo->pid_info);
553
554         snprintf(so_info_path, sizeof(so_info_path),
555                          "%s/%s.%s", cinfo->pfx, cinfo->name, "so_info");
556
557         get_and_save_so_info(maps_path, so_info_path);
558 }
559
560 /* remove a file whose name begins with 'beggining_of_name'. This is needed
561  * when we don't want to include coredump in report, but we only know the
562  * beginning of the coredump file name. */
563 static bool remove_file_in_dir(const char *directory, const char *beginning_of_name)
564 {
565         bool ret = false;
566         int errno_unlink = 0;
567
568         DIR *dir = opendir(directory);
569         if (dir == NULL)
570                 goto end;
571
572         int dir_fd = dirfd(dir);
573         if (dir_fd == -1) {
574                 closedir(dir);
575                 goto end;
576         }
577
578         struct dirent* file_info;
579         while ((file_info = readdir(dir)) != NULL) {
580                 if (strstr(file_info->d_name, beginning_of_name) == file_info->d_name) {
581                         ret = unlinkat(dir_fd, file_info->d_name, 0) != -1;
582                         errno_unlink = errno;
583                         break;
584                 }
585         }
586         closedir(dir);
587         errno = errno_unlink; /* for %m */
588 end:
589         return ret;
590 }
591
592 // These macros are used in functions below
593 #define SNPRINTF_OR_EXIT_W(name, format, member) do { if (snprintf(name##_str, sizeof(name##_str), format, cinfo->member) < 0) goto out; } while (0)
594 #define SNPRINTF_OR_EXIT(name, format) SNPRINTF_OR_EXIT_W(name, format, name##_info)
595
596 static bool extra_script(const struct crash_info *cinfo, pid_t *pid)
597 {
598         if (!config.extra_script || access(config.extra_script, X_OK))
599                 return false;
600
601         char pid_str[11];
602         SNPRINTF_OR_EXIT(pid, "%d");
603
604         char *av[] = { config.extra_script, cinfo->pfx, pid_str, NULL };
605         spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
606         return spawn(av, NULL, &param, pid, NULL);
607
608 out:
609         return false;
610 }
611
612 static void launch_dbus_notify(struct crash_info *cinfo)
613 {
614         assert(cinfo);
615
616         char pid_str[11], tid_str[11], sig_str[11];
617         char *prstatus_fd_str = NULL;
618
619         if (asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
620                 _E("Unable to allocate memory: %m");
621                 return;
622         }
623
624         SNPRINTF_OR_EXIT(pid, "%d");
625         SNPRINTF_OR_EXIT(tid, "%d");
626         SNPRINTF_OR_EXIT(sig, "%d");
627
628         char *legacy_notification_str = config.legacy_notification ? "--legacy-sig" : "";
629
630         char *av[] = { CRASH_NOTIFY_BIN_PATH,
631                         "--cmdline", cinfo->cmd_line,
632                         "--cmdpath", cinfo->cmd_path,
633                         "--pid", pid_str,
634                         "--tid", tid_str,
635                         "--appid", cinfo->appid,
636                         "--pkgid", cinfo->pkgid,
637                         "--reportpath", cinfo->result_path,
638                         "--prstatus_fd", prstatus_fd_str,
639                         "--signal", sig_str,
640                         "--tid-comm", cinfo->comm,
641                         "--hash_native", cinfo->call_stack_hash ?: "none",
642                         legacy_notification_str,
643                         NULL };
644
645         spawn(av, NULL, NULL, NULL, NULL);
646 out:
647         free(prstatus_fd_str);
648 }
649
650 static bool execute_minicoredump(struct crash_info *cinfo, int *exit_code)
651 {
652         char *coredump_name = NULL;
653         char *prstatus_fd_str = NULL;
654         bool is_ok = false;
655
656         if (asprintf(&coredump_name, "%s.coredump", cinfo->name) == -1
657             || asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
658                 _E("Unable to allocate memory");
659                 goto out;
660         }
661
662         char pid_str[11], uid_str[11], gid_str[11], sig_str[11], time_str[11];
663
664         SNPRINTF_OR_EXIT(pid, "%d");
665         SNPRINTF_OR_EXIT(uid, "%d");
666         SNPRINTF_OR_EXIT(gid, "%d");
667         SNPRINTF_OR_EXIT(sig, "%d");
668         SNPRINTF_OR_EXIT(time, "%ld");
669
670         const char *without_core_str = config.dump_core ? NULL : "-s";
671
672         /* Execute minicoredumper */
673         char *args[] = {
674                         MINICOREDUMPER_BIN_PATH,   // minicoredumper filename path
675                         pid_str,                   // %p - pid
676                         uid_str,                   // %u - UID
677                         gid_str,                   // %g - GID
678                         sig_str,                   // %s - number of signal
679                         time_str,                  // %t - time of dump
680                         "localhost",               // %h - hostname
681                         basename(cinfo->cmd_line), // %e - exe name (need for result filename)
682                         MINICOREDUMPER_CONFIG_PATH, // config file
683                         "-d",
684                         cinfo->pfx,            // temp dir
685                         "-o",
686                         coredump_name,             // coredump filename
687                         "-P",
688                         prstatus_fd_str,
689                         (char *)without_core_str,  // with or without core
690                         NULL
691                         };
692
693         spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
694         is_ok = spawn_wait(args, NULL, &param, MINICOREDUMPER_TIMEOUT_MS, exit_code);
695
696         /* Minicoredumper must be executed to dump at least PRSTATUS for
697            other tools, coredump, however, might have been disabled. */
698         if (!config.dump_core && file_exists_in_dir(cinfo->pfx, coredump_name)) {
699                 _E("Saving core disabled but coredump found (minicoredumper bug?). Removing coredump %s/%s", cinfo->pfx, coredump_name);
700                 if (!remove_file_in_dir(cinfo->pfx, coredump_name))
701                         _E("Removing coredump %s/%s failed: %m", cinfo->pfx, coredump_name);
702         }
703
704 out:
705         free(coredump_name);
706         free(prstatus_fd_str);
707
708         return is_ok;
709 }
710
711 static bool execute_livedumper(const struct crash_info *cinfo, int *exit_code)
712 {
713         char *coredump_path = NULL;
714         char *prstatus_fd_str = NULL;
715         bool is_ok = false;
716         char pid_str[11];
717
718         if (asprintf(&coredump_path, "%s/%s.coredump", cinfo->pfx, cinfo->name) == -1 ||
719             asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
720                 _E("Unable to allocate memory");
721                 goto out;
722         }
723
724         SNPRINTF_OR_EXIT(pid, "%d");
725
726         /* Execute livedumper */
727         char *args[] = {
728                         LIVEDUMPER_BIN_PATH,    // livedumper filename path
729                         "-m",                   // minilivecoredump
730                         "-P", prstatus_fd_str,
731                         "-f", coredump_path,
732                         pid_str,                // %p - pid
733                         NULL
734                         };
735
736         spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
737         is_ok = spawn_wait(args, NULL, &param, LIVEDUMPER_TIMEOUT_MS, exit_code);
738 out:
739         free(prstatus_fd_str);
740         free(coredump_path);
741         return is_ok;
742 }
743
744 static bool execute_crash_stack(struct crash_info *cinfo, int *exit_code)
745 {
746         char pid_str[11], tid_str[11], sig_str[11], prstatus_fd_str[11];
747         bool is_ok = false;
748
749         SNPRINTF_OR_EXIT(pid, "%d");
750         SNPRINTF_OR_EXIT(tid, "%d");
751         SNPRINTF_OR_EXIT(sig, "%d");
752         SNPRINTF_OR_EXIT_W(prstatus_fd, "%d", prstatus_fd);
753
754         /* Execute crash-stack */
755         char *args[] = { CRASH_STACK_BIN_PATH,
756                          "--pid", pid_str,
757                          "--tid", tid_str,
758                          "--sig", sig_str,
759                          "--output", cinfo->info_path,
760                          "--output-json", cinfo->info_json,
761                          "--prstatus_fd", prstatus_fd_str,
762                          NULL };
763
764         int p[2];
765         if (pipe2(p, O_NONBLOCK) < 0) {
766                 _E("Cannot create a pipe (%d): %m", errno);
767                 return false;
768         }
769
770         spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = p[1] };
771         is_ok = spawn_wait(args, NULL, &param, CRASH_STACK_TIMEOUT_MS, exit_code);
772
773         char hash[HASH_LEN_MAX];
774         if (read(p[0], hash, sizeof(hash)) == -1)
775                 _E("Read hash error: %m");
776         else
777                 _D("Call stack hash: %s", hash);
778
779         hash[HASH_LEN_MAX-1] = '\0';
780         close(p[0]);
781         close(p[1]);
782
783         char *separator = strchr(hash, HASH_SEP);
784         char *endofline = strchr(hash, '\n');
785         if (separator == NULL || endofline == NULL || endofline < (separator + 1) || endofline < 0 || separator < 0) {
786                 _E("Unsuspected hash format");
787                 goto out;
788         }
789
790         cinfo->call_stack_hash = strndup(separator + 1, endofline - (separator + 1));
791         if (cinfo->call_stack_hash == NULL)
792                 _E("Saving the hash failed: %m");
793
794 out:
795         return is_ok;
796 }
797
798 #undef SNPRINTF_OR_EXIT
799 #undef SNPRINTF_OR_EXIT_W
800
801 static bool kill_pid(const pid_t pid, int sig, bool wait)
802 {
803         if (kill(pid, sig) == -1) {
804                 _E("kill sig %d error: %m\n", sig);
805                 return false;
806         }
807
808         if (wait) {
809                 if (waitpid(pid, NULL, 0) == -1) {
810                         _E("waitpid error: %m");
811                         return false;
812                 }
813         }
814         return true;
815 }
816
817 static bool process_stop(const pid_t pid)
818 {
819         _D("stop process %d", pid);
820         return kill_pid(pid, SIGSTOP, false);
821 }
822
823 static bool process_continue(const pid_t pid)
824 {
825         _D("continue process %d", pid);
826         return kill_pid(pid, SIGCONT, false);
827 }
828
829 static bool copy_application_data(struct crash_info *cinfo, const char *filename)
830 {
831         bool is_ok = false;
832         char *src_filepath = NULL;
833         char *dst_filepath = NULL;
834         char *dst_dirpath = NULL;
835
836         if (cinfo->app_root_path &&
837                 (asprintf(&src_filepath, "%s/%s", cinfo->app_root_path, filename) == -1
838                 || asprintf(&dst_filepath, "%s%s%s", cinfo->pfx, APP_PATH_SUBDIR, filename) == -1)) {
839                 _E("Failed to asprintf for %s file in %s path", filename,
840                                 !src_filepath ? cinfo->app_root_path : cinfo->pfx);
841                 goto out;
842         }
843
844         if (!src_filepath || access(src_filepath, F_OK))
845                 goto out;
846
847         dst_dirpath = strdup(dst_filepath);
848         char *dst_dirname = dirname(dst_dirpath);
849         if (dst_dirpath == NULL || dst_dirname == NULL) {
850                 _E("Out of memory");
851                 goto out;
852         }
853
854         if (mkdir(dst_dirname, 0775) < 0 && errno != EEXIST) {
855                 _E("Failed to mkdir %s: %m", dst_dirname);
856                 (void)check_disk_available(cinfo->pfx, SPACE_REQUIRED_KB);
857                 goto out;
858         }
859
860         if (copy_file(dst_filepath, src_filepath)) {
861                 _E("Cannot copy %s file to: %s", src_filepath, dst_filepath);
862                 (void)check_disk_available(cinfo->app_root_path, SPACE_REQUIRED_KB);
863         }
864         else
865                 is_ok = true;
866 out:
867         free(src_filepath);
868         free(dst_filepath);
869         free(dst_dirpath);
870
871         return is_ok;
872 }
873
874 static void copy_application_xmls(struct crash_info *cinfo)
875 {
876         const char * const app_config_paths[] = {
877                         tzplatform_getenv(TZ_SYS_RW_PACKAGES),
878                         tzplatform_getenv(TZ_SYS_RO_PACKAGES)
879         };
880         char *src_filepath = NULL;
881         char *dst_filepath = NULL;
882         char *dst_dirpath = NULL;
883         char maps_path[PATH_MAX] = {'\0'};
884
885         if (asprintf(&dst_dirpath, "%s%s", cinfo->pfx, APP_PATH_SUBDIR) == -1) {
886                 _E("Failed to asprintf for dst dir: %s%s", cinfo->pfx, APP_PATH_SUBDIR);
887                 return;
888         }
889         if (mkdir(dst_dirpath, 0775) < 0 && errno != EEXIST) {
890                 _E("Failed to mkdir %s (%m)", dst_dirpath);
891                 (void)check_disk_available(cinfo->pfx, SPACE_REQUIRED_KB);
892                 goto out;
893         }
894         if (snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps", cinfo->pid_info) <= 0) {
895                 _E("Failed to snprintf maps path: /proc/%d/maps", cinfo->pid_info);
896                 goto out;
897         }
898
899         GHashTable *app_names = get_app_name_from_map(maps_path);
900         GHashTableIter iter;
901         gpointer key;
902         g_hash_table_iter_init(&iter, app_names);
903         while (g_hash_table_iter_next(&iter, &key, NULL)) {
904                 char *app_name = (char *)key;
905
906                 if (asprintf(&dst_filepath, "%s%s.xml", dst_dirpath, app_name) == -1) {
907                         _E("Failed to asprintf dst file path: %s%s%s.xml",
908                            cinfo->pfx, APP_PATH_SUBDIR, app_name);
909                 } else {
910                         for (size_t i = 0; i < ARRAY_SIZE(app_config_paths); ++i) {
911                                 if (asprintf(&src_filepath, "%s/%s%s", app_config_paths[i], app_name, ".xml") == -1) {
912                                         _E("Failed to asprintf source file path: %s", src_filepath);
913                                         continue;
914                                 }
915                                 if (file_exists(src_filepath)) {
916                                         if (file_exists(dst_filepath)) {
917                                                 _W("File %s.xml already exists in report.", app_name);
918                                         } else {
919                                                 if (copy_file(dst_filepath, src_filepath)) {
920                                                         _E("Cannot copy file from %s to: %s", src_filepath, dst_filepath);
921                                                         (void)check_disk_available(dst_dirpath, SPACE_REQUIRED_KB);
922                                                 }
923                                         }
924                                 }
925                                 free(src_filepath);
926                         }
927                         free(dst_filepath);
928                 }
929                 free(app_name);
930         }
931         g_hash_table_unref(app_names);
932 out:
933         free(dst_dirpath);
934 }
935
936 static bool execute_crash_modules(struct crash_info *cinfo)
937 {
938         int exit_code = 0;
939         if (cinfo->livedump) {
940                 _I("Starting the livedumper");
941                 if (!process_stop(cinfo->pid_info))
942                         return false;
943                 if (!execute_livedumper(cinfo, &exit_code) || exit_code != 0) {
944                         _E("Failed to run livedumper - can not continue");
945                         (void)check_disk_available(cinfo->pfx, SPACE_REQUIRED_KB);
946                         process_continue(cinfo->pid_info);
947                         return false;
948                 }
949         } else {
950                 _I("Starting the minicoredumper");
951                 if (!execute_minicoredump(cinfo, &exit_code) || exit_code != 0) {
952                         _E("Failed to run minicoredumper - can not continue");
953                         (void)check_disk_available(cinfo->pfx, SPACE_REQUIRED_KB);
954                         return false;
955                 }
956         }
957
958         execute_crash_stack(cinfo, NULL);
959         (void)copy_application_data(cinfo, "tizen-manifest.xml"); // manifest is optional because only tizen applications have it
960         copy_application_xmls(cinfo);
961         if (cinfo->livedump)
962                 process_continue(cinfo->pid_info);
963
964         return true;
965 }
966
967 static int mtime_cmp(const void *_a, const void *_b)
968 {
969         const struct file_info *a = _a;
970         const struct file_info *b = _b;
971
972         if (a->mtime < b->mtime)
973                 return -1;
974         if (a->mtime > b->mtime)
975                 return 1;
976         return 0;
977 }
978
979 static int scan_dump(struct file_info **dump_list, off_t *usage)
980 {
981         struct file_info *temp_list;
982         struct dirent **scan_list = NULL;
983         struct stat st;
984         int i, scan_num, dump_num = 0;
985         int fd;
986
987         if ((fd = open(crash_dump_path, O_DIRECTORY)) < 0) {
988                 _E("Failed to open %s: %m", crash_dump_path);
989                 return -1;
990         }
991
992         scan_num = scandir(crash_dump_path, &scan_list, &dump_filter, NULL);
993         if (scan_num < 0) {
994                 close(fd);
995                 return -1;
996         }
997
998         temp_list = (struct file_info *)calloc(scan_num,
999                         sizeof(struct file_info));
1000         if (!temp_list) {
1001                 _E("Failed to calloc for dump list");
1002                 goto exit;
1003         }
1004
1005         for (i = 0; i < scan_num; i++) {
1006                 if (fstatat(fd, scan_list[i]->d_name, &st, 0) < 0) {
1007                         _E("Failed to fstatat");
1008                         continue;
1009                 }
1010
1011                 if (asprintf(&(temp_list[dump_num].path), "%s/%s",
1012                                         crash_dump_path, scan_list[i]->d_name) < 0) {
1013                         _E("Failed to asprintf");
1014                         continue;
1015                 }
1016
1017                 if (scan_list[i]->d_type == DT_DIR) {
1018                         temp_list[dump_num].isdir = 1;
1019                         temp_list[dump_num].size =
1020                                 get_directory_usage(temp_list[dump_num].path);
1021                 } else {
1022                         temp_list[dump_num].isdir = 0;
1023                         temp_list[dump_num].size = st.st_size;
1024                 }
1025                 temp_list[dump_num].mtime = st.st_mtime;
1026                 dump_num++;
1027         }
1028
1029         if (dump_num <= 0) {
1030                 free(temp_list);
1031                 goto exit;
1032         }
1033
1034         if (dump_num != scan_num) {
1035                 struct file_info *const tmp = (struct file_info *)realloc(temp_list,
1036                                 dump_num * sizeof(struct file_info));
1037                 if (!tmp) {
1038                         free(temp_list);
1039                         dump_num = -1;
1040                         goto exit;
1041                 }
1042                 temp_list = tmp;
1043         }
1044
1045         qsort(temp_list, dump_num, sizeof(struct file_info), mtime_cmp);
1046
1047         *usage = 0;
1048         for (i = 0; i < dump_num; i++) {
1049                 _D("[%d] path: %s(%s), size: %zu kb, mtime: %s",
1050                                 i,
1051                                 temp_list[i].path,
1052                                 temp_list[i].isdir ? "DIR" : "FILE",
1053                                 temp_list[i].size / 1024,
1054                                 ctime(&(temp_list[i].mtime)));
1055                 *usage += temp_list[i].size;
1056         }
1057         *dump_list = temp_list;
1058 exit:
1059         for (i = 0; i < scan_num; i++)
1060                 free(scan_list[i]);
1061         free(scan_list);
1062         close(fd);
1063
1064         return dump_num;
1065 }
1066
1067 static bool remove_file_info(struct file_info file)
1068 {
1069         if (file.isdir)
1070                 return remove_dir(file.path, true);
1071         else
1072                 return unlink(file.path) != -1;
1073 }
1074
1075 static void clean_dump(void)
1076 {
1077         struct file_info *dump_list = NULL;
1078         int i, scan_num, dump_num, remove_flag;
1079         off_t usage = 0;
1080         time_t cur_time;
1081
1082         scan_num = scan_dump(&dump_list, &usage);
1083         if (scan_num <= 0)
1084                 return;
1085
1086         dump_num = scan_num;
1087
1088         cur_time = time(NULL);
1089
1090         for (i = 0; i < scan_num; i++) {
1091                 remove_flag = 0;
1092
1093                 /* Retention time check */
1094                 if (config.max_retention_sec &&
1095                         dump_list[i].mtime > 0 &&
1096                         dump_list[i].mtime + config.max_retention_sec < cur_time)
1097                         remove_flag = RET_EXCEED;
1098                 /* Check the number of dumps */
1099                 else if (config.max_crash_dump &&
1100                         0 < dump_num && config.max_crash_dump < dump_num)
1101                         remove_flag = NUM_EXCEED;
1102                 /* Check the max system use size */
1103                 else if (config.system_max_use &&
1104                         0 < dump_num && config.system_max_use < usage / 1024)
1105                         remove_flag = USAGE_EXCEED;
1106
1107                 switch (remove_flag) {
1108                 case RET_EXCEED:
1109                         _I("Reached the maximum retention time %d, so remove (%s)",
1110                                         config.max_retention_sec, dump_list[i].path);
1111                         break;
1112                 case NUM_EXCEED:
1113                         _I("Reached the maximum number of dump %d/%d, so remove (%s)",
1114                                         dump_num, config.max_crash_dump,
1115                                         dump_list[i].path);
1116                         break;
1117                 case USAGE_EXCEED:
1118                         _I("Reached the maximum disk usage %" PRId64 "/%d kb, so remove (%s)",
1119                                         usage / 1024, config.system_max_use,
1120                                         dump_list[i].path);
1121                         break;
1122                 default:
1123                         break;
1124                 }
1125
1126                 if (!remove_flag)
1127                         continue;
1128
1129                 if (!remove_file_info(dump_list[i])) {
1130                         _E("Failed to remove %s", dump_list[i].path);
1131                         continue;
1132                 }
1133                 dump_num--;
1134                 usage -= dump_list[i].size;
1135         }
1136
1137         /* Check disk free space to keep */
1138         if (config.system_keep_free &&
1139                         !check_disk_available(config.crash_root_path,
1140                                              config.system_keep_free)) {
1141                 _I("Disk is not available! so set the maximum number of dump to 1");
1142                 config.max_crash_dump = 1;
1143         }
1144
1145         for (i = 0; i < dump_num; i++)
1146                 free(dump_list[i].path);
1147         free(dump_list);
1148 }
1149
1150 static void compress(struct crash_info *cinfo)
1151 {
1152         char *args[] = {"/bin/zip", "-qyr", cinfo->zip_path, cinfo->name, NULL};
1153         spawn_param_s param1 = { .fn = spawn_nullstdfds };
1154         spawn_param_s param0 = { .fn = spawn_chdir, .u.char_ptr = cinfo->temp_dir, .next = &param1 };
1155         (void)spawn_wait(args, NULL, &param0, ZIP_TIMEOUT_MS, NULL);
1156 }
1157
1158 static bool move_dump_data(const char *from_path, const struct crash_info *cinfo)
1159 {
1160         int lock_fd;
1161         bool is_ok = true;
1162
1163         if ((lock_fd = lock_dir(crash_dump_path, false)) < 0)
1164                 return false;
1165         if (!rename(from_path, cinfo->result_path)) {
1166                 if (chmod(cinfo->result_path, DEFAULT_REPORT_PERM) != 0)
1167                         _E("Error changing permission for %s to %d: %m", cinfo->result_path, DEFAULT_REPORT_PERM);
1168                 clean_dump();
1169         } else {
1170                 _E("Failed to move %s to %s", from_path, cinfo->result_path);
1171                 (void)check_disk_available(crash_dump_path, SPACE_REQUIRED_KB);
1172                 is_ok = false;
1173         }
1174         unlock_dir(lock_fd);
1175
1176         return is_ok;
1177 }
1178
1179 static int wait_for_opt(unsigned int timeout)
1180 {
1181         unsigned int count = 0;
1182
1183         while (!check_disk_available(config.crash_root_path, 0) && count < timeout) {
1184                 log_kmsg("crash-manager: path %s is not available\n", config.crash_root_path);
1185                 sleep(1);
1186                 count++;
1187         }
1188         if (count >= timeout) {
1189                 log_kmsg("crash-manager: timeout (%ds) while waiting for %s."
1190                         "Probably /opt is not mounted.\n", timeout, config.crash_root_path);
1191                 return 0;
1192         }
1193
1194         return 1;
1195 }
1196
1197 EXPORT void free_crash_info(struct crash_info *cinfo)
1198 {
1199         free(cinfo->cmd_line);
1200         free(cinfo->cmd_path);
1201         free(cinfo->comm);
1202         free(cinfo->temp_dir);
1203         free(cinfo->name);
1204         free(cinfo->result_path);
1205         free(cinfo->app_root_path);
1206         free(cinfo->pfx);
1207         free(cinfo->info_path);
1208         free(cinfo->info_json);
1209         free(cinfo->core_path);
1210         free(cinfo->log_path);
1211         free(cinfo->zip_path);
1212         free(cinfo->appid);
1213         free(cinfo->pkgid);
1214         free(cinfo->executable_path);
1215         free(cinfo->call_stack_hash);
1216 }
1217
1218 EXPORT void crash_info_init(struct crash_info *cinfo)
1219 {
1220         cinfo->prstatus_fd = -1;
1221         cinfo->livedump = false;
1222         cinfo->kill = false;
1223         cinfo->print_result_path = false;
1224         cinfo->tid_info = -1;
1225         cinfo->time_info = 0;
1226         cinfo->output_path = NULL;
1227         cinfo->executable_path = NULL;
1228         cinfo->cmd_line = NULL;
1229         cinfo->cmd_path = NULL;
1230         cinfo->comm = NULL;
1231         cinfo->temp_dir = NULL;
1232         cinfo->name = NULL;
1233         cinfo->app_root_path = NULL;
1234         cinfo->pfx = NULL;
1235         cinfo->result_path = NULL;
1236         cinfo->info_path = NULL;
1237         cinfo->info_json = NULL;
1238         cinfo->core_path = NULL;
1239         cinfo->log_path = NULL;
1240         cinfo->zip_path = NULL;
1241         cinfo->appid = NULL;
1242         cinfo->pkgid = NULL;
1243         cinfo->lock_fd = -1;
1244         cinfo->call_stack_hash = NULL;
1245 }
1246
1247 static void release_crashed_process()
1248 {
1249         /* Release the core pipe as passed by kernel, allowing another
1250          * coredump to be handled.
1251          *
1252          * Due to usage of core_pipe_limit there is limited number of
1253          * crash-manager processes that kernel is going to invoke
1254          * concurrently.  As the next and last step is a _synchronous_
1255          * call to crash-popup we close the descriptor here.
1256          *
1257          * Note: for VIP processes this will likely cause the system
1258          * to reboot without showing popup.
1259          */
1260         close(STDIN_FILENO);
1261         _I("Released crashed process lock");
1262 }
1263
1264 static bool run(struct crash_info *cinfo)
1265 {
1266         /* Special PID ( <= 0) for which the report will contain only
1267          * dump_systemstate output
1268          */
1269         bool system_dump = cinfo->pid_info <= 0;
1270         bool zip_report = system_dump || config.allow_zip;
1271
1272         /* Execute processes in parallel */
1273         static pid_t dump_state_pid = 0, extra_script_pid = 0;
1274         int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0;
1275
1276         if (system_dump || config.report_type >= REP_TYPE_FULL) {
1277                 /* Exec dump_systemstate */
1278                 if (!dump_system_state(cinfo, &dump_state_pid)) {
1279                         _E("Failed to get system state report");
1280                         return false;
1281                 }
1282
1283                 if (config.extra_script && !extra_script(cinfo, &extra_script_pid))
1284                         _W("Failed to call extra script from config");
1285         }
1286
1287         _I("Creating report for pid %d, tid %d, cmdline %s, pkgid %s",
1288            cinfo->pid_info, cinfo->tid_info, cinfo->cmd_line, cinfo->pkgid);
1289
1290         if (!system_dump) {
1291                 /* Exec crash modules */
1292                 if (!execute_crash_modules(cinfo)) {
1293                         _E("Failed to get basic crash information");
1294                         return false;
1295                 }
1296
1297                 if (!cinfo->livedump && config.release_early)
1298                         release_crashed_process();
1299         }
1300
1301         char *temp_report;
1302         if (system_dump || config.report_type >= REP_TYPE_FULL) {
1303                 if (!system_dump) {
1304                         /* Save shared objects info (file names, bulid IDs, rpm package names) */
1305                         if (config.dump_so_info)
1306                                 save_so_info(cinfo);
1307                         else
1308                                 _I("Not saving .so_info (disabled in configuration)");
1309                 }
1310
1311                 /* Wait misc. pids */
1312                 wait_for_pid(dump_state_pid, NULL);
1313                 if (extra_script_pid > 0)
1314                         wait_for_pid(extra_script_pid, NULL);
1315
1316                 if (zip_report)
1317                         compress(cinfo);
1318
1319                 temp_report = (zip_report) ? cinfo->zip_path : cinfo->pfx;
1320         } else
1321                 temp_report = cinfo->info_path;
1322
1323         if (move_dump_data(temp_report, cinfo)) {
1324                 _I("Report for pid %d created at %s", cinfo->pid_info, cinfo->result_path);
1325                 diagnostics_send_event("BugreportCreated", NULL);
1326         }
1327
1328         if (cinfo->print_result_path)
1329                 printf("REPORT_PATH=%s\n", cinfo->result_path);
1330
1331         if (!system_dump) {
1332                 if (!cinfo->livedump) {
1333                         if (!config.release_early)
1334                                 release_crashed_process();
1335
1336                         launch_dbus_notify(cinfo);
1337
1338                         /* launch crash-popup only if the .debugmode file exists */
1339                         if (debug_mode)
1340                                 launch_crash_popup(cinfo);
1341                 } else if (cinfo->kill) {
1342                         kill_pid(cinfo->pid_info, SIGKILL, false);
1343                 }
1344         }
1345
1346         return true;
1347 }
1348
1349 static bool crash_manager_prepare(struct crash_info *cinfo)
1350 {
1351         if (!config_init(&config, CRASH_MANAGER_CONFIG_PATH))
1352                 return false;
1353
1354         if (cinfo->executable_path && config_is_path_excluded(&config, cinfo->executable_path))
1355                 return false;
1356
1357         if (!prepare_paths(cinfo))
1358                 return false;
1359
1360         if (!wait_for_opt(WAIT_FOR_OPT_TIMEOUT_SEC))
1361                 return false;
1362
1363         /* Create crash directories */
1364         if (!make_dump_dir())
1365                 return false;
1366
1367         if (!set_crash_info(cinfo))
1368                 return false;
1369
1370         cinfo->lock_fd = lock_dir(cinfo->temp_dir, true);
1371         if (cinfo->lock_fd == -1)
1372                 return false;
1373
1374         return true;
1375 }
1376
1377 static void write_dump_reason(const char *reason, const char *base_dir, const char *name)
1378 {
1379         char *reason_name;
1380
1381         if (asprintf(&reason_name, "%s.dump_reason", name) == -1) {
1382                 _E("Failed to asprintf for reason_name: %m");
1383         } else {
1384                 write_to_file(reason, base_dir, reason_name);
1385                 free(reason_name);
1386         }
1387 }
1388
1389 static void crash_manager_cleanup(struct crash_info *cinfo)
1390 {
1391         assert(cinfo);
1392         unlock_dir(cinfo->lock_fd);
1393
1394         if (!remove_dir(cinfo->temp_dir, true))
1395                 _E("Failed to delete temp directory: %s", cinfo->temp_dir);
1396
1397         clean_temp(crash_temp_path);
1398 }
1399
1400 EXPORT void crash_manager_free(struct crash_info *cinfo)
1401 {
1402         if (cinfo->prstatus_fd >= 0)
1403                 close(cinfo->prstatus_fd);
1404         free(crash_temp_path);
1405         free(crash_dump_path);
1406         config_free(&config);
1407
1408         free_crash_info(cinfo);
1409 }
1410
1411 EXPORT bool crash_manager_direct(struct crash_info *cinfo)
1412 {
1413         if (!crash_manager_prepare(cinfo))
1414                 return false;
1415
1416         bool result = run(cinfo);
1417         crash_manager_cleanup(cinfo);
1418
1419         return result;
1420 }
1421
1422 EXPORT bool crash_manager_livedump_pid(pid_t pid, const char *dump_reason, char *report_path, size_t report_path_len)
1423 {
1424         bool result = false;
1425         struct crash_info cinfo;
1426         crash_info_init(&cinfo);
1427
1428         cinfo.livedump = true;
1429         cinfo.pid_info = pid;
1430
1431         if (!crash_manager_prepare(&cinfo))
1432                 goto exit;
1433
1434         write_dump_reason(dump_reason, cinfo.pfx, cinfo.name);
1435
1436         result = run(&cinfo);
1437         crash_manager_cleanup(&cinfo);
1438
1439         if (!result)
1440                 goto exit;
1441
1442         strncpy(report_path, cinfo.result_path, report_path_len);
1443
1444         result = true;
1445 exit:
1446         crash_manager_free(&cinfo);
1447         _I("Exiting with %s", result ? "success" : "fail");
1448         return result;
1449 }
1450