From 94c45e3c4d185b3f0d70f0d2d761b72c6561e1b5 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 14 Jul 2020 06:55:18 +0200 Subject: Implement add_html --- src/program.c | 175 ++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 41 deletions(-) (limited to 'src/program.c') diff --git a/src/program.c b/src/program.c index c396695..6150616 100644 --- a/src/program.c +++ b/src/program.c @@ -18,8 +18,42 @@ int program_buffer_write_callback(char *data, int size, void *userdata) { return 0; } +static int program_read_output(int process_id, int read_fd, ProgramOutputCallback output_callback, void *userdata) { + int status; + char buffer[4097]; + + for(;;) { + ssize_t bytes_read = read(read_fd, buffer, sizeof(buffer) - 1); + if(bytes_read == 0) { + break; + } else if(bytes_read == -1) { + int err = errno; + fprintf(stderr, "Failed to read from pipe, error: %s\n", strerror(err)); + return -err; + } + + buffer[bytes_read] = '\0'; + if(output_callback && output_callback(buffer, bytes_read, userdata) != 0) + break; + } + + if(waitpid(process_id, &status, 0) == -1) { + perror("waitpid failed"); + return -5; + } + + if(!WIFEXITED(status)) + return -4; + + int exit_status = WEXITSTATUS(status); + if(exit_status != 0) + return -exit_status; + + return 0; +} + int program_exec(const char **args, ProgramOutputCallback output_callback, void *userdata) { - /* 1 arguments */ + /* 1 argument */ if(args[0] == NULL) return -1; @@ -34,6 +68,8 @@ int program_exec(const char **args, ProgramOutputCallback output_callback, void pid_t pid = fork(); if(pid == -1) { perror("Failed to fork"); + close(fd[READ_END]); + close(fd[WRITE_END]); return -3; } else if(pid == 0) { /* child */ if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) { @@ -55,42 +91,8 @@ int program_exec(const char **args, ProgramOutputCallback output_callback, void } 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) { + int result = program_read_output(pid, fd[READ_END], output_callback, userdata); + if(result != 0) { fprintf(stderr, "Failed to execute program ("); const char **arg = args; while(*arg) { @@ -99,13 +101,104 @@ int program_exec(const char **args, ProgramOutputCallback output_callback, void fprintf(stderr, "'%s'", *arg); ++arg; } - fprintf(stderr, "), exit status %d\n", exit_status); - result = -exit_status; - goto cleanup; + fprintf(stderr, ")\n"); } - cleanup: close(fd[READ_END]); return result; } } + +int program_exec_async(const char **args, int *process_id, int *stdin_file, int *stdout_file) { + int result = 0; + + /* 1 argument */ + if(args[0] == NULL) + return -1; + + int stdin_fd[2] = { -1, -1 }; + int stdout_fd[2] = { -1, -1 }; + + if(stdin_file) { + if(pipe(stdin_fd) == -1) { + perror("Failed to open pipe"); + result = -2; + goto cleanup; + } + } + + if(stdout_file) { + if(pipe(stdout_fd) == -1) { + perror("Failed to open pipe"); + result = -2; + goto cleanup; + } + } + + pid_t parent_pid = getpid(); + + pid_t pid = fork(); + if(pid == -1) { + result = -errno; + perror("failed to fork"); + goto cleanup; + } 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); + + if(stdin_file) { + dup2(stdin_fd[READ_END], STDIN_FILENO); + close(stdin_fd[READ_END]); + close(stdin_fd[WRITE_END]); + } + + if(stdout_file) { + dup2(stdout_fd[WRITE_END], STDOUT_FILENO); + close(stdout_fd[READ_END]); + close(stdout_fd[WRITE_END]); + } + + execvp(args[0], (char* const*)args); + perror("execvp"); + exit(127); + } else { /* parent */ + if(process_id) + *process_id = pid; + + if(stdin_file) + close(stdin_fd[READ_END]); + + if(stdout_file) + close(stdout_fd[WRITE_END]); + + *stdin_file = stdin_fd[WRITE_END]; + *stdout_file = stdout_fd[READ_END]; + + return 0; + } + + cleanup: + if(stdin_fd[0] != -1) close(stdin_fd[0]); + if(stdin_fd[1] != -1) close(stdin_fd[1]); + if(stdout_fd[0] != -1) close(stdout_fd[0]); + if(stdout_fd[1] != -1) close(stdout_fd[1]); + return result; +} + +int program_wait_until_exit(int process_id, int stdin_file, int stdout_file, ProgramOutputCallback output_callback, void *userdata) { + if(stdin_file != -1) + close(stdin_file); + + int result = program_read_output(process_id, stdout_file, output_callback, userdata); + + if(stdout_file != -1) + close(stdout_file); + + return result; +} -- cgit v1.2.3