4 * Copyright (c) 2016-2019 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <iniparser.h>
33 #include <sys/prctl.h>
34 #include <sys/procfs.h>
36 #include <sys/types.h>
38 #include <sys/ptrace.h>
42 #include <pkgmgr-info.h>
43 #include <tzplatform_config.h>
46 #define LOG_TAG "CRASH_MANAGER"
49 #include "shared/log.h"
50 #include "shared/config.h"
51 #include "shared/spawn.h"
52 #include "shared/util.h"
54 #include "crash-manager.h"
59 #define CRASH_TEMP_SUBDIR "/temp/"
60 #define CRASH_PATH_SUBDIR "/dump/"
61 #define LIVE_PATH_SUBDIR "/livedump/"
63 #define WAIT_FOR_OPT_TIMEOUT_SEC 60
65 #define MINICOREDUMPER_TIMEOUT_MS DEFAULT_COMMAND_TIMEOUT_MS
66 #define LIVEDUMPER_TIMEOUT_MS DEFAULT_COMMAND_TIMEOUT_MS
67 #define CRASH_STACK_TIMEOUT_MS DEFAULT_COMMAND_TIMEOUT_MS
68 #define ZIP_TIMEOUT_MS DEFAULT_COMMAND_TIMEOUT_MS
83 /* Configuration variables */
85 static char* crash_dump_path;
86 static char* crash_temp_path;
88 /* pkgmgrinfo filter list function for getting application ID */
89 static int appinfo_get_appid_func(pkgmgrinfo_appinfo_h handle,
94 int ret = pkgmgrinfo_appinfo_get_appid(handle, &str);
95 if (ret == PMINFO_R_OK && str)
96 (*(char **)user_data) = strdup(str);
101 /* get application ID by pkgmgrinfo filter */
102 static int get_appid(char *exepath, char *appid, int len)
104 pkgmgrinfo_appinfo_filter_h handle = NULL;
108 ret = pkgmgrinfo_appinfo_filter_create(&handle);
109 if (ret != PMINFO_R_OK) {
114 ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_EXEC, exepath);
115 if (ret != PMINFO_R_OK) {
120 ret = pkgmgrinfo_appinfo_filter_count(handle, &count);
121 if (ret != PMINFO_R_OK) {
131 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appinfo_get_appid_func, &aid);
132 if (ret != PMINFO_R_OK) {
137 snprintf(appid, len, "%s", aid);
143 pkgmgrinfo_appinfo_filter_destroy(handle);
148 /* get package ID by appid */
149 static int get_pkgid(char *appid, char *pkgid, int len)
151 pkgmgrinfo_appinfo_h handle = NULL;
155 ret = pkgmgrinfo_appinfo_get_appinfo(appid, &handle);
156 if (ret != PMINFO_R_OK) {
160 ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkid);
161 if (ret != PMINFO_R_OK) {
165 snprintf(pkgid, len, "%s", pkid);
168 pkgmgrinfo_appinfo_destroy_appinfo(handle);
173 static int prepare_paths(struct crash_info* cinfo)
176 const char *crash_subdir = cinfo->livedump ? LIVE_PATH_SUBDIR : CRASH_PATH_SUBDIR;
178 if (cinfo->output_path) {
179 free(config.crash_root_path);
180 config.crash_root_path = strdup(cinfo->output_path);
181 if (!config.crash_root_path) {
182 _E("strdup() error: %m");
187 tmp_len = strlen(config.crash_root_path) + strlen(crash_subdir);
188 crash_dump_path = (char*)malloc(tmp_len + 1);
189 if (crash_dump_path == NULL) {
190 _E("Couldn't allocate memory for crash_dump_path: %m\n");
193 snprintf(crash_dump_path, tmp_len + 1, "%s%s", config.crash_root_path, crash_subdir);
195 tmp_len = strlen(config.crash_root_path) + strlen(CRASH_TEMP_SUBDIR);
196 crash_temp_path = (char*)malloc(tmp_len + 1);
197 if (crash_temp_path == NULL) {
198 _E("Couldn't allocate memory for crash_temp_path: %m\n");
201 snprintf(crash_temp_path, tmp_len + 1, "%s%s", config.crash_root_path, CRASH_TEMP_SUBDIR);
205 static bool make_dump_dir(void)
207 const char *dirs[] = {crash_dump_path, crash_temp_path};
209 for (size_t i = 0; i < ARRAY_SIZE(dirs); i++) {
210 const char *dirname = dirs[i];
212 int r = mkdir(dirname, 0775);
216 if (errno != EEXIST) {
217 _E("Unable to create directory %s: %m", dirname);
221 struct stat st = {0};
222 r = stat(dirname, &st);
223 bool isdir = !!(st.st_mode & S_IFDIR);
227 else if (!r && !isdir)
230 _E("Failure while trying to ensure %s exists and it is directory: %m", dirname);
237 static bool get_cmd_info(struct crash_info *cinfo)
241 cinfo->cmd_line = malloc(PATH_MAX);
242 if (!cinfo->cmd_line)
245 if (!read_proc_file(cinfo->pid_info, "cmdline", cinfo->cmd_line, PATH_MAX, NULL))
249 if (!get_exe_path(cinfo->pid_info, buf, sizeof(buf)))
252 cinfo->cmd_path = strdup(buf);
254 return !!cinfo->cmd_path;
257 free(cinfo->cmd_line);
258 cinfo->cmd_line = NULL;
262 static int set_prstatus(struct crash_info *cinfo)
265 char prstatus_name[NAME_MAX+1];
267 ret = snprintf(prstatus_name, NAME_MAX, "/%d.prstatus", cinfo->pid_info);
269 _E("Failed to snprintf for prstatus path");
273 cinfo->prstatus_fd = shm_open(prstatus_name, O_RDWR | O_CREAT, 0600);
274 if (cinfo->prstatus_fd < 0) {
279 ret = shm_unlink(prstatus_name);
281 _E("shm_unlink: %m");
285 ret = fcntl(cinfo->prstatus_fd, F_GETFD);
291 ret = fcntl(cinfo->prstatus_fd, F_SETFD, ret & ~FD_CLOEXEC);
297 ret = ftruncate(cinfo->prstatus_fd, sizeof(struct elf_prstatus));
299 _E("ftruncate(): %m");
306 if (cinfo->prstatus_fd >= 0)
307 close(cinfo->prstatus_fd);
311 bool set_crash_info(struct crash_info *cinfo)
314 char *temp_dir_ret = NULL;
318 if (cinfo->livedump) {
325 if (cinfo->livedump && !file_exists(LIVEDUMPER_BIN_PATH)) {
326 fprintf(stderr, "Error: %s doesn't exist - can not perform livedump. Terminating.\n", LIVEDUMPER_BIN_PATH);
327 _E("Error: %s doesn't exist - can not perform livedump. Terminating.\n", LIVEDUMPER_BIN_PATH);
331 if (cinfo->tid_info == -1) {
332 if (cinfo->livedump) {
333 cinfo->tid_info = cinfo->pid_info;
335 cinfo->tid_info = find_crash_tid(cinfo->pid_info);
336 if (cinfo->tid_info < 0) {
338 cinfo->tid_info = cinfo->pid_info;
343 if (!get_cmd_info(cinfo)) {
344 _E("Failed to get command info");
348 if (cinfo->time_info == 0)
349 cinfo->time_info = time(NULL);
351 localtime_r(&cinfo->time_info, &loc_tm);
352 strftime(date, sizeof(date), "%Y%m%d%H%M%S", &loc_tm);
354 if (asprintf(&cinfo->temp_dir, "%s/crash.XXXXXX", crash_temp_path) == -1) {
355 _E("Failed to asprintf for temp_dir");
356 cinfo->temp_dir = NULL;
360 temp_dir_ret = mkdtemp(cinfo->temp_dir);
361 if (!temp_dir_ret || access(temp_dir_ret, F_OK)) {
362 _E("Failed to mkdtemp for temp_dir");
366 if (asprintf(&cinfo->name, "%s_%d_%s", basename(cinfo->cmd_line),
367 cinfo->pid_info, date) == -1) {
368 _E("Failed to snprintf for name");
373 if (config.allow_zip)
374 ret = asprintf(&cinfo->result_path,
375 "%s/%s.zip", crash_dump_path, cinfo->name);
377 ret = asprintf(&cinfo->result_path,
378 "%s/%s", crash_dump_path, cinfo->name);
380 _E("Failed to asprintf for result path");
381 cinfo->result_path = NULL;
385 if (asprintf(&cinfo->pfx, "%s/%s", cinfo->temp_dir, cinfo->name) == -1) {
386 _E("Failed to asprintf for pfx");
390 ret = mkdir(cinfo->pfx, 0775);
392 _E("Failed to mkdir for %s", cinfo->pfx);
396 if (asprintf(&cinfo->info_path, "%s/%s.info", cinfo->pfx, cinfo->name) == -1) {
397 _E("Failed to asprintf for info path");
398 cinfo->info_path = NULL;
402 if (asprintf(&cinfo->core_path, "%s/%s.coredump", cinfo->pfx, cinfo->name) == -1) {
403 _E("Failed to asprintf for core path");
404 cinfo->core_path = NULL;
408 if (asprintf(&cinfo->log_path, "%s/%s.log", cinfo->pfx, cinfo->name) == -1) {
409 _E("Failed to asprintf for log path");
410 cinfo->log_path = NULL;
415 if (asprintf(&cinfo->sysassert_cs_path, "/tmp/crash_stack/%s_%d.info",
416 basename(cinfo->cmd_line), cinfo->pid_info) == -1) {
417 _E("Failed to snprintf for sys-assert callstack path");
418 cinfo->sysassert_cs_path = NULL;
422 if (set_prstatus(cinfo) < 0)
425 if (get_appid(cinfo->cmd_line, cinfo->appid, sizeof(cinfo->appid)) < 0) {
426 snprintf(cinfo->appid, sizeof(cinfo->appid), "%s", basename(cinfo->cmd_line));
427 snprintf(cinfo->pkgid, sizeof(cinfo->pkgid), "%s", basename(cinfo->cmd_line));
429 if (get_pkgid(cinfo->appid, cinfo->pkgid, sizeof(cinfo->pkgid)) < 0)
430 snprintf(cinfo->pkgid, sizeof(cinfo->pkgid), "%s", cinfo->appid);
436 remove_dir(cinfo->temp_dir, 1);
441 static int get_sysassert_cs(struct crash_info *cinfo)
444 char move_path[PATH_MAX];
446 if (access(cinfo->sysassert_cs_path, F_OK)) {
447 _E("The sys-assert cs file not found: %s: %m",
448 cinfo->sysassert_cs_path);
449 cinfo->have_sysassert_report = 0;
452 cinfo->have_sysassert_report = 1;
454 ret = snprintf(move_path, sizeof(move_path), "%s/%s",
455 cinfo->pfx, basename(cinfo->sysassert_cs_path));
457 _E("Failed to snprintf for move path");
461 if (move_file(move_path, cinfo->sysassert_cs_path) < 0) {
462 _E("Failed to move %s to %s",
463 cinfo->sysassert_cs_path, move_path);
471 static void launch_crash_popup(struct crash_info *cinfo)
475 char *av[] = { CRASH_POPUP_BIN_PATH,
476 "--cmdline", cinfo->cmd_line,
477 "--cmdpath", cinfo->cmd_path,
480 spawn_param_s param = { .fn = spawn_nullstdfds };
481 spawn(av, NULL, ¶m, NULL, NULL);
484 static bool dump_system_state(const struct crash_info *cinfo, pid_t *pid)
486 char *av[] = {DUMP_SYSTEMSTATE_BIN_PATH, "-d", "-k", "-j", "-p", "-e", "-f", cinfo->log_path, NULL};
487 spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
488 return spawn(av, NULL, ¶m, pid, NULL);
491 static void save_so_info(const struct crash_info *cinfo)
493 char maps_path[PATH_MAX];
494 char so_info_path[PATH_MAX];
495 snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps",
498 snprintf(so_info_path, sizeof(so_info_path),
499 "%s/%s.%s", cinfo->pfx, cinfo->name, "so_info");
501 get_and_save_so_info(maps_path, so_info_path);
504 /* remove a file whose name begins with 'beggining_of_name'. This is needed
505 * when we don't want to include coredump in report, but we only know the
506 * beginning of the coredump file name. */
507 static int remove_file_in_dir(const char *directory, const char *beginning_of_name)
510 int errno_unlink = 0;
512 DIR *dir = opendir(directory);
516 int dir_fd = dirfd(dir);
522 struct dirent* file_info;
523 while ((file_info = readdir(dir)) != NULL) {
524 if (strstr(file_info->d_name, beginning_of_name) == file_info->d_name) {
525 ret = unlinkat(dir_fd, file_info->d_name, 0);
526 errno_unlink = errno;
531 errno = errno_unlink; /* for %m */
536 // These macros are used in functions below
537 #define SNPRINTF_OR_EXIT_W(name, format, member) if (snprintf(name##_str, sizeof(name##_str), format, cinfo->member) < 0) goto out;
538 #define SNPRINTF_OR_EXIT(name, format) SNPRINTF_OR_EXIT_W(name, format, name##_info)
540 static bool extra_script(const struct crash_info *cinfo, pid_t *pid)
542 if (!config.extra_script)
546 SNPRINTF_OR_EXIT(pid, "%d")
548 char *av[] = { config.extra_script, cinfo->pfx, pid_str, NULL };
549 spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
550 return spawn(av, NULL, ¶m, pid, NULL);
556 static void launch_dbus_notify(struct crash_info *cinfo)
560 char pid_str[11], tid_str[11], sig_str[11];
561 char *prstatus_fd_str = NULL;
562 char tid_comm_str[KERNEL_DEFINED_TASK_COMM_LEN + 1] = { 0, };
564 (void)read_proc_file(cinfo->tid_info, "comm", tid_comm_str, sizeof(tid_comm_str), filter_drop_trailing_whitespace);
566 if (asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
567 _E("Unable to allocate memory: %m");
571 SNPRINTF_OR_EXIT(pid, "%d")
572 SNPRINTF_OR_EXIT(tid, "%d")
573 SNPRINTF_OR_EXIT(sig, "%d")
575 char *av[] = { CRASH_NOTIFY_BIN_PATH,
576 "--cmdline", cinfo->cmd_line,
577 "--cmdpath", cinfo->cmd_path,
580 "--appid", cinfo->appid,
581 "--pkgid", cinfo->pkgid,
582 "--reportpath", cinfo->result_path,
583 "--prstatus_fd", prstatus_fd_str,
585 "--tid-comm", tid_comm_str,
588 spawn(av, NULL, NULL, NULL, NULL);
590 free(prstatus_fd_str);
593 static bool execute_minicoredump(struct crash_info *cinfo, int *exit_code)
595 char *coredump_name = NULL;
596 char *prstatus_fd_str = NULL;
599 if (asprintf(&coredump_name, "%s.coredump", cinfo->name) == -1
600 || asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
601 _E("Unable to allocate memory");
605 char pid_str[11], uid_str[11], gid_str[11], sig_str[11], time_str[11];
607 SNPRINTF_OR_EXIT(pid, "%d")
608 SNPRINTF_OR_EXIT(uid, "%d")
609 SNPRINTF_OR_EXIT(gid, "%d")
610 SNPRINTF_OR_EXIT(sig, "%d")
611 SNPRINTF_OR_EXIT(time, "%ld")
613 /* Execute minicoredumper */
615 MINICOREDUMPER_BIN_PATH, // minicoredumper filename path
619 sig_str, // %s - number of signal
620 time_str, // %t - time of dump
621 "localhost", // %h - hostname
622 basename(cinfo->cmd_line), // %e - exe name (need for result filename)
623 MINICOREDUMPER_CONFIG_PATH, // config file
625 cinfo->pfx, // temp dir
627 coredump_name, // coredump filename
633 spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
634 is_ok = spawn_wait(args, NULL, ¶m, MINICOREDUMPER_TIMEOUT_MS, exit_code);
636 /* Minicoredumper must be executed to dump at least PRSTATUS for
637 other tools, coredump, however, might have been disabled. */
638 if (!config.dump_core) {
639 if (remove_file_in_dir(cinfo->pfx, coredump_name) != 0)
640 _E("Saving core disabled - removing coredump %s/%s failed: %m",
641 cinfo->pfx, coredump_name);
643 _D("Saving core disabled - removed coredump %s/%s",
644 cinfo->pfx, coredump_name);
649 free(prstatus_fd_str);
654 static bool execute_livedumper(const struct crash_info *cinfo, int *exit_code)
656 char *coredump_path = NULL;
657 char *prstatus_fd_str = NULL;
661 if (asprintf(&coredump_path, "%s/%s.coredump", cinfo->pfx, cinfo->name) == -1 ||
662 asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
663 _E("Unable to allocate memory");
667 SNPRINTF_OR_EXIT(pid, "%d")
669 /* Execute livedumper */
671 LIVEDUMPER_BIN_PATH, // livedumper filename path
672 "-m", // minilivecoredump
673 "-P", prstatus_fd_str,
679 spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = STDERR_FILENO };
680 is_ok = spawn_wait(args, NULL, ¶m, LIVEDUMPER_TIMEOUT_MS, exit_code);
682 free(prstatus_fd_str);
687 static bool execute_crash_stack(const struct crash_info *cinfo, int *exit_code)
689 char pid_str[11], tid_str[11], sig_str[11], prstatus_fd_str[11];
692 SNPRINTF_OR_EXIT(pid, "%d")
693 SNPRINTF_OR_EXIT(tid, "%d")
694 SNPRINTF_OR_EXIT(sig, "%d")
695 SNPRINTF_OR_EXIT_W(prstatus_fd, "%d", prstatus_fd)
697 /* Execute crash-stack */
698 char *args[] = { CRASH_STACK_BIN_PATH,
702 "--prstatus_fd", prstatus_fd_str,
705 int fd = open(cinfo->info_path, O_WRONLY | O_CREAT, 0600);
707 _E("open %s error: %m", cinfo->info_path);
711 spawn_param_s param = { .fn = spawn_setstdout, .u.int_val = fd };
712 is_ok = spawn_wait(args, NULL, ¶m, CRASH_STACK_TIMEOUT_MS, exit_code);
719 #undef SNPRINTF_OR_EXIT
720 #undef SNPRINTF_OR_EXIT_W
722 static bool kill_pid(const pid_t pid, int sig, bool wait)
724 if (kill(pid, sig) == -1) {
725 _E("kill sig %d error: %m\n", sig);
730 if (waitpid(pid, NULL, 0) == -1) {
731 _E("waitpid error: %m");
738 static bool process_stop(const pid_t pid)
740 _D("stop process %d", pid);
741 return kill_pid(pid, SIGSTOP, false);
744 static bool process_continue(const pid_t pid)
746 _D("continue process %d", pid);
747 return kill_pid(pid, SIGCONT, false);
750 static bool execute_crash_modules(struct crash_info *cinfo)
753 if (cinfo->livedump) {
754 _I("Starting the livedumper");
755 if (!process_stop(cinfo->pid_info))
757 if (!execute_livedumper(cinfo, &exit_code) || exit_code != 0) {
758 _E("Failed to run livedumper - can not continue");
759 process_continue(cinfo->pid_info);
763 _I("Starting the minicoredumper");
764 if (!execute_minicoredump(cinfo, &exit_code) || exit_code != 0) {
765 _E("Failed to run minicoredumper - can not continue");
771 /* Use process_vm_readv() version as fallback if sys-assert
772 * failed to generate report */
773 if (cinfo->have_sysassert_report)
776 execute_crash_stack(cinfo, NULL);
778 process_continue(cinfo->pid_info);
783 static int lock_dumpdir(void)
787 if ((fd = open(crash_dump_path, O_RDONLY | O_DIRECTORY)) < 0) {
788 _E("Failed to open %s: %m", crash_dump_path);
792 if (flock(fd, LOCK_EX) < 0) {
793 _E("Failed to lock %s for exclusive access: %m", crash_dump_path);
801 static void unlock_dumpdir(int fd)
803 if (flock(fd, LOCK_UN) < 0)
804 _E("Failed to unlock file descriptor: %m");
808 static int dump_filter(const struct dirent *de)
810 if (de->d_name[0] == '.')
815 static int mtime_cmp(const void *_a, const void *_b)
817 const struct file_info *a = _a;
818 const struct file_info *b = _b;
820 if (a->mtime < b->mtime)
822 if (a->mtime > b->mtime)
827 static int scan_dump(struct file_info **dump_list, off_t *usage)
829 struct file_info *temp_list;
830 struct dirent **scan_list = NULL;
832 int i, scan_num, dump_num = 0;
835 if ((fd = open(crash_dump_path, O_DIRECTORY)) < 0) {
836 _E("Failed to open %s: %m", crash_dump_path);
840 scan_num = scandir(crash_dump_path, &scan_list, &dump_filter, NULL);
846 temp_list = (struct file_info *)calloc(scan_num,
847 sizeof(struct file_info));
849 _E("Failed to calloc for dump list");
853 for (i = 0; i < scan_num; i++) {
854 if (fstatat(fd, scan_list[i]->d_name, &st, 0) < 0) {
855 _E("Failed to fstatat");
859 if (asprintf(&(temp_list[dump_num].path), "%s/%s",
860 crash_dump_path, scan_list[i]->d_name) < 0) {
861 _E("Failed to asprintf");
865 if (scan_list[i]->d_type == DT_DIR) {
866 temp_list[dump_num].isdir = 1;
867 temp_list[dump_num].size =
868 get_directory_usage(temp_list[dump_num].path);
870 temp_list[dump_num].isdir = 0;
871 temp_list[dump_num].size = st.st_size;
873 temp_list[dump_num].mtime = st.st_mtime;
882 if (dump_num != scan_num) {
883 struct file_info *const tmp = (struct file_info *)realloc(temp_list,
884 dump_num * sizeof(struct file_info));
893 qsort(temp_list, dump_num, sizeof(struct file_info), mtime_cmp);
896 for (i = 0; i < dump_num; i++) {
897 _D("[%d] path: %s(%s), size: %zu kb, mtime: %s",
900 temp_list[i].isdir ? "DIR" : "FILE",
901 temp_list[i].size / 1024,
902 ctime(&(temp_list[i].mtime)));
903 *usage += temp_list[i].size;
905 *dump_list = temp_list;
907 for (i = 0; i < scan_num; i++)
915 static int check_disk_available(const char *path, int check_size)
917 struct statfs lstatfs;
923 if (statfs(path, &lstatfs) < 0)
925 avail_size = (int)(lstatfs.f_bavail * (lstatfs.f_bsize / 1024));
927 if (check_size > avail_size) {
928 _I("avail_size is (%d)", avail_size);
935 static int remove_file_info(struct file_info file)
938 return remove_dir(file.path, 1);
940 return unlink(file.path);
943 static void clean_dump(void)
945 struct file_info *dump_list = NULL;
946 int i, scan_num, dump_num, remove_flag;
950 scan_num = scan_dump(&dump_list, &usage);
956 cur_time = time(NULL);
958 for (i = 0; i < scan_num; i++) {
961 /* Retention time check */
962 if (config.max_retention_sec &&
963 dump_list[i].mtime > 0 &&
964 dump_list[i].mtime + config.max_retention_sec < cur_time)
965 remove_flag = RET_EXCEED;
966 /* Check the number of dumps */
967 else if (config.max_crash_dump &&
968 0 < dump_num && config.max_crash_dump < dump_num)
969 remove_flag = NUM_EXCEED;
970 /* Check the max system use size */
971 else if (config.system_max_use &&
972 0 < dump_num && config.system_max_use < usage / 1024)
973 remove_flag = USAGE_EXCEED;
975 switch (remove_flag) {
977 _I("Reached the maximum retention time %d, so remove (%s)",
978 config.max_retention_sec, dump_list[i].path);
981 _I("Reached the maximum number of dump %d/%d, so remove (%s)",
982 dump_num, config.max_crash_dump,
986 _I("Reached the maximum disk usage %" PRId64 "/%d kb, so remove (%s)",
987 usage / 1024, config.system_max_use,
997 if (remove_file_info(dump_list[i]) < 0) {
998 _E("Failed to remove %s", dump_list[i].path);
1002 usage -= dump_list[i].size;
1005 /* Check disk free space to keep */
1006 if (config.system_keep_free &&
1007 check_disk_available(config.crash_root_path,
1008 config.system_keep_free) < 0) {
1009 _I("Disk is not available! so set the maximum number of dump to 1");
1010 config.max_crash_dump = 1;
1013 for (i = 0; i < dump_num; i++)
1014 free(dump_list[i].path);
1018 static void compress(struct crash_info *cinfo)
1021 char zip_path[PATH_MAX];
1023 ret = snprintf(zip_path, sizeof(zip_path), "%s/report.zip",
1026 _E("Failed to snprintf for zip path");
1030 char *args[] = {"/bin/zip", "-qyr", zip_path, cinfo->name, NULL};
1031 spawn_param_s param1 = { .fn = spawn_nullstdfds };
1032 spawn_param_s param0 = { .fn = spawn_chdir, .u.char_ptr = cinfo->temp_dir, .next = ¶m1 };
1033 (void)spawn_wait(args, NULL, ¶m0, ZIP_TIMEOUT_MS, NULL);
1035 if ((lock_fd = lock_dumpdir()) < 0)
1037 if (!rename(zip_path, cinfo->result_path))
1040 _E("Failed to move %s to %s", zip_path, cinfo->result_path);
1041 unlock_dumpdir(lock_fd);
1043 if (remove_dir(cinfo->temp_dir, 1) < 0)
1044 _E("Failed to delete temp directory");
1047 static void move_dump_data(const char *from_path, const struct crash_info *cinfo)
1051 if ((lock_fd = lock_dumpdir()) < 0)
1053 if (!rename(from_path, cinfo->result_path))
1056 _E("Failed to move %s to %s",
1057 from_path, cinfo->result_path);
1058 unlock_dumpdir(lock_fd);
1060 if (remove_dir(cinfo->temp_dir, 1) < 0)
1061 _E("Failed to delete temp directory");
1064 static int wait_for_opt(unsigned int timeout)
1066 unsigned int count = 0;
1068 while (check_disk_available(config.crash_root_path, 0) < 0 && count < timeout) {
1069 log_kmsg("crash-manager: path %s is not available\n", config.crash_root_path);
1073 if (count >= timeout) {
1074 log_kmsg("crash-manager: timeout (%ds) while waiting for %s."
1075 "Probably /opt is not mounted.\n", timeout, config.crash_root_path);
1082 static void free_crash_info(struct crash_info *cinfo)
1084 free(cinfo->cmd_line);
1085 free(cinfo->cmd_path);
1086 free(cinfo->temp_dir);
1087 free(cinfo->result_path);
1089 free(cinfo->info_path);
1090 free(cinfo->core_path);
1091 free(cinfo->log_path);
1094 free(cinfo->sysassert_cs_path);
1098 void crash_info_init(struct crash_info *cinfo)
1100 cinfo->prstatus_fd = -1;
1101 cinfo->livedump = false;
1102 cinfo->kill = false;
1103 cinfo->print_result_path = false;
1104 cinfo->tid_info = -1;
1105 cinfo->time_info = 0;
1106 cinfo->output_path = NULL;
1107 cinfo->cmd_line = NULL;
1108 cinfo->cmd_path = NULL;
1109 cinfo->temp_dir = NULL;
1111 cinfo->result_path = NULL;
1112 cinfo->info_path = NULL;
1113 cinfo->core_path = NULL;
1116 static bool run(struct crash_info *cinfo)
1118 /* Execute processes in parallel */
1119 static pid_t dump_state_pid = 0, extra_script_pid = 0;
1120 int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0;
1123 /* Fetch callstack of sys-assert */
1124 get_sysassert_cs(cinfo);
1127 if (config.report_type >= REP_TYPE_FULL) {
1128 /* Exec dump_systemstate */
1129 if (!dump_system_state(cinfo, &dump_state_pid)) {
1130 _E("Failed to get system state report");
1134 if (config.extra_script && !extra_script(cinfo, &extra_script_pid))
1135 _W("Failed to call extra script from config");
1138 /* Exec crash modules */
1139 if (!execute_crash_modules(cinfo)) {
1140 _E("Failed to get basic crash information");
1144 if (config.report_type >= REP_TYPE_FULL) {
1145 /* Save shared objects info (file names, bulid IDs, rpm package names) */
1146 save_so_info(cinfo);
1148 /* Wait misc. pids */
1149 wait_for_pid(dump_state_pid, NULL);
1150 if (extra_script_pid > 0)
1151 wait_for_pid(extra_script_pid, NULL);
1153 /* Tar compression */
1154 if (config.allow_zip)
1157 move_dump_data(cinfo->pfx, cinfo);
1159 free(cinfo->result_path);
1160 if (asprintf(&cinfo->result_path, "%s/%s.info",
1161 crash_dump_path, cinfo->name) == -1) {
1162 cinfo->result_path = NULL;
1163 _E("asprintf() error: %m");
1166 move_dump_data(cinfo->info_path, cinfo);
1169 if (cinfo->print_result_path)
1170 printf("REPORT_PATH=%s\n", cinfo->result_path);
1172 if (!cinfo->livedump) {
1173 /* Release the core pipe as passed by kernel, allowing another
1174 * coredump to be handled.
1176 * Due to usage of core_pipe_limit there is limited number of
1177 * crash-manager processes that kernel is going to invoke
1178 * concurrently. As the next and last step is a _synchronous_
1179 * call to crash-popup we close the descriptor here.
1181 * Note: for VIP processes this will likely cause the system
1182 * to reboot without showing popup.
1184 close(STDIN_FILENO);
1186 launch_dbus_notify(cinfo);
1188 /* launch crash-popup only if the .debugmode file exists */
1190 launch_crash_popup(cinfo);
1191 } else if (cinfo->kill) {
1192 kill_pid(cinfo->pid_info, SIGKILL, false);
1198 static bool crash_manager_prepare(struct crash_info *cinfo)
1200 if (!config_init(&config, CRASH_MANAGER_CONFIG_PATH))
1203 if (!prepare_paths(cinfo))
1206 if (!wait_for_opt(WAIT_FOR_OPT_TIMEOUT_SEC))
1209 /* Create crash directories */
1210 if (!make_dump_dir())
1213 if (!set_crash_info(cinfo))
1219 static void write_dump_reason(const char *reason, const char *base_dir, const char *name)
1223 if (asprintf(&reason_name, "%s.dump_reason", name) == -1) {
1224 _E("Failed to asprintf for reason_name: %m");
1226 write_to_file(reason, base_dir, reason_name);
1231 void crash_manager_free(struct crash_info *cinfo)
1233 if (cinfo->prstatus_fd >= 0)
1234 close(cinfo->prstatus_fd);
1235 free(crash_temp_path);
1236 free(crash_dump_path);
1237 config_free(&config);
1239 free_crash_info(cinfo);
1242 bool crash_manager_direct(struct crash_info *cinfo)
1244 if (!crash_manager_prepare(cinfo))
1250 bool crash_manager_livedump_pid(pid_t pid, const char *dump_reason, char *report_path, size_t report_path_len)
1252 bool result = false;
1253 struct crash_info cinfo;
1254 crash_info_init(&cinfo);
1256 cinfo.livedump = true;
1257 cinfo.pid_info = pid;
1259 if (!crash_manager_prepare(&cinfo))
1262 write_dump_reason(dump_reason, cinfo.pfx, cinfo.name);
1267 strncpy(report_path, cinfo.result_path, report_path_len);
1271 crash_manager_free(&cinfo);
1272 _I("Exiting with %s", result ? "success" : "fail");