2014-11-27 05:36:48 +00:00
|
|
|
/*
|
2023-05-19 00:37:26 +00:00
|
|
|
* Copyright (c) 2023 Lain Bailey <lain@obsproject.com>
|
2014-11-27 05:36:48 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
2015-06-08 18:30:51 +00:00
|
|
|
#include <sys/wait.h>
|
2020-09-12 04:33:27 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <spawn.h>
|
2024-04-19 19:18:17 +00:00
|
|
|
#include <fcntl.h>
|
2014-11-27 05:36:48 +00:00
|
|
|
|
|
|
|
#include "bmem.h"
|
|
|
|
#include "pipe.h"
|
|
|
|
|
|
|
|
struct os_process_pipe {
|
|
|
|
bool read_pipe;
|
2020-09-12 04:33:27 +00:00
|
|
|
int pid;
|
2014-11-27 05:36:48 +00:00
|
|
|
FILE *file;
|
2020-09-12 04:33:27 +00:00
|
|
|
FILE *err_file;
|
2014-11-27 05:36:48 +00:00
|
|
|
};
|
|
|
|
|
2024-01-14 03:17:53 +00:00
|
|
|
os_process_pipe_t *os_process_pipe_create_internal(const char *bin, char **argv,
|
|
|
|
const char *type)
|
2014-11-27 05:36:48 +00:00
|
|
|
{
|
2020-09-12 04:33:27 +00:00
|
|
|
struct os_process_pipe process_pipe = {0};
|
2014-11-27 05:36:48 +00:00
|
|
|
struct os_process_pipe *out;
|
2020-09-12 04:33:27 +00:00
|
|
|
posix_spawn_file_actions_t file_actions;
|
2014-11-27 05:36:48 +00:00
|
|
|
|
2024-01-14 03:17:53 +00:00
|
|
|
if (!bin || !argv || !type) {
|
2014-11-27 05:36:48 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-09-12 04:33:27 +00:00
|
|
|
process_pipe.read_pipe = *type == 'r';
|
|
|
|
|
|
|
|
int mainfds[2] = {0};
|
|
|
|
int errfds[2] = {0};
|
|
|
|
|
|
|
|
if (pipe(mainfds) != 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pipe(errfds) != 0) {
|
|
|
|
close(mainfds[0]);
|
|
|
|
close(mainfds[1]);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (posix_spawn_file_actions_init(&file_actions) != 0) {
|
|
|
|
close(mainfds[0]);
|
|
|
|
close(mainfds[1]);
|
|
|
|
close(errfds[0]);
|
|
|
|
close(errfds[1]);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-04-19 19:18:17 +00:00
|
|
|
fcntl(mainfds[0], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(mainfds[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(errfds[0], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(errfds[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
|
2020-09-12 04:33:27 +00:00
|
|
|
if (process_pipe.read_pipe) {
|
|
|
|
posix_spawn_file_actions_addclose(&file_actions, mainfds[0]);
|
|
|
|
if (mainfds[1] != STDOUT_FILENO) {
|
|
|
|
posix_spawn_file_actions_adddup2(
|
|
|
|
&file_actions, mainfds[1], STDOUT_FILENO);
|
|
|
|
posix_spawn_file_actions_addclose(&file_actions,
|
|
|
|
mainfds[0]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mainfds[0] != STDIN_FILENO) {
|
|
|
|
posix_spawn_file_actions_adddup2(
|
|
|
|
&file_actions, mainfds[0], STDIN_FILENO);
|
|
|
|
posix_spawn_file_actions_addclose(&file_actions,
|
|
|
|
mainfds[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
posix_spawn_file_actions_addclose(&file_actions, errfds[0]);
|
|
|
|
posix_spawn_file_actions_adddup2(&file_actions, errfds[1],
|
|
|
|
STDERR_FILENO);
|
|
|
|
|
|
|
|
int pid;
|
2024-01-14 03:17:53 +00:00
|
|
|
int ret = posix_spawn(&pid, bin, &file_actions, NULL,
|
|
|
|
(char *const *)argv, NULL);
|
2020-09-12 04:33:27 +00:00
|
|
|
|
|
|
|
posix_spawn_file_actions_destroy(&file_actions);
|
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
close(mainfds[0]);
|
|
|
|
close(mainfds[1]);
|
|
|
|
close(errfds[0]);
|
|
|
|
close(errfds[1]);
|
2014-11-27 05:36:48 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-09-12 04:33:27 +00:00
|
|
|
close(errfds[1]);
|
|
|
|
process_pipe.err_file = fdopen(errfds[0], "r");
|
|
|
|
|
|
|
|
if (process_pipe.read_pipe) {
|
|
|
|
close(mainfds[1]);
|
|
|
|
process_pipe.file = fdopen(mainfds[0], "r");
|
|
|
|
} else {
|
|
|
|
close(mainfds[0]);
|
|
|
|
process_pipe.file = fdopen(mainfds[1], "w");
|
|
|
|
}
|
|
|
|
|
|
|
|
process_pipe.pid = pid;
|
|
|
|
|
|
|
|
out = bmalloc(sizeof(os_process_pipe_t));
|
|
|
|
*out = process_pipe;
|
2014-11-27 05:36:48 +00:00
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2024-01-14 03:17:53 +00:00
|
|
|
os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
|
|
|
|
const char *type)
|
|
|
|
{
|
|
|
|
if (!cmd_line)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
char *argv[3] = {"-c", (char *)cmd_line, NULL};
|
|
|
|
return os_process_pipe_create_internal("/bin/sh", argv, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
os_process_pipe_t *os_process_pipe_create2(const os_process_args_t *args,
|
|
|
|
const char *type)
|
|
|
|
{
|
|
|
|
char **argv = os_process_args_get_argv(args);
|
|
|
|
return os_process_pipe_create_internal(argv[0], argv, type);
|
|
|
|
}
|
|
|
|
|
2015-06-08 18:30:51 +00:00
|
|
|
int os_process_pipe_destroy(os_process_pipe_t *pp)
|
2014-11-27 05:36:48 +00:00
|
|
|
{
|
2015-06-08 18:30:51 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
2014-11-27 05:36:48 +00:00
|
|
|
if (pp) {
|
2020-09-12 04:33:27 +00:00
|
|
|
int status;
|
|
|
|
|
|
|
|
fclose(pp->file);
|
|
|
|
pp->file = NULL;
|
|
|
|
|
|
|
|
fclose(pp->err_file);
|
|
|
|
pp->err_file = NULL;
|
|
|
|
|
|
|
|
do {
|
|
|
|
ret = waitpid(pp->pid, &status, 0);
|
|
|
|
} while (ret == -1 && errno == EINTR);
|
|
|
|
|
2015-06-08 18:30:51 +00:00
|
|
|
if (WIFEXITED(status))
|
|
|
|
ret = (int)(char)WEXITSTATUS(status);
|
2014-11-27 05:36:48 +00:00
|
|
|
bfree(pp);
|
|
|
|
}
|
2015-06-08 18:30:51 +00:00
|
|
|
|
|
|
|
return ret;
|
2014-11-27 05:36:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data, size_t len)
|
|
|
|
{
|
|
|
|
if (!pp) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!pp->read_pipe) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-29 09:50:05 +00:00
|
|
|
return fread(data, 1, len, pp->file);
|
2014-11-27 05:36:48 +00:00
|
|
|
}
|
|
|
|
|
2019-03-30 14:45:23 +00:00
|
|
|
size_t os_process_pipe_read_err(os_process_pipe_t *pp, uint8_t *data,
|
|
|
|
size_t len)
|
|
|
|
{
|
2020-09-12 04:33:27 +00:00
|
|
|
if (!pp) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fread(data, 1, len, pp->err_file);
|
2019-03-30 14:45:23 +00:00
|
|
|
}
|
|
|
|
|
2014-11-27 05:36:48 +00:00
|
|
|
size_t os_process_pipe_write(os_process_pipe_t *pp, const uint8_t *data,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
if (!pp) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (pp->read_pipe) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-02-24 00:57:46 +00:00
|
|
|
size_t written = 0;
|
|
|
|
while (written < len) {
|
|
|
|
size_t ret = fwrite(data + written, 1, len - written, pp->file);
|
|
|
|
if (!ret)
|
|
|
|
return written;
|
2020-09-12 04:33:27 +00:00
|
|
|
|
2020-02-24 00:57:46 +00:00
|
|
|
written += ret;
|
|
|
|
}
|
|
|
|
return written;
|
2014-11-27 05:36:48 +00:00
|
|
|
}
|