double forking for process spawning

This commit is contained in:
Leonardo Hernández Hernández 2022-03-28 18:42:34 -06:00
parent 504128aed3
commit 4e26081c4f
No known key found for this signature in database
GPG Key ID: E538897EE11B9624

46
dwl.c
View File

@ -1748,22 +1748,31 @@ run(char *startup_cmd)
/* Now that the socket exists, run the startup command */ /* Now that the socket exists, run the startup command */
if (startup_cmd) { if (startup_cmd) {
/* For explanation about double-forking see spawn() */
int piperw[2]; int piperw[2];
pipe(piperw); pipe(piperw);
startup_pid = fork(); startup_pid = fork();
if (startup_pid < 0) if (startup_pid < 0)
EBARF("startup: fork"); EBARF("startup: fork");
if (startup_pid == 0) { if (startup_pid == 0) {
dup2(piperw[0], STDIN_FILENO); pid_t child;
close(piperw[0]);
close(piperw[1]); close(piperw[1]);
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL); if ((child = fork()) == 0) {
EBARF("startup: execl"); dup2(piperw[0], STDIN_FILENO);
close(piperw[0]);
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, NULL);
EBARF("startup: execl");
}
close(piperw[0]);
_exit(0);
} }
dup2(piperw[1], STDOUT_FILENO); dup2(piperw[1], STDOUT_FILENO);
close(piperw[1]); close(piperw[1]);
close(piperw[0]); close(piperw[0]);
waitpid(startup_pid, NULL, 0);
} }
/* If nobody is reading the status output, don't terminate */ /* If nobody is reading the status output, don't terminate */
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
printstatus(); printstatus();
@ -1789,11 +1798,6 @@ run(char *startup_cmd)
* loop configuration to listen to libinput events, DRM events, generate * loop configuration to listen to libinput events, DRM events, generate
* frame events at the refresh rate, and so on. */ * frame events at the refresh rate, and so on. */
wl_display_run(dpy); wl_display_run(dpy);
if (startup_cmd) {
kill(startup_pid, SIGTERM);
waitpid(startup_pid, NULL, 0);
}
} }
Client * Client *
@ -2080,12 +2084,28 @@ setup(void)
void void
spawn(const Arg *arg) spawn(const Arg *arg)
{ {
if (fork() == 0) { /* The simplest way to avoid zombie processes is `signal(SIGCHLD, SIG_IGN)`
dup2(STDERR_FILENO, STDOUT_FILENO); * but Xwayland implementation in wlroots currently prevent us from setting
* our own disposition for SIGCHLD; to be able to spawn child processes
* we do double-fork, so we spawn the command in the second fork and wait
* for the first fork.
*/
pid_t pid = -1;
if ((pid = fork()) == 0) {
pid_t child = -1;
setsid(); setsid();
execvp(((char **)arg->v)[0], (char **)arg->v); signal(SIGPIPE, SIG_DFL);
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]); /* Fork child process again */
if ((child = fork()) == 0) {
dup2(STDERR_FILENO, STDOUT_FILENO);
execvp(((char **)arg->v)[0], (char **)arg->v);
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]);
}
_exit(0); /* Close child process */
} else if (pid < 0) {
EBARF("spawn: fork");
} }
waitpid(pid, NULL, 0);
} }
void void