3 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 #include <iniparser.h>
24 #include <sys/types.h>
32 static const char *const report_type_strmap[] = {
33 [REP_TYPE_INFO] = "INFO",
34 [REP_TYPE_FULL] = "FULL",
37 static const char *report_type_to_str(enum ReportType report_type)
39 if (report_type < 0 || report_type >= ARRAY_SIZE(report_type_strmap))
41 return report_type_strmap[report_type];
44 enum ReportType report_type_from_str(const char *report_type_str)
46 assert(report_type_str);
48 for (int i = 0; i < (int)ARRAY_SIZE(report_type_strmap); i++) {
49 if (0 == strcasecmp(report_type_str, report_type_strmap[i]))
50 return (enum ReportType)i;
53 return REP_TYPE_INVALID;
56 static int config_load_exclude_paths(config_t *c, dictionary *ini)
61 int n = iniparser_getsecnkeys(ini, EXCLUDEPATHS_SECTION);
62 _D("config: Found %d entries in " EXCLUDEPATHS_SECTION, n);
66 char **keys = alloca(sizeof(char *) * n);
67 int total = n + c->n_exclude_paths;
70 c->exclude_paths = realloc(c->exclude_paths, sizeof(char *) * total);
72 if (!keys || !c->exclude_paths)
75 keys = iniparser_getseckeys(ini, EXCLUDEPATHS_SECTION);
79 for (int i = c->n_exclude_paths, j = 0; i < total; i++, j++) {
80 const char *const str = iniparser_getstring(ini, keys[j], NULL);
84 _D("config: Adding <%s> to exclude paths list", str);
85 c->exclude_paths[i] = strdup(str);
86 if (!c->exclude_paths[i])
88 c->n_exclude_paths += 1;
94 _E("Out of memory. ExcludePaths configuration not loaded.");
98 bool config_is_path_excluded(config_t *c, const char *const path)
103 for (int i = 0; i < c->n_exclude_paths; i++) {
104 if (strcmp(path, c->exclude_paths[i]) == 0) {
105 _I("Found match on exclude paths list: %s", path);
112 static bool config_load_from_dict(config_t *c, dictionary *ini)
117 const char *str = iniparser_getstring(ini, CRASH_SECTION ":CrashRootPath", NULL);
119 char *crash_root_path = strdup(str);
120 if (!crash_root_path) {
121 _E("config: Unable to set CrashRootPath - aborting");
125 free(c->crash_root_path);
126 c->crash_root_path = crash_root_path;
129 /* strdup() can technically fail, but we don't mind. It is better to
130 * create a report without the extra script than to abort completely. */
131 str = iniparser_getstring(ini, CRASH_SECTION ":ExtraScript", NULL);
133 char *extra_script = strdup(str);
135 free(c->extra_script);
136 c->extra_script = extra_script;
138 _W("Out of memory. ExtraScript will not be executed.");
141 str = iniparser_getstring(ini, CRASH_SECTION ":ReportType", NULL);
143 int type = report_type_from_str(str);
144 if (report_type_to_str(type))
145 c->report_type = type;
148 #define UPDATE(where, type, key) where = iniparser_get##type(ini, CRASH_SECTION ":" key, where)
150 UPDATE(c->system_max_use, int, "SystemMaxUse");
151 UPDATE(c->max_retention_sec, int, "MaxRetentionSec");
152 UPDATE(c->max_crash_dump, int, "MaxCrashDump");
153 UPDATE(c->dump_core, boolean, "DumpCore");
154 UPDATE(c->dump_so_info, boolean, "DumpSharedObjectInfo");
155 UPDATE(c->allow_zip, boolean, "AllowZip");
156 UPDATE(c->legacy_notification, boolean, "UseLegacyNotification");
160 config_load_exclude_paths(c, ini);
165 static bool config_load_from_path(config_t *c, const char *const path)
169 dictionary *ini = iniparser_load(path);
171 _E("Failed to load config file %s", path);
175 bool ret = config_load_from_dict(c, ini);
176 iniparser_freedict(ini);
181 static int entry_filter(const struct dirent *e)
185 const char *const conf_suffix = ".conf";
186 const char *const name = e->d_name;
187 int len = strlen(name);
189 if (e->d_type != DT_REG || len <= strlen(conf_suffix))
192 // accept only files ending with predefined suffix
193 return strcmp(name + len - strlen(conf_suffix), conf_suffix) == 0;
196 static bool config_load_from_dir_prefix(config_t *c, const char *const dir_prefix)
200 char dir_path[PATH_MAX];
201 int ret = snprintf(dir_path, sizeof(dir_path), "%s.d", dir_prefix);
202 if (ret < 0 || ret >= PATH_MAX) {
203 _W("config: internal error while trying to prepare config dir path");
207 int fd = open(dir_path, O_RDONLY | O_DIRECTORY);
208 if (fd < 0 && errno == ENOENT)
211 _E("config: Unable to access config directory at %s: %m", dir_path);
215 struct dirent **entries = NULL;
216 int n = scandirat(fd, ".", &entries, entry_filter, alphasort);
220 for (int i = 0; i < n; ++i) {
221 char file_path[PATH_MAX];
222 const char *fname = entries[i]->d_name;
223 ret = snprintf(file_path, sizeof(file_path), "%s/%s", dir_path, fname);
224 if (ret < 0 || ret >= PATH_MAX) {
225 _W("config: internal error while trying to prepare for reading %s config file", fname);
228 _D("config: reading additional configuration file from %s", file_path);
229 (void)config_load_from_path(c, file_path);
238 static bool config_apply_defaults(config_t *c)
242 memset(c, 0, sizeof(*c));
244 c->crash_root_path = strdup(CRASH_ROOT_PATH);
245 c->report_type = REP_TYPE_FULL;
246 c->system_max_use = SYSTEM_MAX_USE;
247 c->system_keep_free = SYSTEM_KEEP_FREE;
248 c->max_retention_sec = MAX_RETENTION_SEC;
249 c->max_crash_dump = MAX_CRASH_DUMP;
250 c->dump_core = DUMP_CORE;
251 c->dump_so_info = DUMP_SO_INFO;
252 c->allow_zip = ALLOW_ZIP;
253 c->legacy_notification = LEGACY_NOTIFICATION;
255 return c->crash_root_path != NULL;
258 static void config_dump(config_t *c)
262 _D("config: crash_root_path = %s\n"
263 "config: extra_script = %s\n"
264 "config: report_type = %s\n"
265 "config: system_max_use = %d\n"
266 "config: system_keep_free = %d\n"
267 "config: max_retention_sec = %d\n"
268 "config: max_crash_dump = %d\n"
269 "config: dump_core = %d\n"
270 "config: dump_so_info = %d\n"
271 "config: allow_zip = %d\n"
272 "config: legacy_notification = %d\n",
275 report_type_to_str(c->report_type),
278 c->max_retention_sec,
283 c->legacy_notification);
286 bool config_init(config_t *c, const char *const path)
288 if (!config_apply_defaults(c) || !config_load_from_path(c, path)) {
289 _E("config: Unable to initialize configuration");
293 (void)config_load_from_dir_prefix(c, path);
300 void config_free(config_t *c)
304 free(c->crash_root_path);
305 free(c->extra_script);
306 for (int i = 0; i < c->n_exclude_paths; i++)
307 free(c->exclude_paths[i]);
308 free(c->exclude_paths);
310 memset(c, 0, sizeof(*c));