Added some more signatures
This commit is contained in:
200
src/utils.c
200
src/utils.c
@@ -6,6 +6,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
LogLevel log_level = LOG_LEVEL_WARNING;
|
||||
|
||||
@@ -87,3 +90,200 @@ Result format(char** out_string, const char* fmt, ...) {
|
||||
*out_string = buffer;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr, const char* executable, ...) {
|
||||
if (out_exit_code != NULL)
|
||||
*out_exit_code = -1;
|
||||
|
||||
if (out_stdout != NULL)
|
||||
*out_stdout = NULL;
|
||||
if (out_stderr != NULL)
|
||||
*out_stderr = NULL;
|
||||
|
||||
// Count the number of arguments
|
||||
int argc = 1; // The first argument is the executable itself
|
||||
|
||||
va_list args;
|
||||
va_start(args, executable);
|
||||
|
||||
while (va_arg(args, const char*) != NULL)
|
||||
argc++;
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Allocate an array for the arguments
|
||||
char** argv = calloc(argc + 1, sizeof(char*));
|
||||
if (argv == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to allocate memory for the arguments (%s).", strerror(errno));
|
||||
return OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Fill the array with the arguments
|
||||
argv[0] = strdup(executable);
|
||||
if (argv[0] == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to duplicate the executable string (%s).", strerror(errno));
|
||||
|
||||
free(argv);
|
||||
|
||||
return OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
va_start(args, executable);
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
argv[i] = strdup(va_arg(args, const char*));
|
||||
if (argv[i] == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to duplicate the argument string (%s).", strerror(errno));
|
||||
|
||||
for (int j = 0; j < i; j++)
|
||||
free(argv[j]);
|
||||
free(argv);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Set the last element of the array to NULL
|
||||
argv[argc] = NULL;
|
||||
|
||||
// Create pipes for the stdout and stderr
|
||||
int stdout_pipe[2];
|
||||
if (pipe(stdout_pipe) == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to create the stdout pipe (%s).", strerror(errno));
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int stderr_pipe[2];
|
||||
if (pipe(stderr_pipe) == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to create the stderr pipe (%s).", strerror(errno));
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
|
||||
close(stdout_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Fork the process
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to fork the process (%s).", strerror(errno));
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
|
||||
close(stdout_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
close(stderr_pipe[0]);
|
||||
close(stderr_pipe[1]);
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// Redirect the stdout and stderr to the pipes
|
||||
dup2(stdout_pipe[1], STDOUT_FILENO);
|
||||
dup2(stderr_pipe[1], STDERR_FILENO);
|
||||
|
||||
// Close the unused ends of the pipes
|
||||
close(stdout_pipe[0]);
|
||||
close(stdout_pipe[1]);
|
||||
close(stderr_pipe[0]);
|
||||
close(stderr_pipe[1]);
|
||||
|
||||
// Execute the command
|
||||
execvp(executable, argv);
|
||||
|
||||
// If the command failed to execute, print an error message and exit
|
||||
fprintf(stderr, "Failed to execute the command '%s' (%s).\n", executable, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Free the arguments array
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
|
||||
// Close the unused ends of the pipes
|
||||
close(stdout_pipe[1]);
|
||||
close(stderr_pipe[1]);
|
||||
|
||||
// Wait for the child process to finish
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
// Read the output from the pipes
|
||||
if (out_stdout != NULL)
|
||||
read_fd(stdout_pipe[0], out_stdout);
|
||||
if (out_stderr != NULL)
|
||||
read_fd(stderr_pipe[0], out_stderr);
|
||||
|
||||
// Close the pipes
|
||||
close(stdout_pipe[0]);
|
||||
close(stderr_pipe[0]);
|
||||
|
||||
// Set the exit code
|
||||
if (out_exit_code != NULL)
|
||||
*out_exit_code = WEXITSTATUS(status);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result read_fd(int fd, char** out_string) {
|
||||
*out_string = NULL;
|
||||
|
||||
// Create a buffer for the output
|
||||
char buffer[4096];
|
||||
size_t length = 0;
|
||||
|
||||
// Read the output from the file descriptor
|
||||
ssize_t bytes_read;
|
||||
while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
|
||||
// Reallocate the buffer
|
||||
char* new_buffer = realloc(*out_string, length + bytes_read + 1);
|
||||
if (new_buffer == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to reallocate memory for the output string (%s).", strerror(errno));
|
||||
|
||||
free(*out_string);
|
||||
*out_string = NULL;
|
||||
|
||||
return OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*out_string = new_buffer;
|
||||
|
||||
// Copy the new data to the buffer
|
||||
memcpy(*out_string + length, buffer, bytes_read);
|
||||
length += bytes_read;
|
||||
}
|
||||
|
||||
// Check if an error occurred
|
||||
if (bytes_read == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to read from the file descriptor (%s).", strerror(errno));
|
||||
|
||||
free(*out_string);
|
||||
*out_string = NULL;
|
||||
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Null-terminate the string
|
||||
if (length > 0)
|
||||
(*out_string)[length] = '\0';
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
Reference in New Issue
Block a user