From ae0520e57267dbd866fc8cd25f66f4e6af2ac118 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 13 Jul 2020 15:59:30 +0200 Subject: Move c files into src directory --- src/program.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 src/program.c (limited to 'src/program.c') diff --git a/src/program.c b/src/program.c new file mode 100644 index 0000000..c396695 --- /dev/null +++ b/src/program.c @@ -0,0 +1,111 @@ +#include "program.h" +#include "buffer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define READ_END 0 +#define WRITE_END 1 + +int program_buffer_write_callback(char *data, int size, void *userdata) { + Buffer *buffer = userdata; + buffer_append(buffer, data, size); + return 0; +} + +int program_exec(const char **args, ProgramOutputCallback output_callback, void *userdata) { + /* 1 arguments */ + if(args[0] == NULL) + return -1; + + int fd[2]; + if(pipe(fd) == -1) { + perror("Failed to open pipe"); + return -2; + } + + pid_t parent_pid = getpid(); + + pid_t pid = fork(); + if(pid == -1) { + perror("Failed to fork"); + return -3; + } else if(pid == 0) { /* child */ + if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) { + perror("prctl(PR_SET_PDEATHSIG, SIGTERM) failed"); + exit(127); + } + + /* Test if the parent died before the above call to prctl */ + if(getppid() != parent_pid) + exit(127); + + dup2(fd[WRITE_END], STDOUT_FILENO); + close(fd[READ_END]); + close(fd[WRITE_END]); + + execvp(args[0], (char* const*)args); + perror("execvp"); + exit(127); + } else { /* parent */ + close(fd[WRITE_END]); + + int result = 0; + int status; + + char buffer[4097]; + + if(output_callback) { + for(;;) { + ssize_t bytes_read = read(fd[READ_END], buffer, sizeof(buffer) - 1); + if(bytes_read == 0) { + break; + } else if(bytes_read == -1) { + int err = errno; + fprintf(stderr, "Failed to read from pipe to program %s, error: %s\n", args[0], strerror(err)); + result = -err; + goto cleanup; + } + + buffer[bytes_read] = '\0'; + if(output_callback(buffer, bytes_read, userdata) != 0) + break; + } + } + + if(waitpid(pid, &status, 0) == -1) { + perror("waitpid failed"); + result = -5; + goto cleanup; + } + + if(!WIFEXITED(status)) { + result = -4; + goto cleanup; + } + + int exit_status = WEXITSTATUS(status); + if(exit_status != 0) { + fprintf(stderr, "Failed to execute program ("); + const char **arg = args; + while(*arg) { + if(arg != args) + fputc(' ', stderr); + fprintf(stderr, "'%s'", *arg); + ++arg; + } + fprintf(stderr, "), exit status %d\n", exit_status); + result = -exit_status; + goto cleanup; + } + + cleanup: + close(fd[READ_END]); + return result; + } +} -- cgit v1.2.3