summaryrefslogtreecommitdiff
path: root/process-posix.c
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-01-01 23:16:38 -0500
committerpommicket <pommicket@gmail.com>2023-01-01 23:16:38 -0500
commitf173b7715cf1385db1cea67a3db07bb7d38174e9 (patch)
tree8d56748af7592ed94f11393252c1fb5419279d26 /process-posix.c
parent850ab378946e8d6f0818b4ccf8eee413f68dcb95 (diff)
finish os.h amalgamation
Diffstat (limited to 'process-posix.c')
-rw-r--r--process-posix.c198
1 files changed, 0 insertions, 198 deletions
diff --git a/process-posix.c b/process-posix.c
deleted file mode 100644
index 57af73f..0000000
--- a/process-posix.c
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "process.h"
-
-#include <fcntl.h>
-#include <sys/wait.h>
-#include <signal.h>
-
-struct Process {
- pid_t pid;
- int stdout_pipe;
- // only applicable if separate_stderr was specified.
- int stderr_pipe;
- int stdin_pipe;
- char error[64];
-};
-
-int process_get_id(void) {
- return getpid();
-}
-
-static void set_nonblocking(int fd) {
- fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
-}
-
-bool process_run_ex(Process *proc, const char *command, const ProcessSettings *settings) {
- memset(proc, 0, sizeof *proc);
-
- int stdin_pipe[2] = {0}, stdout_pipe[2] = {0}, stderr_pipe[2] = {0};
- if (pipe(stdin_pipe) != 0) {
- strbuf_printf(proc->error, "%s", strerror(errno));
- return false;
- }
- if (pipe(stdout_pipe) != 0) {
- strbuf_printf(proc->error, "%s", strerror(errno));
- close(stdin_pipe[0]);
- close(stdin_pipe[1]);
- return false;
- }
- if (settings->separate_stderr) {
- if (pipe(stderr_pipe) != 0) {
- strbuf_printf(proc->error, "%s", strerror(errno));
- close(stdin_pipe[0]);
- close(stdin_pipe[1]);
- close(stdout_pipe[0]);
- close(stdout_pipe[1]);
- return false;
- }
- }
-
- bool success = false;
- pid_t pid = fork();
- if (pid == 0) {
- // child process
- chdir(settings->working_directory);
- // put child in its own group. it will be in this group with all of its descendents,
- // so by killing everything in the group, we kill all the descendents of this process.
- // if we didn't do this, we would just be killing the sh process in process_kill.
- setpgid(0, 0);
- // pipe stuff
- dup2(stdout_pipe[1], STDOUT_FILENO);
- if (stderr_pipe[1])
- dup2(stderr_pipe[1], STDERR_FILENO);
- else
- dup2(stdout_pipe[1], STDERR_FILENO);
- dup2(stdin_pipe[0], STDIN_FILENO);
- // don't need these file descriptors anymore
- close(stdin_pipe[0]);
- close(stdin_pipe[1]);
- close(stdout_pipe[0]);
- close(stdout_pipe[1]);
- if (stderr_pipe[0]) {
- close(stderr_pipe[0]);
- close(stderr_pipe[1]);
- }
-
- char *program = "/bin/sh";
- char *argv[] = {program, "-c", (char *)command, NULL};
- if (execv(program, argv) == -1) {
- dprintf(STDERR_FILENO, "%s: %s\n", program, strerror(errno));
- exit(127);
- }
- } else if (pid > 0) {
- // parent process
-
- // we're reading from (the child's) stdout/stderr and writing to stdin,
- // so we don't need the write end of the stdout pipe or the
- // read end of the stdin pipe.
- close(stdout_pipe[1]);
- if (stderr_pipe[1])
- close(stderr_pipe[1]);
- close(stdin_pipe[0]);
- // set pipes to non-blocking
- if (!settings->stdout_blocking)
- set_nonblocking(stdout_pipe[0]);
- if (stderr_pipe[0] && !settings->stderr_blocking)
- set_nonblocking(stderr_pipe[0]);
- if (!settings->stdin_blocking)
- set_nonblocking(stdin_pipe[1]);
- proc->pid = pid;
- proc->stdout_pipe = stdout_pipe[0];
- if (stderr_pipe[0])
- proc->stderr_pipe = stderr_pipe[0];
- proc->stdin_pipe = stdin_pipe[1];
- success = true;
- }
- return success;
-}
-
-bool process_run(Process *proc, char const *command) {
- const ProcessSettings settings = {0};
- return process_run_ex(proc, command, &settings);
-}
-
-
-char const *process_geterr(Process *p) {
- return *p->error ? p->error : NULL;
-}
-
-long long process_write(Process *proc, const char *data, size_t size) {
- assert(proc->stdin_pipe); // check that process hasn't been killed
- ssize_t bytes_written = write(proc->stdin_pipe, data, size);
- if (bytes_written >= 0) {
- return (long long)bytes_written;
- } else if (errno == EAGAIN) {
- return 0;
- } else {
- strbuf_printf(proc->error, "%s", strerror(errno));
- return -2;
- }
-}
-
-static long long process_read_fd(Process *proc, int fd, char *data, size_t size) {
- assert(fd);
- ssize_t bytes_read = read(fd, data, size);
- if (bytes_read >= 0) {
- return (long long)bytes_read;
- } else if (errno == EAGAIN) {
- return -1;
- } else {
- strbuf_printf(proc->error, "%s", strerror(errno));
- return -2;
- }
-}
-
-long long process_read(Process *proc, char *data, size_t size) {
- return process_read_fd(proc, proc->stdout_pipe, data, size);
-}
-
-long long process_read_stderr(Process *proc, char *data, size_t size) {
- return process_read_fd(proc, proc->stderr_pipe, data, size);
-}
-
-static void process_close_pipes(Process *proc) {
- close(proc->stdin_pipe);
- close(proc->stdout_pipe);
- close(proc->stderr_pipe);
- proc->stdin_pipe = 0;
- proc->stdout_pipe = 0;
- proc->stderr_pipe = 0;
-}
-
-void process_kill(Process *proc) {
- kill(-proc->pid, SIGKILL); // kill everything in process group
- // get rid of zombie process
- waitpid(proc->pid, NULL, 0);
- proc->pid = 0;
- process_close_pipes(proc);
-}
-
-int process_check_status(Process *proc, char *message, size_t message_size) {
- int wait_status = 0;
- int ret = waitpid(proc->pid, &wait_status, WNOHANG);
- if (ret == 0) {
- // process still running
- return 0;
- } else if (ret > 0) {
- if (WIFEXITED(wait_status)) {
- process_close_pipes(proc);
- int code = WEXITSTATUS(wait_status);
- if (code == 0) {
- str_printf(message, message_size, "exited successfully");
- return +1;
- } else {
- str_printf(message, message_size, "exited with code %d", code);
- return -1;
- }
- } else if (WIFSIGNALED(wait_status)) {
- process_close_pipes(proc);
- str_printf(message, message_size, "terminated by signal %d", WTERMSIG(wait_status));
- return -1;
- }
- return 0;
- } else {
- // this process is gone or something?
- process_close_pipes(proc);
- str_printf(message, message_size, "process ended unexpectedly");
- return -1;
- }
-}