diff --git a/src/common/spawn.c b/src/common/spawn.c index 41acd9f6..d42061b7 100644 --- a/src/common/spawn.c +++ b/src/common/spawn.c @@ -1,4 +1,14 @@ +#define _POSIX_C_SOURCE 200809L +#include #include +#include +#include +#include +#include +#include +#include +#include "common/log.h" +#include "common/spawn.h" void spawn_async_no_shell(char const *command) @@ -6,18 +16,45 @@ spawn_async_no_shell(char const *command) GError *err = NULL; gchar **argv = NULL; + assert(command); + + /* Use glib's shell-parse to mimic Openbox's behaviour */ g_shell_parse_argv((gchar *)command, NULL, &argv, &err); if (err) { g_message("%s", err->message); g_error_free(err); return; } - g_spawn_async(NULL, argv, NULL, - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, - NULL, &err); - if (err) { - g_message("%s", err->message); - g_error_free(err); + + /* + * Avoid zombie processes by using a double-fork, whereby the + * grandchild becomes orphaned & the responsibility of the OS. + */ + pid_t child = 0, grandchild = 0; + + child = fork(); + switch (child) { + case -1: + warn("unable to fork()"); + goto out; + case 0: + setsid(); + sigset_t set; + sigemptyset(&set); + sigprocmask(SIG_SETMASK, &set, NULL); + grandchild = fork(); + if (grandchild == 0) { + execvp(argv[0], argv); + exit(0); + } else if (grandchild < 0) { + warn("unable to fork()"); + } + exit(0); + default: + break; } + waitpid(child, NULL, 0); +out: g_strfreev(argv); } + diff --git a/src/server.c b/src/server.c index 096267e3..54ebe931 100644 --- a/src/server.c +++ b/src/server.c @@ -14,7 +14,6 @@ static struct wlr_compositor *compositor; static struct wl_event_source *sighup_source; -static struct wl_event_source *sigchld_source; static struct wl_event_source *sigint_source; static struct wl_event_source *sigterm_source; @@ -34,19 +33,6 @@ handle_sighup(int signal, void *data) return 0; } -static int -handle_sigchld(int signal, void *data) -{ - int status; - pid_t pid; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0); - if (pid < 0) { - wlr_log_errno(WLR_ERROR, "waitpid"); - } - return 0; -} - static int handle_sigterm(int signal, void *data) { @@ -86,8 +72,6 @@ server_init(struct server *server) event_loop = wl_display_get_event_loop(server->wl_display); sighup_source = wl_event_loop_add_signal( event_loop, SIGHUP, handle_sighup, &server->wl_display); - sigchld_source = wl_event_loop_add_signal( - event_loop, SIGCHLD, handle_sigchld, NULL); sigint_source = wl_event_loop_add_signal( event_loop, SIGINT, handle_sigterm, NULL); sigterm_source = wl_event_loop_add_signal( @@ -263,9 +247,6 @@ server_finish(struct server *server) if (sighup_source) { wl_event_source_remove(sighup_source); } - if (sigchld_source) { - wl_event_source_remove(sigchld_source); - } wl_display_destroy_clients(server->wl_display); seat_finish(server);