4 * Copyright (c) 2016 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.
28 #include <sys/procfs.h>
30 #include <sys/types.h>
31 #include <sys/prctl.h>
36 #include <iniparser.h>
37 #include <tzplatform_config.h>
38 #include <pkgmgr-info.h>
39 #include "crash-manager.h"
41 #include "shared/log.h"
42 #include "shared/util.h"
43 #include "dbus_notify.h"
46 #define LOG_TAG "CRASH_MANAGER"
50 #define CRASH_SECTION "CrashManager"
52 /* Crash-popup dbus */
53 #define POPUP_BUS_NAME "org.tizen.system.popup"
54 #define POPUP_OBJECT_PATH "/Org/Tizen/System/Popup/Crash"
55 #define POPUP_INTERFACE_NAME POPUP_BUS_NAME".Crash"
56 #define POPUP_METHOD "PopupLaunch"
58 /* Configuration default values */
59 /* note: 0 means unlimited */
60 #define SYSTEM_MAX_USE 0
61 #define SYSTEM_KEEP_FREE 0
62 #define MAX_RETENTION_SEC 0
63 #define MAX_CRASH_DUMP 0
65 #define ALLOW_ZIP true
68 #define PKGNAME_MAX 128
70 #define CRASH_TEMP_SUBDIR "/temp/"
71 #define CRASH_PATH_SUBDIR "/dump/"
73 #define WAIT_FOR_OPT_TIMEOUT_SEC 60
75 #define DEFAULT_COMMAND_TIMEOUT 12*60
76 #define MINICOREDUMPER_TIMEOUT DEFAULT_COMMAND_TIMEOUT
77 #define CRASH_STACK_TIMEOUT DEFAULT_COMMAND_TIMEOUT
78 #define ZIP_TIMEOUT DEFAULT_COMMAND_TIMEOUT
91 #define REP_DEFAULT_TYPE REP_TYPE_FULL
93 #define REP_TYPE_FULL_STR "FULL"
94 #define REP_TYPE_INFO_STR "INFO"
103 /* Configuration variables */
104 static int system_max_use;
105 static int system_keep_free;
106 static int max_retention_sec;
107 static int max_crash_dump;
108 static int dump_core;
109 static bool allow_zip;
110 static char* crash_root_path;
111 static char* crash_crash_path;
112 static char* crash_temp_path;
113 static int report_type;
115 /* Paths and variables */
132 char appid[APPID_MAX];
133 char pkgid[PKGNAME_MAX];
135 char *sysassert_cs_path;
136 bool have_sysassert_report;
141 /* pkgmgrinfo filter list function for getting application ID */
142 static int appinfo_get_appid_func(pkgmgrinfo_appinfo_h handle,
146 int ret = PMINFO_R_ERROR;
148 pkgmgrinfo_appinfo_get_appid(handle, &str);
150 (*(char **)user_data) = strdup(str);
156 /* get application ID by pkgmgrinfo filter */
157 static int get_appid(char *exepath, char *appid, int len)
159 pkgmgrinfo_appinfo_filter_h handle = NULL;
163 ret = pkgmgrinfo_appinfo_filter_create(&handle);
164 if (ret != PMINFO_R_OK) {
169 ret = pkgmgrinfo_appinfo_filter_add_string(handle, PMINFO_APPINFO_PROP_APP_EXEC, exepath);
170 if (ret != PMINFO_R_OK) {
175 ret = pkgmgrinfo_appinfo_filter_count(handle, &count);
176 if (ret != PMINFO_R_OK) {
186 ret = pkgmgrinfo_appinfo_filter_foreach_appinfo(handle, appinfo_get_appid_func, &aid);
187 if (ret != PMINFO_R_OK) {
192 snprintf(appid, len, "%s", aid);
198 pkgmgrinfo_appinfo_filter_destroy(handle);
203 /* get package ID by appid */
204 static int get_pkgid(char *appid, char *pkgid, int len)
206 pkgmgrinfo_appinfo_h handle = NULL;
210 ret = pkgmgrinfo_appinfo_get_appinfo(appid, &handle);
211 if (ret != PMINFO_R_OK) {
215 ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkid);
216 if (ret != PMINFO_R_OK) {
220 snprintf(pkgid, len, "%s", pkid);
223 pkgmgrinfo_appinfo_destroy_appinfo(handle);
228 static int prepare_paths(void)
231 tmp_len = strlen(crash_root_path) + strlen(CRASH_PATH_SUBDIR);
232 crash_crash_path = (char*)malloc(tmp_len + 1);
233 if (crash_crash_path == NULL) {
234 _E("Couldn't allocate memory for crash_crash_path: %m\n");
237 snprintf(crash_crash_path, tmp_len + 1, "%s%s", crash_root_path, CRASH_PATH_SUBDIR);
239 tmp_len = strlen(crash_root_path) + strlen(CRASH_TEMP_SUBDIR);
240 crash_temp_path = (char*)malloc(tmp_len + 1);
241 if (crash_temp_path == NULL) {
242 _E("Couldn't allocate memory for crash_temp_path: %m\n");
245 snprintf(crash_temp_path, tmp_len + 1, "%s%s", crash_root_path, CRASH_TEMP_SUBDIR);
249 static const char* report_type_to_str(const int report_type)
251 switch (report_type) {
253 return REP_TYPE_INFO_STR;
256 return REP_TYPE_FULL_STR;
263 static int report_type_from_str(const char* report_type_str)
265 if (report_type_str == NULL)
268 if (strncmp(report_type_str, REP_TYPE_FULL_STR, strlen(REP_TYPE_FULL_STR)) == 0)
269 return REP_TYPE_FULL;
270 else if (strncmp(report_type_str, REP_TYPE_INFO_STR, strlen(REP_TYPE_INFO_STR)) == 0)
271 return REP_TYPE_INFO;
276 static int get_config(void)
278 dictionary *ini = NULL;
284 system_max_use = SYSTEM_MAX_USE;
285 system_keep_free = SYSTEM_KEEP_FREE;
286 max_retention_sec = MAX_RETENTION_SEC;
287 max_crash_dump = MAX_CRASH_DUMP;
288 dump_core = DUMP_CORE;
289 allow_zip = ALLOW_ZIP;
290 crash_root_path = strdup(CRASH_ROOT_PATH);
291 if (crash_root_path == NULL) {
292 _E("strdup error: %m\n");
295 report_type = REP_DEFAULT_TYPE;
297 ini = iniparser_load(CRASH_MANAGER_CONFIG_PATH);
299 _E("Failed to load conf file %s", CRASH_MANAGER_CONFIG_PATH);
303 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "SystemMaxUse");
304 value = iniparser_getint(ini, key, -1);
306 _D("Invalid value for SystemMaxUse. Use default value [ %d kbyte]",
309 _D("SystemMaxUse [ %d kbyte]", value);
310 system_max_use = value;
313 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "SystemKeepFree");
314 value = iniparser_getint(ini, key, -1);
316 _D("Invalid value for SystemKeepFree. Use default value [ %d kbyte]",
319 _D("SystemKeepFree [ %d kbyte]", value);
320 system_keep_free = value;
324 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "MaxRetentionSec");
325 value = iniparser_getint(ini, key, -1);
327 _D("Invalid value for MaxRetentionSec. Use default value [ %d ]",
330 _D("MaxRetentionSec [ %d ]", value);
331 max_retention_sec = value;
334 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "MaxCrashDump");
335 value = iniparser_getint(ini, key, -1);
337 _D("Invalid value for MaxCrashDump. Use default value [ %d ]",
340 _D("MaxCrashDump [ %d ]", value);
341 max_crash_dump = value;
344 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "DumpCore");
345 value = iniparser_getint(ini, key, -1);
346 if (value != 0 && value != 1) {
347 _D("Invalid value for DumpCore default value [ %d ]",
350 _D("DumpCore [ %d ]", value);
354 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "AllowZip");
355 value = iniparser_getboolean(ini, key, -1);
357 _D("Invalid value for AllowZip. Use default value [ %s ]",
358 ALLOW_ZIP ? "true" : "false");
360 _D("AllowZip [ %s ]", value ? "true" : "false");
364 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "CrashRootPath");
365 value_str = iniparser_getstring(ini, key, NULL);
366 if (value_str == NULL) {
367 _D("Invalid value for CrashRootPath. Use default value [ %s ]",
370 _D("CrashRootPath [ %s ]", value_str);
371 free(crash_root_path);
372 crash_root_path = strdup(value_str);
373 if (crash_root_path == NULL) {
374 _E("strdup error: %m\n");
380 snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "ReportType");
381 value_str = iniparser_getstring(ini, key, NULL);
382 if (value_str == NULL) {
383 _D("Invalid value for ReportType. Use default value [ %s ]",
384 report_type_to_str(report_type));
386 _D("ReportType [ %s ]", value_str);
387 report_type = report_type_from_str(value_str);
389 if (report_type < 0) {
390 _E("Unknown ReportType %s. Fallback to default: %s",
391 value_str, report_type_to_str(REP_DEFAULT_TYPE));
392 report_type = REP_DEFAULT_TYPE;
397 iniparser_freedict(ini);
401 static int make_dump_dir(void)
405 if (!stat(crash_crash_path, &st)) {
406 if (!(st.st_mode & S_IFDIR)) {
407 _E("%s (not DIR) is already exist", crash_crash_path);
411 if (mkdir(crash_crash_path, 0775) < 0) {
412 _E("Failed to mkdir for %s", crash_crash_path);
417 if (!stat(crash_temp_path, &st)) {
418 if (!(st.st_mode & S_IFDIR)) {
419 _E("%s (not DIR) is already exist", crash_temp_path);
423 if (mkdir(crash_temp_path, 0775) < 0) {
424 _E("Failed to mkdir for %s", crash_temp_path);
432 static int get_cmd_info(struct crash_info *cinfo)
434 cinfo->cmd_line = get_cmd_line(cinfo->pid_info);
435 cinfo->cmd_path = get_exe_path(cinfo->pid_info);
437 return (cinfo->cmd_line != NULL && cinfo->cmd_path != NULL);
440 static int set_prstatus(struct crash_info *cinfo)
443 char prstatus_name[NAME_MAX+1];
445 ret = snprintf(prstatus_name, NAME_MAX, "/%d.prstatus", cinfo->pid_info);
447 _E("Failed to snprintf for prstatus path");
451 cinfo->prstatus_fd = shm_open(prstatus_name, O_RDWR | O_CREAT, 0600);
452 if (cinfo->prstatus_fd < 0) {
457 ret = shm_unlink(prstatus_name);
459 _E("shm_unlink: %m");
463 ret = fcntl(cinfo->prstatus_fd, F_GETFD);
469 ret = fcntl(cinfo->prstatus_fd, F_SETFD, ret & ~FD_CLOEXEC);
475 ret = ftruncate(cinfo->prstatus_fd, sizeof(struct elf_prstatus));
477 _E("ftruncate(): %m");
484 if (cinfo->prstatus_fd >= 0)
485 close(cinfo->prstatus_fd);
489 static int set_crash_info(struct crash_info *cinfo, int argc, char *argv[])
492 char *temp_dir_ret = NULL;
496 cinfo->pid_info = strtol(argv[1], NULL, 10);
497 cinfo->sig_info = atoi(argv[4]);
499 cinfo->tid_info = strtol(argv[6], NULL, 10);
501 cinfo->tid_info = find_crash_tid(cinfo->pid_info);
502 if (cinfo->tid_info < 0) {
504 cinfo->tid_info = cinfo->pid_info;
508 ret = get_cmd_info(cinfo);
510 _E("Failed to get command info");
514 cinfo->time_info = strtol(argv[5], NULL, 10);
515 localtime_r(&cinfo->time_info, &loc_tm);
516 strftime(date, sizeof(date), "%Y%m%d%H%M%S", &loc_tm);
518 if (asprintf(&cinfo->temp_dir, "%s/crash.XXXXXX", crash_temp_path) == -1) {
519 _E("Failed to asprintf for temp_dir");
520 cinfo->temp_dir = NULL;
524 temp_dir_ret = mkdtemp(cinfo->temp_dir);
525 if (!temp_dir_ret || access(temp_dir_ret, F_OK)) {
526 _E("Failed to mkdtemp for temp_dir");
530 if (asprintf(&cinfo->name, "%s_%d_%s", basename(cinfo->cmd_line),
531 cinfo->pid_info, date) == -1) {
532 _E("Failed to snprintf for name");
538 ret = asprintf(&cinfo->result_path,
539 "%s/%s.zip", crash_crash_path, cinfo->name);
541 ret = asprintf(&cinfo->result_path,
542 "%s/%s", crash_crash_path, cinfo->name);
544 _E("Failed to asprintf for result path");
545 cinfo->result_path = NULL;
549 if (asprintf(&cinfo->pfx, "%s/%s", cinfo->temp_dir, cinfo->name) == -1) {
550 _E("Failed to asprintf for pfx");
554 ret = mkdir(cinfo->pfx, 0775);
556 _E("Failed to mkdir for %s", cinfo->pfx);
560 if (asprintf(&cinfo->info_path, "%s/%s.info", cinfo->pfx, cinfo->name) == -1) {
561 _E("Failed to asprintf for info path");
562 cinfo->info_path = NULL;
566 if (asprintf(&cinfo->core_path, "%s/%s.coredump", cinfo->pfx, cinfo->name) == -1) {
567 _E("Failed to asprintf for core path");
568 cinfo->core_path = NULL;
572 if (asprintf(&cinfo->log_path, "%s/%s.log", cinfo->pfx, cinfo->name) == -1) {
573 _E("Failed to asprintf for log path");
574 cinfo->log_path = NULL;
579 if (asprintf(&cinfo->sysassert_cs_path, "/tmp/crash_stack/%s_%d.info",
580 basename(cinfo->cmd_line), cinfo->pid_info) == -1) {
581 _E("Failed to snprintf for sys-assert callstack path");
582 cinfo->sysassert_cs_path = NULL;
586 if (set_prstatus(cinfo) < 0)
589 if (get_appid(cinfo->cmd_line, cinfo->appid, sizeof(cinfo->appid)) < 0) {
590 snprintf(cinfo->appid, sizeof(cinfo->appid), "%s", basename(cinfo->cmd_line));
591 snprintf(cinfo->pkgid, sizeof(cinfo->pkgid), "%s", basename(cinfo->cmd_line));
593 if (get_pkgid(cinfo->appid, cinfo->pkgid, sizeof(cinfo->pkgid)) < 0)
594 snprintf(cinfo->pkgid, sizeof(cinfo->pkgid), "%s", cinfo->appid);
600 remove_dir(cinfo->temp_dir, 1);
605 static int get_sysassert_cs(struct crash_info *cinfo)
608 char move_path[PATH_MAX];
610 if (access(cinfo->sysassert_cs_path, F_OK)) {
611 _E("The sys-assert cs file not found: %s",
612 cinfo->sysassert_cs_path);
613 cinfo->have_sysassert_report = 0;
616 cinfo->have_sysassert_report = 1;
618 ret = snprintf(move_path, sizeof(move_path), "%s/%s",
619 cinfo->pfx, basename(cinfo->sysassert_cs_path));
621 _E("Failed to snprintf for move path");
625 if (move_file(move_path, cinfo->sysassert_cs_path) < 0) {
626 _E("Failed to move %s to %s",
627 cinfo->sysassert_cs_path, move_path);
635 static void launch_crash_popup(struct crash_info *cinfo)
637 GDBusConnection *conn;
638 GVariantBuilder *builder;
639 GVariant *parameters = NULL;
640 GVariant *reply = NULL;
641 GError *error = NULL;
644 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
646 _E("Failed to get dbus: %s", error->message);
651 builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
652 g_variant_builder_add(builder, "{ss}", "_SYSPOPUP_CONTENT_", "crash");
653 g_variant_builder_add(builder, "{ss}", "_PROCESS_NAME_",
654 basename(cinfo->cmd_line));
655 g_variant_builder_add(builder, "{ss}", "_EXEPATH_", cinfo->cmd_path);
656 parameters = g_variant_new("(a{ss})", builder);
657 g_variant_builder_unref(builder);
659 reply = g_dbus_connection_call_sync(conn,
662 POPUP_INTERFACE_NAME,
665 G_VARIANT_TYPE("(i)"),
666 G_DBUS_CALL_FLAGS_NONE,
671 _E("Failed to get reply: %s", error->message);
676 g_variant_get(reply, "(i)", &ret);
677 _I("Crash_popup is launched: (%d)", ret);
681 g_variant_unref(reply);
683 g_variant_unref(parameters);
685 g_object_unref(conn);
688 static int dump_system_state(const struct crash_info *cinfo)
691 char command[PATH_MAX];
693 ret = snprintf(command, sizeof(command),
694 "/usr/bin/dump_systemstate -d -k -j -f '%s'",
697 _E("Failed to snprintf for dump_systemstate command");
701 return system_command_parallel(command);
704 static void save_so_info(const struct crash_info *cinfo)
706 char maps_path[PATH_MAX];
707 char so_info_path[PATH_MAX];
708 snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps",
711 snprintf(so_info_path, sizeof(so_info_path),
712 "%s/%s.%s", cinfo->pfx, cinfo->name, "so_info");
714 get_and_save_so_info(maps_path, so_info_path);
717 // These macros are used in execute_minicoredump() and execute_crash_stack()
718 #define SNPRINTF_OR_EXIT_W(name, format, member) if (snprintf(name##_str, sizeof(name##_str), format, cinfo->member) < 0) goto out;
719 #define SNPRINTF_OR_EXIT(name, format) SNPRINTF_OR_EXIT_W(name, format, name##_info)
721 static int execute_minicoredump(struct crash_info *cinfo)
723 char *coredump_name = NULL;
724 char *prstatus_fd_str = NULL;
727 if (asprintf(&coredump_name, "%s.coredump", cinfo->name) == -1
728 || asprintf(&prstatus_fd_str, "%d", cinfo->prstatus_fd) == -1) {
729 _E("Unable to allocate memory");
733 char pid_str[11], uid_str[11], gid_str[11], sig_str[11], time_str[11];
735 SNPRINTF_OR_EXIT(pid, "%d")
736 SNPRINTF_OR_EXIT(uid, "%d")
737 SNPRINTF_OR_EXIT(gid, "%d")
738 SNPRINTF_OR_EXIT(sig, "%d")
739 SNPRINTF_OR_EXIT(time, "%ld")
741 /* Execute minicoredumper */
743 MINICOREDUMPER_BIN_PATH, // minicoredumper filename path
747 sig_str, // %s - number of signal
748 time_str, // %t - time of dump
749 "localhost", // %h - hostname
750 "core", // %e - exe name (need for result filename)
751 MINICOREDUMPER_CONFIG_PATH, // config file
753 cinfo->pfx, // temp dir
755 coredump_name, // coredump filename
761 _D(" %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
762 args[0], args[1], args[2], args[3],
763 args[4], args[5], args[6], args[7],
764 args[8], args[9], args[10], args[11],
765 args[12], args[13], args[14]);
767 run_command_timeout(args[0], args, NULL, MINICOREDUMPER_TIMEOUT);
770 /* Minicoredumper must be executed to dump at least PRSTATUS for
771 other tools, coredump, however, might have been disabled. */
774 int errno_unlink = 0;
775 int dirfd = open(cinfo->pfx, O_DIRECTORY);
777 ret = unlinkat(dirfd, coredump_name, 0);
778 errno_unlink = errno;
780 errno = errno_unlink; /* for %m below */
784 _E("Saving core disabled - removing coredump %s/%s failed: %m",
785 cinfo->pfx, coredump_name);
787 _D("Saving core disabled - removed coredump %s/%s",
788 cinfo->pfx, coredump_name);
793 free(prstatus_fd_str);
798 static int execute_crash_stack(const struct crash_info *cinfo)
803 char pid_str[11], tid_str[11], sig_str[11], prstatus_fd_str[11];
805 SNPRINTF_OR_EXIT(pid, "%d")
806 SNPRINTF_OR_EXIT(tid, "%d")
807 SNPRINTF_OR_EXIT(sig, "%d")
808 SNPRINTF_OR_EXIT_W(prstatus_fd, "%d", prstatus_fd)
810 /* Execute crash-stack */
824 _D(" %s %s %s %s %s %s %s %s %s",
825 args[0], args[1], args[2], args[3],
826 args[4], args[5], args[6], args[7], args[8]);
828 fd = open(cinfo->info_path, O_WRONLY | O_CREAT, 0600);
830 _E("open %s error: %m", cinfo->info_path);
834 ret = run_command_write_fd_timeout(CRASH_STACK_PATH, args, NULL, fd, NULL, 0, CRASH_STACK_TIMEOUT);
843 #undef SNPRINTF_OR_EXIT
844 #undef SNPRINTF_OR_EXIT_W
846 static int execute_crash_modules(struct crash_info *cinfo)
848 _D("Execute crash module: ");
850 if (execute_minicoredump(cinfo) < 0) {
851 _E("Failed to run minicoredumper - can not continue");
856 /* Use process_vm_readv() version as fallback if sys-assert
857 * failed to generate report */
858 if (cinfo->have_sysassert_report)
861 execute_crash_stack(cinfo);
866 static int lock_dumpdir(void)
870 if ((fd = open(crash_crash_path, O_RDONLY | O_DIRECTORY)) < 0) {
871 _E("Failed to open %s", crash_crash_path);
875 if (flock(fd, LOCK_EX) < 0) {
876 _E("Failed to flock (LOCK)");
884 static void unlock_dumpdir(int fd)
886 if (flock(fd, LOCK_UN) < 0)
887 _E("Failed to unlink (UNLOCK)");
891 static int dump_filter(const struct dirent *de)
893 if (de->d_name[0] == '.')
898 static int mtime_cmp(const void *_a, const void *_b)
900 const struct file_info *a = _a;
901 const struct file_info *b = _b;
903 if (a->mtime < b->mtime)
905 if (a->mtime > b->mtime)
910 static int scan_dump(struct file_info **dump_list, off_t *usage)
912 struct file_info *temp_list;
913 struct dirent **scan_list = NULL;
915 int i, scan_num, dump_num = 0;
918 if ((fd = open(crash_crash_path, O_DIRECTORY)) < 0) {
919 _E("Failed to open %s", crash_crash_path);
923 scan_num = scandir(crash_crash_path, &scan_list, &dump_filter, NULL);
929 temp_list = (struct file_info *)calloc(scan_num,
930 sizeof(struct file_info));
932 _E("Failed to calloc for dump list");
936 for (i = 0; i < scan_num; i++) {
937 if (fstatat(fd, scan_list[i]->d_name, &st, 0) < 0) {
938 _E("Failed to fstatat");
942 if (asprintf(&(temp_list[dump_num].path), "%s/%s",
943 crash_crash_path, scan_list[i]->d_name) < 0) {
944 _E("Failed to asprintf");
948 if (scan_list[i]->d_type == DT_DIR) {
949 temp_list[dump_num].isdir = 1;
950 temp_list[dump_num].size =
951 get_directory_usage(temp_list[dump_num].path);
953 temp_list[dump_num].isdir = 0;
954 temp_list[dump_num].size = st.st_size;
956 temp_list[dump_num].mtime = st.st_mtime;
965 if (dump_num != scan_num) {
966 struct file_info *const tmp = (struct file_info *)realloc(temp_list,
967 dump_num * sizeof(struct file_info));
976 qsort(temp_list, dump_num, sizeof(struct file_info), mtime_cmp);
979 for (i = 0; i < dump_num; i++) {
980 _D("[%d] path: %s(%s), size: %zu kb, mtime: %s",
983 temp_list[i].isdir ? "DIR" : "FILE",
984 temp_list[i].size / 1024,
985 ctime(&(temp_list[i].mtime)));
986 *usage += temp_list[i].size;
988 *dump_list = temp_list;
990 for (i = 0; i < scan_num; i++)
998 static int check_disk_available(const char *path, int check_size)
1000 struct statfs lstatfs;
1006 if (statfs(path, &lstatfs) < 0)
1008 avail_size = (int)(lstatfs.f_bavail * (lstatfs.f_bsize / 1024));
1010 if (check_size > avail_size) {
1011 _I("avail_size is (%d)", avail_size);
1018 static int remove_file(struct file_info file)
1021 return remove_dir(file.path, 1);
1023 return unlink(file.path);
1026 static void clean_dump(void)
1028 struct file_info *dump_list = NULL;
1029 int i, scan_num, dump_num, remove_flag;
1033 scan_num = scan_dump(&dump_list, &usage);
1037 dump_num = scan_num;
1039 cur_time = time(NULL);
1041 for (i = 0; i < scan_num; i++) {
1044 /* Retention time check */
1045 if (max_retention_sec &&
1046 dump_list[i].mtime > 0 &&
1047 dump_list[i].mtime + max_retention_sec < cur_time)
1048 remove_flag = RET_EXCEED;
1049 /* Check the number of dumps */
1050 else if (max_crash_dump &&
1051 0 < dump_num && max_crash_dump < dump_num)
1052 remove_flag = NUM_EXCEED;
1053 /* Check the max system use size */
1054 else if (system_max_use &&
1055 0 < dump_num && system_max_use < usage / 1024)
1056 remove_flag = USAGE_EXCEED;
1058 switch (remove_flag) {
1060 _I("Reached the maximum retention time %d, so remove (%s)",
1061 max_retention_sec, dump_list[i].path);
1064 _I("Reached the maximum number of dump %d/%d, so remove (%s)",
1065 dump_num, max_crash_dump,
1069 _I("Reached the maximum disk usage %" PRId64 "/%d kb, so remove (%s)",
1070 usage / 1024, system_max_use,
1080 if (remove_file(dump_list[i]) < 0) {
1081 _E("Failed to remove %s", dump_list[i].path);
1085 usage -= dump_list[i].size;
1088 /* Check disk free space to keep */
1089 if (system_keep_free &&
1090 check_disk_available(crash_root_path,
1091 system_keep_free) < 0) {
1092 _I("Disk is not available! so set the maximum number of dump to 1");
1096 for (i = 0; i < dump_num; i++)
1097 free(dump_list[i].path);
1101 static void compress(struct crash_info *cinfo)
1104 char zip_path[PATH_MAX];
1107 ret = snprintf(zip_path, sizeof(zip_path), "%s/report.zip",
1110 _E("Failed to snprintf for zip path");
1114 if (getcwd(cwd, sizeof(cwd)) == NULL) {
1115 _E("getcwd() error: %m\n");
1119 if (chdir(cinfo->temp_dir) == -1) {
1120 _E("chdir() to %s error: %m\n", cinfo->temp_dir);
1133 run_command_timeout(args[0], args, NULL, ZIP_TIMEOUT);
1135 if (chdir(cwd) == -1) {
1136 _E("chdir() to %s error: %m\n", cwd);
1140 if ((lock_fd = lock_dumpdir()) < 0)
1142 if (!rename(zip_path, cinfo->result_path))
1145 _E("Failed to move %s to %s", zip_path, cinfo->result_path);
1146 unlock_dumpdir(lock_fd);
1148 if (remove_dir(cinfo->temp_dir, 1) < 0)
1149 _E("Failed to delete temp directory");
1152 static void move_dump_data(const char *from_path, const struct crash_info *cinfo)
1156 if ((lock_fd = lock_dumpdir()) < 0)
1158 if (!rename(from_path, cinfo->result_path))
1161 _E("Failed to move %s to %s",
1162 from_path, cinfo->result_path);
1163 unlock_dumpdir(lock_fd);
1165 if (remove_dir(cinfo->temp_dir, 1) < 0)
1166 _E("Failed to delete temp directory");
1169 static int wait_for_opt(unsigned int timeout)
1171 unsigned int count = 0;
1173 while (check_disk_available(crash_root_path, 0) < 0 && count < timeout) {
1174 log_kmsg("crash-manager: path %s is not available\n", crash_root_path);
1178 if (count >= timeout) {
1179 log_kmsg("crash-manager: timeout (%ds) while waiting for %s."
1180 "Probably /opt is not mounted.\n", timeout, crash_root_path);
1187 static void free_crash_info(struct crash_info *cinfo)
1189 free(cinfo->cmd_line);
1190 free(cinfo->cmd_path);
1191 free(cinfo->temp_dir);
1192 free(cinfo->result_path);
1194 free(cinfo->info_path);
1195 free(cinfo->core_path);
1196 free(cinfo->log_path);
1199 free(cinfo->sysassert_cs_path);
1203 int main(int argc, char *argv[])
1205 struct crash_info cinfo = {.prstatus_fd = -1};
1207 /* Execute dump_systemstate in parallel */
1208 static int dump_state_pid;
1209 int debug_mode = access(DEBUGMODE_PATH, F_OK) == 0;
1213 * prctl(PR_SET_DUMPABLE, 0) is not neccessary. Kernel runs the
1214 * crash-manager and sets RLIMIT_CORE to 1 for the process. This is special
1215 * value that prevents from running crash-manager recursively.
1218 /* Get Configuration */
1219 if (get_config() < 0) {
1225 if (!prepare_paths()) {
1230 if (!wait_for_opt(WAIT_FOR_OPT_TIMEOUT_SEC)) {
1235 /* Create crash directories */
1236 if (make_dump_dir() < 0) {
1241 /* Set crash info */
1242 if (set_crash_info(&cinfo, argc, argv) < 0) {
1248 /* Fetch callstack of sys-assert */
1249 get_sysassert_cs(&cinfo);
1252 if (report_type >= REP_TYPE_FULL) {
1253 /* Exec dump_systemstate */
1254 dump_state_pid = dump_system_state(&cinfo);
1256 if (dump_state_pid < 0) {
1261 /* Exec crash modules */
1262 if (execute_crash_modules(&cinfo) < 0) {
1267 if (report_type >= REP_TYPE_FULL) {
1268 /* Save shared objects info (file names, bulid IDs, rpm package names) */
1269 save_so_info(&cinfo);
1271 /* Wait dump_system_state */
1272 wait_system_command(dump_state_pid);
1274 /* Tar compression */
1278 move_dump_data(cinfo.pfx, &cinfo);
1280 free(cinfo.result_path);
1281 if (asprintf(&cinfo.result_path, "%s/%s.info",
1282 crash_crash_path, cinfo.name) == -1) {
1283 cinfo.result_path = NULL;
1284 _E("asprintf() error: %m");
1288 move_dump_data(cinfo.info_path, &cinfo);
1291 struct NotifyParams notify_params = {
1292 .prstatus_fd = cinfo.prstatus_fd,
1293 .pid = cinfo.pid_info,
1294 .tid = cinfo.tid_info,
1295 .cmd_name = basename(cinfo.cmd_line),
1296 .cmd_path = cinfo.cmd_path,
1297 .report_path = cinfo.result_path,
1298 .appid = cinfo.appid,
1299 .pkgid = cinfo.pkgid
1302 send_notify(¬ify_params);
1304 /* Release the core pipe as passed by kernel, allowing another
1305 * coredump to be handled.
1307 * Due to usage of core_pipe_limit there is limited number of
1308 * crash-manager processes that kernel is going to invoke
1309 * concurrently. As the next and last step is a _synchronous_
1310 * call to crash-popup we close the descriptor here.
1312 * Note: for VIP processes this will likely cause the system
1313 * to reboot without showing popup.
1315 close(STDIN_FILENO);
1317 /* launch crash-popup only if the .debugmode file exists */
1319 launch_crash_popup(&cinfo);
1322 if (cinfo.prstatus_fd >= 0)
1323 close(cinfo.prstatus_fd);
1324 free(crash_temp_path);
1325 free(crash_root_path);
1326 free(crash_crash_path);
1328 free_crash_info(&cinfo);