#include "defs.h"
#include "dbus_notify.h"
#include "shared/log.h"
+#include "shared/config.h"
#include "shared/spawn.h"
#include "shared/util.h"
#include "so-info.h"
/* Parsing */
#define KEY_MAX 255
-#define CRASH_SECTION "CrashManager"
/* Crash-popup dbus */
#define POPUP_BUS_NAME "org.tizen.system.popup"
#define POPUP_INTERFACE_NAME POPUP_BUS_NAME".Crash"
#define POPUP_METHOD "PopupLaunch"
-/* Configuration default values */
-/* note: 0 means unlimited */
-#define SYSTEM_MAX_USE 0
-#define SYSTEM_KEEP_FREE 0
-#define MAX_RETENTION_SEC 0
-#define MAX_CRASH_DUMP 0
-#define DUMP_CORE 1
-#define ALLOW_ZIP true
-
#define APPID_MAX 128
#define PKGNAME_MAX 128
USAGE_EXCEED
};
-enum {
- REP_TYPE_INFO = 0,
- REP_TYPE_FULL
-};
-
-#define REP_DEFAULT_TYPE REP_TYPE_FULL
-
-#define REP_TYPE_FULL_STR "FULL"
-#define REP_TYPE_INFO_STR "INFO"
-
struct file_info {
bool isdir;
size_t size;
};
/* Configuration variables */
-static int system_max_use;
-static int system_keep_free;
-static int max_retention_sec;
-static int max_crash_dump;
-static int dump_core;
-static bool allow_zip;
-static char* crash_root_path;
+config_t config;
static char* crash_crash_path;
static char* crash_temp_path;
-static int report_type;
/* Paths and variables */
struct crash_info {
static int prepare_paths(void)
{
int tmp_len;
- tmp_len = strlen(crash_root_path) + strlen(CRASH_PATH_SUBDIR);
+ tmp_len = strlen(config.crash_root_path) + strlen(CRASH_PATH_SUBDIR);
crash_crash_path = (char*)malloc(tmp_len + 1);
if (crash_crash_path == NULL) {
_E("Couldn't allocate memory for crash_crash_path: %m\n");
return 0;
}
- snprintf(crash_crash_path, tmp_len + 1, "%s%s", crash_root_path, CRASH_PATH_SUBDIR);
+ snprintf(crash_crash_path, tmp_len + 1, "%s%s", config.crash_root_path, CRASH_PATH_SUBDIR);
- tmp_len = strlen(crash_root_path) + strlen(CRASH_TEMP_SUBDIR);
+ tmp_len = strlen(config.crash_root_path) + strlen(CRASH_TEMP_SUBDIR);
crash_temp_path = (char*)malloc(tmp_len + 1);
if (crash_temp_path == NULL) {
_E("Couldn't allocate memory for crash_temp_path: %m\n");
return 0;
}
- snprintf(crash_temp_path, tmp_len + 1, "%s%s", crash_root_path, CRASH_TEMP_SUBDIR);
+ snprintf(crash_temp_path, tmp_len + 1, "%s%s", config.crash_root_path, CRASH_TEMP_SUBDIR);
return 1;
}
-static const char* report_type_to_str(const int report_type)
-{
- switch (report_type) {
- case REP_TYPE_INFO:
- return REP_TYPE_INFO_STR;
- break;
- case REP_TYPE_FULL:
- return REP_TYPE_FULL_STR;
- default:
- return NULL;
- break;
- }
-}
-
-static int report_type_from_str(const char* report_type_str)
-{
- if (report_type_str == NULL)
- return -1;
-
- if (strncmp(report_type_str, REP_TYPE_FULL_STR, strlen(REP_TYPE_FULL_STR)) == 0)
- return REP_TYPE_FULL;
- else if (strncmp(report_type_str, REP_TYPE_INFO_STR, strlen(REP_TYPE_INFO_STR)) == 0)
- return REP_TYPE_INFO;
-
- return -1;
-}
-
-static int get_config(void)
-{
- dictionary *ini = NULL;
- char key[KEY_MAX];
- int value;
- int result = 1;
- char *value_str;
-
- system_max_use = SYSTEM_MAX_USE;
- system_keep_free = SYSTEM_KEEP_FREE;
- max_retention_sec = MAX_RETENTION_SEC;
- max_crash_dump = MAX_CRASH_DUMP;
- dump_core = DUMP_CORE;
- allow_zip = ALLOW_ZIP;
- crash_root_path = strdup(CRASH_ROOT_PATH);
- if (crash_root_path == NULL) {
- _E("strdup error: %m\n");
- return -1;
- }
- report_type = REP_DEFAULT_TYPE;
-
- ini = iniparser_load(CRASH_MANAGER_CONFIG_PATH);
- if (!ini) {
- _E("Failed to load conf file %s", CRASH_MANAGER_CONFIG_PATH);
- return 0;
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "SystemMaxUse");
- value = iniparser_getint(ini, key, -1);
- if (value < 0) {
- _D("Invalid value for SystemMaxUse. Use default value [ %d kbyte]",
- SYSTEM_MAX_USE);
- } else {
- _D("SystemMaxUse [ %d kbyte]", value);
- system_max_use = value;
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "SystemKeepFree");
- value = iniparser_getint(ini, key, -1);
- if (value < 0) {
- _D("Invalid value for SystemKeepFree. Use default value [ %d kbyte]",
- SYSTEM_KEEP_FREE);
- } else {
- _D("SystemKeepFree [ %d kbyte]", value);
- system_keep_free = value;
- }
-
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "MaxRetentionSec");
- value = iniparser_getint(ini, key, -1);
- if (value < 0) {
- _D("Invalid value for MaxRetentionSec. Use default value [ %d ]",
- MAX_RETENTION_SEC);
- } else {
- _D("MaxRetentionSec [ %d ]", value);
- max_retention_sec = value;
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "MaxCrashDump");
- value = iniparser_getint(ini, key, -1);
- if (value < 0) {
- _D("Invalid value for MaxCrashDump. Use default value [ %d ]",
- MAX_CRASH_DUMP);
- } else {
- _D("MaxCrashDump [ %d ]", value);
- max_crash_dump = value;
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "DumpCore");
- value = iniparser_getint(ini, key, -1);
- if (value != 0 && value != 1) {
- _D("Invalid value for DumpCore default value [ %d ]",
- DUMP_CORE);
- } else {
- _D("DumpCore [ %d ]", value);
- dump_core = value;
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "AllowZip");
- value = iniparser_getboolean(ini, key, -1);
- if (value < 0) {
- _D("Invalid value for AllowZip. Use default value [ %s ]",
- ALLOW_ZIP ? "true" : "false");
- } else {
- _D("AllowZip [ %s ]", value ? "true" : "false");
- allow_zip = value;
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "CrashRootPath");
- value_str = iniparser_getstring(ini, key, NULL);
- if (value_str == NULL) {
- _D("Invalid value for CrashRootPath. Use default value [ %s ]",
- CRASH_ROOT_PATH);
- } else {
- _D("CrashRootPath [ %s ]", value_str);
- free(crash_root_path);
- crash_root_path = strdup(value_str);
- if (crash_root_path == NULL) {
- _E("strdup error: %m\n");
- result = -1;
- goto out;
- }
- }
-
- snprintf(key, sizeof(key), "%s:%s", CRASH_SECTION, "ReportType");
- value_str = iniparser_getstring(ini, key, NULL);
- if (value_str == NULL) {
- _D("Invalid value for ReportType. Use default value [ %s ]",
- report_type_to_str(report_type));
- } else {
- _D("ReportType [ %s ]", value_str);
- report_type = report_type_from_str(value_str);
-
- if (report_type < 0) {
- _E("Unknown ReportType %s. Fallback to default: %s",
- value_str, report_type_to_str(REP_DEFAULT_TYPE));
- report_type = REP_DEFAULT_TYPE;
- }
- }
-
-out:
- iniparser_freedict(ini);
- return result;
-}
-
static int make_dump_dir(void)
{
struct stat st;
goto rm_temp;
}
- if (allow_zip)
+ if (config.allow_zip)
ret = asprintf(&cinfo->result_path,
"%s/%s.zip", crash_crash_path, cinfo->name);
else
/* Minicoredumper must be executed to dump at least PRSTATUS for
other tools, coredump, however, might have been disabled. */
- if (!dump_core) {
+ if (!config.dump_core) {
if (remove_file_in_dir(cinfo->pfx, coredump_name) != 0)
_E("Saving core disabled - removing coredump %s/%s failed: %m",
cinfo->pfx, coredump_name);
remove_flag = 0;
/* Retention time check */
- if (max_retention_sec &&
+ if (config.max_retention_sec &&
dump_list[i].mtime > 0 &&
- dump_list[i].mtime + max_retention_sec < cur_time)
+ dump_list[i].mtime + config.max_retention_sec < cur_time)
remove_flag = RET_EXCEED;
/* Check the number of dumps */
- else if (max_crash_dump &&
- 0 < dump_num && max_crash_dump < dump_num)
+ else if (config.max_crash_dump &&
+ 0 < dump_num && config.max_crash_dump < dump_num)
remove_flag = NUM_EXCEED;
/* Check the max system use size */
- else if (system_max_use &&
- 0 < dump_num && system_max_use < usage / 1024)
+ else if (config.system_max_use &&
+ 0 < dump_num && config.system_max_use < usage / 1024)
remove_flag = USAGE_EXCEED;
switch (remove_flag) {
case RET_EXCEED:
_I("Reached the maximum retention time %d, so remove (%s)",
- max_retention_sec, dump_list[i].path);
+ config.max_retention_sec, dump_list[i].path);
break;
case NUM_EXCEED:
_I("Reached the maximum number of dump %d/%d, so remove (%s)",
- dump_num, max_crash_dump,
+ dump_num, config.max_crash_dump,
dump_list[i].path);
break;
case USAGE_EXCEED:
_I("Reached the maximum disk usage %" PRId64 "/%d kb, so remove (%s)",
- usage / 1024, system_max_use,
+ usage / 1024, config.system_max_use,
dump_list[i].path);
break;
default:
}
/* Check disk free space to keep */
- if (system_keep_free &&
- check_disk_available(crash_root_path,
- system_keep_free) < 0) {
+ if (config.system_keep_free &&
+ check_disk_available(config.crash_root_path,
+ config.system_keep_free) < 0) {
_I("Disk is not available! so set the maximum number of dump to 1");
- max_crash_dump = 1;
+ config.max_crash_dump = 1;
}
for (i = 0; i < dump_num; i++)
{
unsigned int count = 0;
- while (check_disk_available(crash_root_path, 0) < 0 && count < timeout) {
- log_kmsg("crash-manager: path %s is not available\n", crash_root_path);
+ while (check_disk_available(config.crash_root_path, 0) < 0 && count < timeout) {
+ log_kmsg("crash-manager: path %s is not available\n", config.crash_root_path);
sleep(1);
count++;
}
if (count >= timeout) {
log_kmsg("crash-manager: timeout (%ds) while waiting for %s."
- "Probably /opt is not mounted.\n", timeout, crash_root_path);
+ "Probably /opt is not mounted.\n", timeout, config.crash_root_path);
return 0;
}
* value that prevents from running crash-manager recursively.
*/
- /* Get Configuration */
- if (get_config() < 0) {
+ if (!config_init(&config, CRASH_MANAGER_CONFIG_PATH)) {
res = EXIT_FAILURE;
goto exit;
}
- /* Prepare paths */
if (!prepare_paths()) {
res = EXIT_FAILURE;
goto exit;
get_sysassert_cs(&cinfo);
#endif
- if (report_type >= REP_TYPE_FULL) {
+ if (config.report_type >= REP_TYPE_FULL) {
/* Exec dump_systemstate */
if (!dump_system_state(&cinfo, &dump_state_pid)) {
res = EXIT_FAILURE;
goto exit;
}
- if (report_type >= REP_TYPE_FULL) {
+ if (config.report_type >= REP_TYPE_FULL) {
/* Save shared objects info (file names, bulid IDs, rpm package names) */
save_so_info(&cinfo);
wait_for_pid(dump_state_pid, NULL);
/* Tar compression */
- if (allow_zip)
+ if (config.allow_zip)
compress(&cinfo);
else
move_dump_data(cinfo.pfx, &cinfo);
if (cinfo.prstatus_fd >= 0)
close(cinfo.prstatus_fd);
free(crash_temp_path);
- free(crash_root_path);
free(crash_crash_path);
+ config_free(&config);
free_crash_info(&cinfo);
--- /dev/null
+/*
+ * crash-manager
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <assert.h>
+#include <iniparser.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "defs.h"
+#include "log.h"
+#include "util.h"
+
+static const char *const report_type_strmap[] = {
+ [REP_TYPE_INFO] = "INFO",
+ [REP_TYPE_FULL] = "FULL",
+};
+
+static const char *report_type_to_str(enum ReportType report_type)
+{
+ if (report_type < 0 || report_type >= ARRAY_SIZE(report_type_strmap))
+ return NULL;
+ return report_type_strmap[report_type];
+}
+
+enum ReportType report_type_from_str(const char *report_type_str)
+{
+ assert(report_type_str);
+
+ for (int i = 0; i < (int)ARRAY_SIZE(report_type_strmap); i++) {
+ if (0 == strcmp(report_type_str, report_type_strmap[i]))
+ return (enum ReportType)i;
+ }
+
+ return REP_TYPE_INVALID;
+}
+
+bool config_init(config_t *c, const char *const path)
+{
+ assert(c);
+ assert(path);
+
+ dictionary *ini = iniparser_load(path);
+ if (!ini) {
+ _E("Failed to load config file %s", path);
+ return false;
+ }
+
+ bool ret = false;
+
+#define GET(type, key, defval) iniparser_get##type(ini, CRASH_SECTION ":" key, defval)
+
+ c->crash_root_path = strdup(GET(string, "CrashRootPath", CRASH_ROOT_PATH));
+ if (!c->crash_root_path)
+ goto out;
+
+ char *reptype = GET(string, "ReportType", (char *)report_type_strmap[REP_TYPE_FULL]);
+ c->report_type = report_type_from_str(reptype);
+ if (!report_type_to_str(c->report_type))
+ goto out;
+
+ c->system_max_use = GET(int, "SystemMaxUse", SYSTEM_MAX_USE);
+ c->system_keep_free = GET(int, "SystemKeepFree", SYSTEM_KEEP_FREE);
+ c->max_retention_sec = GET(int, "MaxRetentionSec", SYSTEM_MAX_USE);
+ c->max_crash_dump = GET(int, "MaxCrashDump", MAX_CRASH_DUMP);
+ c->dump_core = GET(boolean, "DumpCore", DUMP_CORE);
+ c->allow_zip = GET(boolean, "AllowZip", ALLOW_ZIP);
+
+#undef GET
+
+ ret = true;
+out:
+ iniparser_freedict(ini);
+ return ret;
+}
+
+void config_free(config_t *c)
+{
+ assert(c);
+
+ free(c->crash_root_path);
+}