diff --git a/src/common/util.c b/src/common/util.c index a15cca7c..df118790 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -5,7 +5,9 @@ #include #include #include - +#include +#include +#include #include "util.h" #define PCRE2_CODE_UNIT_WIDTH 8 @@ -92,3 +94,29 @@ uint32_t get_now_in_ms(void) { uint32_t timespec_to_ms(struct timespec *ts) { return (uint32_t)ts->tv_sec * 1000 + (uint32_t)ts->tv_nsec / 1000000; } + +void restore_nofile_limit(void) { + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { + // Restore the soft limit to the hard limit + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rl) != 0) { + wlr_log(WLR_DEBUG, "restore_nofile_limit: setrlimit failed"); + } + } else { + wlr_log(WLR_DEBUG, "restore_nofile_limit: getrlimit failed"); + } +} + +void reset_child_environment(void) { + restore_nofile_limit(); + + // Reset signal handlers + sigset_t set; + sigemptyset(&set); + sigprocmask(SIG_SETMASK, &set, NULL); + + // Reset signal handlers to default + signal(SIGPIPE, SIG_DFL); + signal(SIGCHLD, SIG_DFL); +} \ No newline at end of file diff --git a/src/common/util.h b/src/common/util.h index 8fb60338..4df00a46 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -7,4 +7,5 @@ int32_t fd_set_nonblock(int32_t fd); int32_t regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); uint32_t get_now_in_ms(void); -uint32_t timespec_to_ms(struct timespec *ts); \ No newline at end of file +uint32_t timespec_to_ms(struct timespec *ts); +void reset_child_environment(void); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index bd065141..cdc4c9f4 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -794,70 +794,88 @@ int32_t centerwin(const Arg *arg) { } int32_t spawn_shell(const Arg *arg) { - if (!arg->v) - return 0; + if (!arg->v) + return 0; - if (fork() == 0) { - // 1. 忽略可能导致 coredump 的信号 - signal(SIGSEGV, SIG_IGN); - signal(SIGABRT, SIG_IGN); - signal(SIGILL, SIG_IGN); + pid_t child = fork(); + if (child == -1) { + wlr_log_errno(WLR_ERROR, "spawn_shell: first fork failed"); + return 0; + } - dup2(STDERR_FILENO, STDOUT_FILENO); - setsid(); + if (child == 0) { + reset_child_environment(); - execlp("sh", "sh", "-c", arg->v, (char *)NULL); + pid_t grandchild = fork(); + if (grandchild == -1) { + wlr_log_errno(WLR_ERROR, "spawn_shell: second fork failed"); + _exit(EXIT_FAILURE); + } - // fallback to bash - execlp("bash", "bash", "-c", arg->v, (char *)NULL); + if (grandchild == 0) { + + execlp("sh", "sh", "-c", arg->v, (char *)NULL); + // fallback to bash + execlp("bash", "bash", "-c", arg->v, (char *)NULL); + wlr_log_errno(WLR_ERROR, "spawn_shell: execlp failed for '%s'", arg->v); + _exit(EXIT_FAILURE); + } - // if execlp fails, we should not reach here - wlr_log(WLR_ERROR, - "mango: failed to execute command '%s' with shell: %s\n", - arg->v, strerror(errno)); - _exit(EXIT_FAILURE); - } - return 0; + _exit(EXIT_SUCCESS); + } + + waitpid(child, NULL, 0); + return 0; } int32_t spawn(const Arg *arg) { + if (!arg->v) + return 0; - if (!arg->v) - return 0; + pid_t child = fork(); + if (child == -1) { + wlr_log_errno(WLR_ERROR, "spawn: first fork failed"); + return 0; + } - if (fork() == 0) { - // 1. 忽略可能导致 coredump 的信号 - signal(SIGSEGV, SIG_IGN); - signal(SIGABRT, SIG_IGN); - signal(SIGILL, SIG_IGN); + if (child == 0) { + // reset environment + reset_child_environment(); - dup2(STDERR_FILENO, STDOUT_FILENO); - setsid(); + // create second child + pid_t grandchild = fork(); + if (grandchild == -1) { + wlr_log_errno(WLR_ERROR, "spawn: second fork failed"); + _exit(EXIT_FAILURE); + } - // 2. 解析参数 - char *argv[64]; - int32_t argc = 0; - char *token = strtok((char *)arg->v, " "); - while (token != NULL && argc < 63) { - wordexp_t p; - if (wordexp(token, &p, 0) == 0) { - argv[argc++] = p.we_wordv[0]; - } else { - argv[argc++] = token; - } - token = strtok(NULL, " "); - } - argv[argc] = NULL; + if (grandchild == 0) { + // execute actual command + char *argv[64]; + int32_t argc = 0; + char *token = strtok((char *)arg->v, " "); + while (token != NULL && argc < 63) { + wordexp_t p; + if (wordexp(token, &p, 0) == 0) { + argv[argc++] = p.we_wordv[0]; + } else { + argv[argc++] = token; + } + token = strtok(NULL, " "); + } + argv[argc] = NULL; - // 3. 执行命令 - execvp(argv[0], argv); + execvp(argv[0], argv); + wlr_log_errno(WLR_ERROR, "spawn: execvp '%s' failed", argv[0]); + _exit(EXIT_FAILURE); + } - // 4. execvp 失败时:打印错误并直接退出(避免 coredump) - wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0], - strerror(errno)); - _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作 - } - return 0; + + _exit(EXIT_SUCCESS); + } + + waitpid(child, NULL, 0); + return 0; } int32_t spawn_on_empty(const Arg *arg) { diff --git a/src/mango.c b/src/mango.c index 540395ae..5611c8bd 100644 --- a/src/mango.c +++ b/src/mango.c @@ -86,6 +86,7 @@ #include #include #include +#include #include #ifdef XWAYLAND #include