4 * Copyright (c) 2012 - 2013 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/statfs.h>
29 #include <sys/types.h>
32 #include <Ecore_File.h>
34 #include "core/launch.h"
35 #include "core/devices.h"
37 #define CRASH_PID_MAX 7
38 #define CRASH_MODE_MAX 2
39 #define CRASH_TIME_MAX 65
40 #define CRASH_POPUP_ON 1
41 #define CRASH_POPUP_OFF 0
42 #define CRASH_CHECK_SIZE (512 * 1024)
43 #define CRASH_CHECK_DISK_PATH "/opt/usr"
44 #define CRASH_LIMIT_NUM 5
45 #define CRASH_ARG_NUM 6
46 #define CRASH_DELIMITER "|"
47 #define CRASH_VERIFY_MAX 5
48 #define CRASH_PROCESSNAME_MAX NAME_MAX
49 #define CRASH_EXEPATH_MAX NAME_MAX
50 #define CRASH_ARG_MAX (CRASH_PROCESSNAME_MAX + CRASH_EXEPATH_MAX + CRASH_TIME_MAX + CRASH_PID_MAX + CRASH_MODE_MAX + CRASH_VERIFY_MAX)
51 #define CRASH_NOTI_DIR "/opt/share/crash"
52 #define CRASH_NOTI_FILE "curbs.log"
53 #define CRASH_NOTI_PATH CRASH_NOTI_DIR"/"CRASH_NOTI_FILE
54 #define CRASH_COREDUMP_PATH "/opt/usr/share/crash/core"
55 #define CRASH_DUMP_PATH "/opt/usr/share/crash/dump"
56 #define CRASH_INFO_PATH "/opt/share/crash/info"
57 #define CRASH_WORKER_PATH "/usr/bin/crash-worker"
58 #define CRASH_POPUP_PATH "/usr/apps/org.tizen.crash-popup/bin/crash-popup"
61 static int add_noti(void);
64 char crash_mode[CRASH_MODE_MAX];
65 char crash_processname[CRASH_PROCESSNAME_MAX];
66 char crash_timestr[CRASH_TIME_MAX];
67 char crash_pid[CRASH_PID_MAX];
68 char crash_exepath[CRASH_EXEPATH_MAX];
69 char crash_verify[CRASH_VERIFY_MAX];
72 static int is_running_process(pid_t pid)
74 char buf[PATH_MAX + 1];
75 snprintf(buf, sizeof(buf), "/proc/%d", pid);
76 if (!access(buf, R_OK))
80 static int make_noti_file(const char *path, const char *file)
85 struct group *group_entry;
88 snprintf(buf, sizeof(buf), "%s/%s", path, file); /* buf - full path to file */
89 if (access(buf, F_OK) == 0) /* if file exists then return -1 */
92 /* save old mask and set new calling process's file mode creation mask */
95 mkdir(path, 0775); /* make directory, if exest then errno==EEXIST */
96 group_entry = getgrnam("crash"); /* need to find out group ID of "crash" group name */
97 if (group_entry == NULL) {
98 umask(old_mask); /* restore old file mask */
101 chown(path, 0, group_entry->gr_gid); /* chown root:crash */
102 if ((fd = open(buf, O_CREAT, 0666)) < 0) { /* create crash file */
103 umask(old_mask); /* restore old file mask */
106 fchown(fd, 0, group_entry->gr_gid); /* chown root:crash */
108 umask(old_mask); /* restore old file mask */
112 static int make_coredump_dir(void)
116 struct group *group_entry;
118 if (access(CRASH_COREDUMP_PATH, F_OK) == 0) /* if file exists then return -1 */
121 /* save old mask and set new calling process's file mode creation mask */
124 mkdir(CRASH_COREDUMP_PATH, 0775); /* make directory, if exest then errno==EEXIST */
125 group_entry = getgrnam("crash"); /* need to find out group ID of "crash" group name*/
126 if (group_entry == NULL) {
127 umask(old_mask); /* restore old file mask */
130 chown(CRASH_COREDUMP_PATH, 0, group_entry->gr_gid); /* chown root:crash */
131 umask(old_mask); /* restore old file mask */
135 static int make_info_dir(void)
139 struct group *group_entry;
141 if (access(CRASH_INFO_PATH, F_OK) == 0) /* if file exists then return -1 */
144 /* save old mask and set new calling process's file mode creation mask */
147 mkdir(CRASH_INFO_PATH, 0775); /* make directory, if exest then errno==EEXIST */
148 group_entry = getgrnam("crash"); /* need to find out group ID of "crash" group name*/
149 if (group_entry == NULL) {
150 umask(old_mask); /* restore old file mask */
153 chown(CRASH_INFO_PATH, 0, group_entry->gr_gid); /* chown root:crash */
154 umask(old_mask); /* restore old file mask */
158 static int clean_coredump_dir(void)
163 dir = opendir(CRASH_COREDUMP_PATH);
165 _E("opendir failed");
169 if (dfd < 0) return 0;
170 while ((dp = readdir(dir)) != NULL) {
171 const char *name = dp->d_name;
172 /* always skip "." and ".." */
173 if (name[0] == '.') {
174 if (name[1] == 0) continue;
175 if ((name[1] == '.') && (name[2] == 0)) continue;
177 if (unlinkat(dfd, name, 0) < 0) {
178 _E("FAIL: clean_coredump_dir (%s)",name);
185 static int clean_dump_dir(void)
189 char dirname[PATH_MAX];
191 dir = opendir(CRASH_DUMP_PATH);
193 _E("opendir failed");
196 while ((dp = readdir(dir)) != NULL) {
197 if (dp->d_type == DT_DIR) {
198 const char *name = dp->d_name;
199 /* always skip "." and ".." */
200 if (name[0] == '.') {
201 if (name[1] == 0) continue;
202 if ((name[1] == '.') && (name[2] == 0)) continue;
204 snprintf(dirname, sizeof(dirname), "%s/%s", CRASH_DUMP_PATH, name);
205 if (ecore_file_recursive_rm(dirname) == EINA_FALSE) {
206 _E("FAIL: clean_dump_dir (%s)",dirname);
214 static int clean_info_dir(void)
219 dir = opendir(CRASH_INFO_PATH);
221 _E("opendir failed");
225 if (dfd < 0) return 0;
226 while ((dp = readdir(dir)) != NULL) {
227 const char *name = dp->d_name;
228 /* always skip "." and ".." */
229 if (name[0] == '.') {
230 if (name[1] == 0) continue;
231 if ((name[1] == '.') && (name[2] == 0)) continue;
233 if (unlinkat(dfd, name, 0) < 0) {
234 _E("FAIL: clean_info_dir (%s)",name);
241 static int crash_arg_parser(char *linebuffer, struct crash_arg *arg)
245 int verify_arg_num = 0;
247 if (linebuffer == NULL || arg == NULL) {
248 _E("crash_arg_parser input arguments is NULL");
251 ptr = strtok(linebuffer, CRASH_DELIMITER);
253 _E("can't strtok linebuffer ptr(%s)", ptr);
256 snprintf(arg->crash_mode, CRASH_MODE_MAX, "%s", ptr);
257 ptr = strtok(NULL, CRASH_DELIMITER);
259 _E("can't strtok linebuffer ptr(%s)", ptr);
262 snprintf(arg->crash_processname, CRASH_PROCESSNAME_MAX, "%s", ptr);
263 ptr = strtok(NULL, CRASH_DELIMITER);
265 _E("can't strtok linebuffer ptr(%s)", ptr);
268 snprintf(arg->crash_timestr, CRASH_TIME_MAX, "%s", ptr);
269 ptr = strtok(NULL, CRASH_DELIMITER);
271 _E("can't strtok linebuffer ptr(%s)", ptr);
274 snprintf(arg->crash_pid, CRASH_PID_MAX, "%s", ptr);
275 ptr = strtok(NULL, CRASH_DELIMITER);
277 _E("can't strtok linebuffer ptr(%s)", ptr);
280 snprintf(arg->crash_exepath, CRASH_EXEPATH_MAX, "%s", ptr);
281 ptr = strtok(NULL, CRASH_DELIMITER);
283 _E("can't strtok linebuffer ptr(%s)", ptr);
286 snprintf(arg->crash_verify, CRASH_VERIFY_MAX, "%s", ptr);
287 verify_num = strlen(arg->crash_processname) + strlen(arg->crash_exepath);
288 verify_arg_num = atoi(arg->crash_verify);
289 _D("vnum %d vanum %d", verify_num, verify_arg_num);
290 if (verify_num == verify_arg_num)
295 static void launch_crash_worker(const char *filename, int popup_on)
297 static int popup_pid = 0;
301 char linebuffer[CRASH_ARG_MAX] = {0,};
302 char crash_worker_args[CRASH_ARG_MAX] = {0,};
303 struct crash_arg parsing_arg;
304 fp = fopen(filename, "r");
308 /* launch crash process */
309 while (fgets(linebuffer, CRASH_ARG_MAX, fp) != NULL) {
310 len = strlen(linebuffer);
311 if (!len || linebuffer[len - 1] != '\n') {
312 _E("crash inoti msg must be terminated with new line character\n");
315 /* change last caracter from \n to \0 */
316 linebuffer[strlen(linebuffer) - 1] = '\0';
317 if (crash_arg_parser(linebuffer, &parsing_arg) != 1)
319 snprintf(crash_worker_args, sizeof(crash_worker_args), "%s %s %s %s %s",
320 parsing_arg.crash_mode, parsing_arg.crash_processname,
321 parsing_arg.crash_timestr, parsing_arg.crash_pid, parsing_arg.crash_exepath);
322 _D("crash_worker args(%s)", crash_worker_args);
323 _D("(%s%s%s)", parsing_arg.crash_mode,
324 parsing_arg.crash_processname, parsing_arg.crash_timestr);
325 ret = ss_launch_evenif_exist (CRASH_WORKER_PATH, crash_worker_args);
329 snprintf(buf, sizeof(buf), "/proc/%d/oom_adj", ret);
330 fpAdj = fopen(buf, "w");
332 fprintf(fpAdj, "%d", (-17));
337 if (!is_running_process(popup_pid))
338 popup_pid = ss_launch_evenif_exist (CRASH_POPUP_PATH, parsing_arg.crash_processname);
342 _E("popup failed)\n");
348 fp = fopen(filename, "w");
357 static Ecore_File_Monitor *crash_file_monitor;
359 static Ecore_File_Monitor_Cb __crash_file_cb(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path)
362 case ECORE_FILE_EVENT_DELETED_DIRECTORY:
363 case ECORE_FILE_EVENT_DELETED_SELF:
364 if (make_noti_file(CRASH_NOTI_DIR, CRASH_NOTI_FILE) < 0) {
365 launch_crash_worker(path, CRASH_POPUP_ON);
368 case ECORE_FILE_EVENT_MODIFIED:
370 launch_crash_worker(path, CRASH_POPUP_ON);
375 static int _get_file_count(char *path)
382 while ((dp = readdir(dir)) != NULL) {
383 const char *name = dp->d_name;
384 /* always skip "." and ".." */
385 if (name[0] == '.') {
386 if (name[1] == 0) continue;
387 if ((name[1] == '.') && (name[2] == 0)) continue;
394 /* check disk available size */
395 static int _check_disk_available(void)
397 struct statfs lstatfs;
399 if (statfs(CRASH_CHECK_DISK_PATH, &lstatfs) < 0)
401 avail_size = (int)(lstatfs.f_bavail * (lstatfs.f_bsize/1024));
402 if (CRASH_CHECK_SIZE > avail_size)
407 static void bs_init(void *data)
409 if (make_noti_file(CRASH_NOTI_DIR, CRASH_NOTI_FILE) < 0) {
410 _E("make_noti_file() failed");
411 launch_crash_worker(CRASH_NOTI_PATH, CRASH_POPUP_OFF);
413 if (make_info_dir() < 0) {
414 if (CRASH_LIMIT_NUM < _get_file_count(CRASH_INFO_PATH))
417 if (make_coredump_dir() < 0) {
418 if (CRASH_LIMIT_NUM < _get_file_count(CRASH_COREDUMP_PATH)
419 || _check_disk_available() < 0)
420 clean_coredump_dir();
422 if (CRASH_LIMIT_NUM < _get_file_count(CRASH_DUMP_PATH))
425 if (ecore_file_init() == 0) {
426 _E("ecore_file_init() failed");
427 launch_crash_worker(CRASH_NOTI_PATH, CRASH_POPUP_OFF);
429 crash_file_monitor = ecore_file_monitor_add(CRASH_NOTI_PATH,(void *) __crash_file_cb, NULL);
430 if (!crash_file_monitor) {
431 _E("ecore_file_monitor_add() failed");
432 launch_crash_worker(CRASH_NOTI_PATH, CRASH_POPUP_OFF);
437 const struct device_ops bs_device_ops = {