q66 pushed a commit to branch master. http://git.enlightenment.org/core/enlightenment.git/commit/?id=f918476da1021104661178282d19d293c96fe633
commit f918476da1021104661178282d19d293c96fe633 Author: Daniel Kolesa <[email protected]> Date: Mon Dec 1 15:46:37 2014 +0000 e_start_main: refactor (reduce scope depth, separate ifdefs, cleanup) The main reason for this change is to clean it up for proper non-Linux platform support, but also to make it cleaner in general. --- src/bin/e_start_main.c | 583 ++++++++++++++++++++++++++++--------------------- 1 file changed, 331 insertions(+), 252 deletions(-) diff --git a/src/bin/e_start_main.c b/src/bin/e_start_main.c index 328cc4c..12c185b 100644 --- a/src/bin/e_start_main.c +++ b/src/bin/e_start_main.c @@ -275,6 +275,197 @@ _cserve2_start() } #endif +static void +_print_usage(const char *hstr) +{ + printf("Options:\n" + "\t-valgrind[=MODE]\n" + "\t\tRun enlightenment from inside valgrind, mode is OR of:\n" + "\t\t 1 = plain valgrind to catch crashes (default)\n" + "\t\t 2 = trace children (thumbnailer, efm slaves, ...)\n" + "\t\t 4 = check leak\n" + "\t\t 8 = show reachable after processes finish.\n" + "\t\t all = all of above\n" + "\t-massif\n" + "\t\tRun enlightenment from inside massif valgrind tool.\n" + "\t-callgrind\n" + "\t\tRun enlightenment from inside callgrind valgrind tool.\n" + "\t-valgrind-log-file=<FILENAME>\n" + "\t\tSave valgrind log to file, see valgrind's --log-file for details.\n" + "\n" + "Please run:\n" + "\tenlightenment %s\n" + "for more options.\n", + hstr); + exit(0); +} + +static Eina_Bool +_sig_continue(siginfo_t sig) +{ + return (sig.si_signo != SIGSEGV && + sig.si_signo != SIGFPE && +// sig.si_signo != SIGBUS && + sig.si_signo != SIGABRT); +} + +static void +_sig_remember(siginfo_t sig, Eina_Bool *susr1, Eina_Bool *sill) +{ + if (sig.si_signo == SIGUSR1) + { + if (*sill) *susr1 = EINA_TRUE; + } + else + *sill = (sig.si_signo == SIGILL); +} + +static int +_e_ptrace_attach(int child, int *status, Eina_Bool really_know) +{ +#ifdef HAVE_SYS_PTRACE_H + int result = 0; + + if (really_know) + return waitpid(child, status, 0); + + ptrace(PT_ATTACH, child, NULL, 0); + result = waitpid(child, status, 0); + + if (!stop_ptrace && WIFSTOPPED(*status)) + ptrace(PT_CONTINUE, child, NULL, 0); +#else + (void)child; + (void)really_know; + (void)status; + return 0; +#endif +} + +static void +_e_ptrace_detach(int child, int back, Eina_Bool really_know) +{ +#ifdef HAVE_SYS_PTRACE_H + if (!really_know) + ptrace(PT_DETACH, child, NULL, back); +#else + (void)child; + (void)back; + (void)really_know); +#endif +} + +static void +_e_ptrace_traceme(Eina_Bool really_know) +{ +#ifdef HAVE_SYS_PTRACE_H + if (!really_know) + ptrace(PT_TRACE_ME, 0, NULL, 0); +#else + (void)really_know; +#endif +} + +static int +_e_ptrace_getsiginfo(int child, siginfo_t *sig, Eina_Bool really_know) +{ + memset(sig, 0, sizeof(siginfo_t)); +#ifdef HAVE_SYS_PTRACE_H + if (!really_know) + return ptrace(PT_GETSIGINFO, child, NULL, sig); +#else + (void)really_know; +#endif + return 0; +} + +static void +_e_ptrace_continue(int child, int back, Eina_Bool really_know) +{ +#ifdef HAVE_SYS_PTRACE_H + if (!really_know) + ptrace(PT_CONTINUE, child, NULL, back); +#else + (void)child; + (void)back; + (void)really_know); +#endif +} + +static int +_e_start_child(char **args, Eina_Bool really_know) +{ + _e_ptrace_traceme(really_know); + execv(args[0], args); + /* We failed, 0 mean normal exit from E with no restart or crash so let exit */ + return 0; +} + +static Eina_Bool +_e_ptrace_kernel_check() +{ +#ifdef __linux__ + /* Check if patch to prevent ptrace to another process is present in the kernel. */ + Eina_Bool ret = EINA_FALSE; + int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY); + if (fd != -1) + { + char c; + ret = (read(fd, &c, sizeof (c)) == sizeof (c) && c != '0'); + } + close(fd); + return ret; +#else + return EINA_FALSE; +#endif +} + +static int +_e_call_gdb(int child, const char *home, char **backtrace_str) +{ + int r = 0; + char buf[4096]; + /* call e_sys gdb */ + snprintf(buf, sizeof(buf), + "gdb " + "--pid=%i " + "-batch " + "-ex 'set logging file %s/.e-crashdump.txt' " + "-ex 'set logging on' " + "-ex 'thread apply all backtrace full' " + "-ex detach > /dev/null 2>&1 < /dev/zero", + child, + home); + r = system(buf); + + fprintf(stderr, "called gdb with '%s' = %i\n", + buf, WEXITSTATUS(r)); + + snprintf(buf, 4096, + "%s/.e-crashdump.txt", + home); + + *backtrace_str = strdup(buf); + return WEXITSTATUS(r); +} + +static int +_e_call_alert(int child, siginfo_t sig, int exit_gdb, const char *backtrace_str, + Eina_Bool susr1) +{ + char buf[4096]; + snprintf(buf, sizeof(buf), + backtrace_str ? + "%s/enlightenment/utils/enlightenment_alert %i %i %i '%s'" : + "%s/enlightenment/utils/enlightenment_alert %i %i %i", + eina_prefix_lib_get(pfx), + (sig.si_signo == SIGSEGV && susr1) ? SIGILL : sig.si_signo, + child, + exit_gdb, + backtrace_str); + return system(buf); +} + int main(int argc, char **argv) { @@ -323,88 +514,73 @@ main(int argc, char **argv) for (i = 1; i < argc; i++) { + if ((!strcmp(argv[i], "-h")) || (!strcmp(argv[i], "-help")) || + (!strcmp(argv[i], "--help"))) + { + _print_usage(argv[i]); + } if (!strcmp(argv[i], "-valgrind-gdb")) valgrind_gdbserver = 1; + else if (!strcmp(argv[i], "-massif")) + valgrind_tool = 1; + else if (!strcmp(argv[i], "-callgrind")) + valgrind_tool = 2; + else if (!strcmp(argv[i], "-display")) + { + i++; + env_set("DISPLAY", argv[i]); + } else if (!strncmp(argv[i], "-valgrind", sizeof("-valgrind") - 1)) { const char *val = argv[i] + sizeof("-valgrind") - 1; - - if (*val == '\0') valgrind_mode = 1; - else if (*val == '-') + switch (*val) { + case '\0': + valgrind_mode = 1; + break; + case '=': + val++; + if (!strcmp(val, "all")) valgrind_mode = VALGRIND_MODE_ALL; + else valgrind_mode = atoi(val); + break; + case '-': val++; if (!strncmp(val, "log-file=", sizeof("log-file=") - 1)) { valgrind_log = val + sizeof("log-file=") - 1; if (*valgrind_log == '\0') valgrind_log = NULL; } + break; + default: + printf("Unknown valgrind option: %s\n", argv[i]); + break; } - else if (*val == '=') - { - val++; - if (!strcmp(val, "all")) valgrind_mode = VALGRIND_MODE_ALL; - else valgrind_mode = atoi(val); - } - else - printf("Unknown valgrind option: %s\n", argv[i]); } - else if (!strcmp(argv[i], "-display")) + else if (!strcmp(argv[i], "-i-really-know-what-i-am-doing-and-accept" + "-full-responsibility-for-it")) { - i++; - env_set("DISPLAY", argv[i]); + really_know = EINA_TRUE; } - else if (!strcmp(argv[i], "-massif")) - valgrind_tool = 1; - else if (!strcmp(argv[i], "-callgrind")) - valgrind_tool = 2; - else if ((!strcmp(argv[i], "-h")) || - (!strcmp(argv[i], "-help")) || - (!strcmp(argv[i], "--help"))) - { - printf - ( - "Options:\n" - "\t-valgrind[=MODE]\n" - "\t\tRun enlightenment from inside valgrind, mode is OR of:\n" - "\t\t 1 = plain valgrind to catch crashes (default)\n" - "\t\t 2 = trace children (thumbnailer, efm slaves, ...)\n" - "\t\t 4 = check leak\n" - "\t\t 8 = show reachable after processes finish.\n" - "\t\t all = all of above\n" - "\t-massif\n" - "\t\tRun enlightenment from inside massif valgrind tool.\n" - "\t-callgrind\n" - "\t\tRun enlightenment from inside callgrind valgrind tool.\n" - "\t-valgrind-log-file=<FILENAME>\n" - "\t\tSave valgrind log to file, see valgrind's --log-file for details.\n" - "\n" - "Please run:\n" - "\tenlightenment %s\n" - "for more options.\n", - argv[i]); - exit(0); - } - else if (!strcmp(argv[i], "-i-really-know-what-i-am-doing-and-accept-full-responsibility-for-it")) - really_know = EINA_TRUE; } - if (really_know) _env_path_append("PATH", eina_prefix_bin_get(pfx)); - else _env_path_prepend("PATH", eina_prefix_bin_get(pfx)); + if (really_know) + _env_path_append("PATH", eina_prefix_bin_get(pfx)); + else + _env_path_prepend("PATH", eina_prefix_bin_get(pfx)); - if (valgrind_mode || valgrind_tool) + if ((valgrind_mode || valgrind_tool) && + !find_valgrind(valgrind_path, sizeof(valgrind_path))) { - if (!find_valgrind(valgrind_path, sizeof(valgrind_path))) - { - printf("E - valgrind required but no binary found! Ignoring request.\n"); - valgrind_mode = 0; - } + printf("E - valgrind required but no binary found! Ignoring request.\n"); + valgrind_mode = 0; } printf("E - PID=%i, valgrind=%d", getpid(), valgrind_mode); if (valgrind_mode) { printf(" valgrind-command='%s'", valgrind_path); - if (valgrind_log) printf(" valgrind-log-file='%s'", valgrind_log); + if (valgrind_log) + printf(" valgrind-log-file='%s'", valgrind_log); } putchar('\n'); @@ -438,18 +614,25 @@ main(int argc, char **argv) } fclose(f); } + tmps = getenv("XDG_DATA_HOME"); - if (tmps) snprintf(buf, sizeof(buf), "%s/Applications/.bin", tmps); - else snprintf(buf, sizeof(buf), "%s/Applications/.bin", home); - if (really_know) _env_path_append("PATH", buf); - else _env_path_prepend("PATH", buf); + if (tmps) + snprintf(buf, sizeof(buf), "%s/Applications/.bin", tmps); + else + snprintf(buf, sizeof(buf), "%s/Applications/.bin", home); + + if (really_know) + _env_path_append("PATH", buf); + else + _env_path_prepend("PATH", buf); } /* run e directly now */ snprintf(buf, sizeof(buf), "%s/enlightenment", eina_prefix_bin_get(pfx)); args = alloca((argc + 2 + VALGRIND_MAX_ARGS) * sizeof(char *)); - i = valgrind_append(args, valgrind_gdbserver, valgrind_mode, valgrind_tool, valgrind_path, valgrind_log); + i = valgrind_append(args, valgrind_gdbserver, valgrind_mode, valgrind_tool, + valgrind_path, valgrind_log); args[i++] = buf; copy_args(args + i, argv + 1, argc - 1); args[i + argc - 1] = NULL; @@ -469,212 +652,108 @@ main(int argc, char **argv) /* Now looping until */ while (restart) { + pid_t result; + int status; + Eina_Bool done = EINA_FALSE; + Eina_Bool remember_sigill = EINA_FALSE; + Eina_Bool remember_sigusr1 = EINA_FALSE; + stop_ptrace = EINA_FALSE; child = fork(); - if (child < 0) /* failed attempt */ + if (child < 0) return -1; else if (child == 0) + return _e_start_child(args, really_know); + + /* in the parent - ptrace attach and continue */ + env_set("E_RESTART", "1"); + _e_ptrace_attach(child, &status, really_know); + + /* now loop until done */ +not_done: + result = waitpid(child, &status, WNOHANG); + /* Wait for evas_cserve2 and E */ + if (!result) + result = waitpid(-1, &status, 0); + + if (result == child) { -#ifdef HAVE_SYS_PTRACE_H - if (!really_know) - /* in the child */ - ptrace(PT_TRACE_ME, 0, NULL, NULL); -#endif - execv(args[0], args); - return 0; /* We failed, 0 mean normal exit from E with no restart or crash so let exit */ + if (WIFSTOPPED(status) && !stop_ptrace) + { + char buffer[4096]; + char *backtrace_str = NULL; + + siginfo_t sig; + int r = _e_ptrace_getsiginfo(child, &sig, + really_know); + + int back = (r == 0 && sig.si_signo != SIGTRAP) + ? sig.si_signo : 0; + + _sig_remember(sig, &remember_sigusr1, &remember_sigill); + + if (r != 0 || _sig_continue(sig)) + { + _e_ptrace_continue(child, back, really_know); + goto not_done; + } + _e_ptrace_detach(child, back, really_know); + + /* And call gdb if available */ + if (home && !_e_ptrace_kernel_check()) + r = _e_call_gdb(child, home, &backtrace_str); + else + r = 0; + + /* call e_alert */ + r = _e_call_alert(child, sig, r, backtrace_str, + remember_sigusr1); + free(backtrace_str); + + /* kill e */ + kill(child, SIGKILL); + + if (WEXITSTATUS(r) != 1) + restart = EINA_FALSE; + } + else if (!WIFEXITED(status) || stop_ptrace) + done = EINA_TRUE; } - else + else if (result == -1) { - env_set("E_RESTART", "1"); - /* in the parent */ - pid_t result; - int status; - Eina_Bool done = EINA_FALSE; - Eina_Bool remember_sigill = EINA_FALSE; - Eina_Bool remember_sigusr1 = EINA_FALSE; - Eina_Bool bad_kernel = EINA_FALSE; - -#ifdef HAVE_SYS_PTRACE_H - if (!really_know) - ptrace(PT_ATTACH, child, NULL, NULL); - result = waitpid(child, &status, 0); - if ((!really_know) && (!stop_ptrace)) + if (errno != EINTR) { - if (WIFSTOPPED(status)) - ptrace(PT_CONTINUE, child, NULL, NULL); + done = EINA_TRUE; + restart = EINA_FALSE; } -#endif - while (!done) + else if (stop_ptrace) { - result = waitpid(child, &status, WNOHANG); - if (!result) - { - /* Wait for evas_cserve2 and E */ - result = waitpid(-1, &status, 0); - } - - if (result == child) - { - if ((WIFSTOPPED(status)) && (!stop_ptrace)) - { - char buffer[4096]; - char *backtrace_str = NULL; - siginfo_t sig; - int r = 0; - int back; - - memset(&sig, 0, sizeof(siginfo_t)); -#ifdef HAVE_SYS_PTRACE_H - if (!really_know) - r = ptrace(PT_GETSIGINFO, child, NULL, &sig); -#endif - back = r == 0 && - sig.si_signo != SIGTRAP ? sig.si_signo : 0; - - if (sig.si_signo == SIGUSR1) - { - if (remember_sigill) - remember_sigusr1 = EINA_TRUE; - } - else if (sig.si_signo == SIGILL) - { - remember_sigill = EINA_TRUE; - } - else - { - remember_sigill = EINA_FALSE; - } - - if (r != 0 || - (sig.si_signo != SIGSEGV && - sig.si_signo != SIGFPE && -// sig.si_signo != SIGBUS && - sig.si_signo != SIGABRT)) - { -#ifdef HAVE_SYS_PTRACE_H - if (!really_know) - ptrace(PT_CONTINUE, child, NULL, back); -#endif - continue; - } -#ifdef HAVE_SYS_PTRACE_H - if (!really_know) - /* E should be in pause, we can detach */ - ptrace(PT_DETACH, child, NULL, back); -#endif - /* And call gdb if available */ - r = 0; - - /* Check if patch to prevent ptrace to another process is present in the kernel. */ - { - int fd; - char c; - - fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY); - if (fd != -1) - { - if (read(fd, &c, sizeof (c)) == sizeof (c) && c != '0') - bad_kernel = EINA_TRUE; - } - close(fd); - } - - if (home && !bad_kernel) - { - /* call e_sys gdb */ - snprintf(buffer, sizeof(buffer), - "gdb " - "--pid=%i " - "-batch " - "-ex 'set logging file %s/.e-crashdump.txt' " - "-ex 'set logging on' " - "-ex 'thread apply all backtrace full' " - "-ex detach > /dev/null 2>&1 < /dev/zero", - child, - home); - r = system(buffer); - - fprintf(stderr, "called gdb with '%s' = %i\n", - buffer, WEXITSTATUS(r)); - - snprintf(buffer, 4096, - "%s/.e-crashdump.txt", - home); - - backtrace_str = strdup(buffer); - r = WEXITSTATUS(r); - } - - /* call e_alert */ - snprintf(buffer, 4096, - backtrace_str ? - "%s/enlightenment/utils/enlightenment_alert %i %i %i '%s'" : - "%s/enlightenment/utils/enlightenment_alert %i %i %i", - eina_prefix_lib_get(pfx), - sig.si_signo == SIGSEGV && remember_sigusr1 ? SIGILL : sig.si_signo, - child, - r, - backtrace_str); - r = system(buffer); - - /* kill e */ - kill(child, SIGKILL); - - if (WEXITSTATUS(r) != 1) - { - restart = EINA_FALSE; - } - } - else if (!WIFEXITED(status)) - { - done = EINA_TRUE; - } - else if (stop_ptrace) - { - done = EINA_TRUE; - } - } - else if (result == -1) - { - if (errno != EINTR) - { - done = EINA_TRUE; - restart = EINA_FALSE; - } - else - { - if (stop_ptrace) - { - kill(child, SIGSTOP); - usleep(200000); -#ifdef HAVE_SYS_PTRACE_H - if (!really_know) - ptrace(PT_DETACH, child, NULL, NULL); -#endif - } - } - } + kill(child, SIGSTOP); + usleep(200000); + _e_ptrace_detach(child, 0, really_know); + } + } #ifdef E_CSERVE - else if (cs_use && (result == cs_child)) - { - if (WIFSIGNALED(status)) - { - printf("E - cserve2 terminated with signal %d\n", - WTERMSIG(status)); - cs_child = _cserve2_start(); - } - else if (WIFEXITED(status)) - { - printf("E - cserve2 exited with code %d\n", - WEXITSTATUS(status)); - cs_child = -1; - } - } -#endif + else if (cs_use && (result == cs_child)) + { + if (WIFSIGNALED(status)) + { + printf("E - cserve2 terminated with signal %d\n", + WTERMSIG(status)); + cs_child = _cserve2_start(); + } + else if (WIFEXITED(status)) + { + printf("E - cserve2 exited with code %d\n", + WEXITSTATUS(status)); + cs_child = -1; } } +#endif + if (!done) + goto not_done; } #ifdef E_CSERVE --
