+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
#include <glib.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "common/log.h"
+#include "common/spawn.h"
void
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);
}
+
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;
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)
{
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(
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);