mirror of
https://github.com/labwc/labwc.git
synced 2025-11-04 13:30:07 -05:00
common/spawn.c: add spawn_piped()
This commit is contained in:
parent
0671a3bfd3
commit
e5488fefcb
3 changed files with 180 additions and 6 deletions
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -11,6 +12,26 @@
|
|||
#include "common/spawn.h"
|
||||
#include "common/fd_util.h"
|
||||
|
||||
static void
|
||||
reset_signals_and_limits(void)
|
||||
{
|
||||
restore_nofile_limit();
|
||||
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
|
||||
/* Restore ignored signals */
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
}
|
||||
|
||||
static void
|
||||
set_cloexec(int fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
|
||||
void
|
||||
spawn_async_no_shell(char const *command)
|
||||
{
|
||||
|
|
@ -39,14 +60,9 @@ spawn_async_no_shell(char const *command)
|
|||
wlr_log(WLR_ERROR, "unable to fork()");
|
||||
goto out;
|
||||
case 0:
|
||||
restore_nofile_limit();
|
||||
reset_signals_and_limits();
|
||||
|
||||
setsid();
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
/* Restore ignored signals */
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
grandchild = fork();
|
||||
if (grandchild == 0) {
|
||||
execvp(argv[0], argv);
|
||||
|
|
@ -63,3 +79,76 @@ out:
|
|||
g_strfreev(argv);
|
||||
}
|
||||
|
||||
pid_t
|
||||
spawn_piped(const char *command, int *pipe_fd)
|
||||
{
|
||||
assert(command);
|
||||
|
||||
int pipe_rw[2];
|
||||
if (pipe(pipe_rw) != 0) {
|
||||
wlr_log(WLR_ERROR, "unable to pipe()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
close(pipe_rw[0]);
|
||||
close(pipe_rw[1]);
|
||||
wlr_log(WLR_ERROR, "unable to fork()");
|
||||
return pid;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* child */
|
||||
reset_signals_and_limits();
|
||||
|
||||
/*
|
||||
* replace stdin and stderr with /dev/null
|
||||
* and stdout with the write end of the pipe
|
||||
*/
|
||||
dup2(pipe_rw[1], STDOUT_FILENO);
|
||||
close(pipe_rw[0]);
|
||||
close(pipe_rw[1]);
|
||||
|
||||
int dev_null = open("/dev/null", O_RDWR);
|
||||
if (dev_null < 0) {
|
||||
wlr_log_errno(WLR_ERROR, "opening /dev/null failed");
|
||||
/*
|
||||
* Just close stdin and stderr and
|
||||
* hope $command can deal with that.
|
||||
*/
|
||||
close(STDIN_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
} else {
|
||||
dup2(dev_null, STDIN_FILENO);
|
||||
dup2(dev_null, STDERR_FILENO);
|
||||
close(dev_null);
|
||||
}
|
||||
|
||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||
/*
|
||||
* Our stderr points to /dev/null or is closed
|
||||
* at this point so logging is pretty useless.
|
||||
*/
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* labwc */
|
||||
close(pipe_rw[1]);
|
||||
|
||||
/*
|
||||
* Prevent leaking the read end of the pipe to further
|
||||
* children forked during the lifetime of the descriptor.
|
||||
*/
|
||||
set_cloexec(pipe_rw[0]);
|
||||
|
||||
*pipe_fd = pipe_rw[0];
|
||||
return pid;
|
||||
}
|
||||
|
||||
void
|
||||
spawn_piped_close(pid_t pid, int pipe_fd)
|
||||
{
|
||||
close(pipe_fd);
|
||||
/* waitpid() is done in a generic SIGCHLD handler in src/server.c */
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue