Reimplemented most functions
This commit is contained in:
321
src/utils.c
321
src/utils.c
@@ -3,21 +3,21 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
LogLevel log_level = LOG_LEVEL_WARNING;
|
||||
LogLevel log_level = LOG_LEVEL_INFO;
|
||||
|
||||
void set_log_level(LogLevel level) {
|
||||
void SetLogLevel(LogLevel level) {
|
||||
log_level = level;
|
||||
}
|
||||
|
||||
void log_message(LogLevel level, const char* format, ...) {
|
||||
void Log(LogLevel level, const char* format, ...) {
|
||||
if (level < log_level)
|
||||
return;
|
||||
|
||||
@@ -26,13 +26,15 @@ void log_message(LogLevel level, const char* format, ...) {
|
||||
|
||||
const char* color;
|
||||
const char* level_str;
|
||||
|
||||
// Set the color and level_str based on the log level
|
||||
switch (level) {
|
||||
case LOG_LEVEL_DEBUG:
|
||||
color = "\033[0;90m";
|
||||
level_str = "DEBUG";
|
||||
break;
|
||||
case LOG_LEVEL_INFO:
|
||||
color = "\033[0;36m";
|
||||
level_str = "INFO";
|
||||
case LOG_LEVEL_WARNING:
|
||||
color = "\033[0;33m";
|
||||
level_str = "WARNING";
|
||||
@@ -58,48 +60,44 @@ void log_message(LogLevel level, const char* format, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
Result format(char** out_string, const char* fmt, ...) {
|
||||
*out_string = NULL;
|
||||
Status Format(char** _string, const char* fmt, ...) {
|
||||
*_string = NULL;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
// Calculate the length of the formatted string
|
||||
size_t length = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
|
||||
va_end(args);
|
||||
|
||||
if (length <= 0) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to calculate the length of the formatted string (%s).", strerror(errno));
|
||||
Log(LOG_LEVEL_ERROR, "Failed to calculate the length of the formatted string.");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Allocate a buffer for the formatted string
|
||||
char* buffer = calloc(length, sizeof(char));
|
||||
if (buffer == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to allocate memory for the formatted string (%s).", strerror(errno));
|
||||
return OUT_OF_MEMORY;
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for the formatted string (%s).", strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
// Format the string
|
||||
vsnprintf(buffer, length, fmt, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
*out_string = buffer;
|
||||
*_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;
|
||||
Status RunExecutable(int* _exit_code, char** _stdout, char** _stderr, const char* executable, ...) {
|
||||
if (_exit_code != NULL)
|
||||
*_exit_code = -1;
|
||||
if (_stdout != NULL)
|
||||
*_stdout = NULL;
|
||||
if (_stderr != NULL)
|
||||
*_stderr = NULL;
|
||||
|
||||
// Count the number of arguments
|
||||
int argc = 1; // The first argument is the executable itself
|
||||
@@ -113,48 +111,44 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
|
||||
va_end(args);
|
||||
|
||||
// Allocate an array for the arguments
|
||||
char** argv = calloc(argc + 1, sizeof(char*));
|
||||
char** argv = calloc(argc + 1, sizeof(char*)); // +1 for the NULL terminator
|
||||
if (argv == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to allocate memory for the arguments (%s).", strerror(errno));
|
||||
return OUT_OF_MEMORY;
|
||||
Log(LOG_LEVEL_ERROR, "Failed to allocate memory for the arguments array (%s).", strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Fill the array with the arguments
|
||||
// Fill the arguments array
|
||||
argv[0] = strdup(executable);
|
||||
if (argv[0] == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to duplicate the executable string (%s).", strerror(errno));
|
||||
|
||||
Log(LOG_LEVEL_ERROR, "Failed to duplicate the executable path (%s).", strerror(errno));
|
||||
free(argv);
|
||||
|
||||
return OUT_OF_MEMORY;
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
va_start(args, executable);
|
||||
|
||||
// Duplicate the arguments and store them in the array
|
||||
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));
|
||||
Log(LOG_LEVEL_ERROR, "Failed to duplicate the argument n°%d (%s).", i, strerror(errno));
|
||||
|
||||
for (int j = 0; j < i; j++)
|
||||
free(argv[j]);
|
||||
free(argv);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return OUT_OF_MEMORY;
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
// Set the last element of the array to NULL
|
||||
argv[argc] = NULL;
|
||||
|
||||
// Create pipes for the stdout and stderr
|
||||
// Create pipes for the standard output and error
|
||||
int stdout_pipe[2];
|
||||
if (pipe(stdout_pipe) == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to create the stdout pipe (%s).", strerror(errno));
|
||||
Log(LOG_LEVEL_ERROR, "Failed to create the standard output pipe (%s).", strerror(errno));
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
@@ -165,7 +159,7 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
|
||||
|
||||
int stderr_pipe[2];
|
||||
if (pipe(stderr_pipe) == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to create the stderr pipe (%s).", strerror(errno));
|
||||
Log(LOG_LEVEL_ERROR, "Failed to create the standard error pipe (%s).", strerror(errno));
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
@@ -181,7 +175,7 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to fork the process (%s).", strerror(errno));
|
||||
Log(LOG_LEVEL_ERROR, "Failed to fork the process (%s).", strerror(errno));
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
@@ -196,7 +190,7 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// Redirect the stdout and stderr to the pipes
|
||||
// Redirect the standard output and error to the pipes
|
||||
dup2(stdout_pipe[1], STDOUT_FILENO);
|
||||
dup2(stderr_pipe[1], STDERR_FILENO);
|
||||
|
||||
@@ -207,116 +201,84 @@ Result run_executable(int* out_exit_code, char** out_stdout, char** out_stderr,
|
||||
close(stderr_pipe[1]);
|
||||
|
||||
// Execute the command
|
||||
execvp(executable, argv);
|
||||
execv(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));
|
||||
// If execv returns, it failed
|
||||
fprintf(stderr, "Failed to execute the command (%s).\n", 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
|
||||
// Free the arguments
|
||||
for (int i = 0; i < argc; i++)
|
||||
free(argv[i]);
|
||||
free(argv);
|
||||
|
||||
// Wait for the child process to terminate
|
||||
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);
|
||||
// Read the standard output and error
|
||||
if (_stdout != NULL)
|
||||
ReadFileDescriptor(stdout_pipe[0], _stdout);
|
||||
|
||||
if (_stderr != NULL)
|
||||
ReadFileDescriptor(stderr_pipe[0], _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);
|
||||
if (_exit_code != NULL)
|
||||
*_exit_code = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result read_fd(int fd, char** out_string) {
|
||||
*out_string = NULL;
|
||||
Status ReadFileDescriptor(int fd, char** _content) {
|
||||
*_content = NULL;
|
||||
|
||||
// Create a buffer for the output
|
||||
// Allocate a buffer for the content
|
||||
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;
|
||||
char* new_content = realloc(*_content, length + bytes_read + 1); // +1 for the NULL terminator
|
||||
if (new_content == NULL) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to reallocate memory for the file content (%s).", strerror(errno));
|
||||
free(*_content);
|
||||
return FAILURE;
|
||||
}
|
||||
*_content = new_content;
|
||||
|
||||
*out_string = new_buffer;
|
||||
|
||||
// Copy the new data to the buffer
|
||||
memcpy(*out_string + length, buffer, bytes_read);
|
||||
memcpy(*_content + length, buffer, bytes_read);
|
||||
length += bytes_read;
|
||||
|
||||
(*_content)[length] = '\0';
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
Log(LOG_LEVEL_ERROR, "Failed to read from the file descriptor (%s).", strerror(errno));
|
||||
free(*_content);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Null-terminate the string
|
||||
if (length > 0)
|
||||
(*out_string)[length] = '\0';
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result read_file(const char* path, char** out_string) {
|
||||
*out_string = NULL;
|
||||
|
||||
// Open the file
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to open the file '%s' (%s).", path, strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
Result result = read_fd(fd, out_string);
|
||||
|
||||
// Close the file
|
||||
close(fd);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Result write_fd(int fd, const char* string) {
|
||||
// Write the string to the file descriptor
|
||||
size_t length = strlen(string);
|
||||
Status WriteFileDescriptor(int fd, const char* content) {
|
||||
size_t length = strlen(content);
|
||||
ssize_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < length) {
|
||||
ssize_t result = write(fd, string + bytes_written, length - bytes_written);
|
||||
ssize_t result = write(fd, content + bytes_written, length - bytes_written);
|
||||
if (result == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to write to the file descriptor (%s).", strerror(errno));
|
||||
Log(LOG_LEVEL_ERROR, "Failed to write to the file descriptor (%s).", strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
@@ -326,141 +288,38 @@ Result write_fd(int fd, const char* string) {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result write_file(const char* path, const char* string) {
|
||||
Status ReadFile(const char* path, char** _content) {
|
||||
*_content = NULL;
|
||||
|
||||
// Open the file
|
||||
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to open the file '%s' (%s).", path, strerror(errno));
|
||||
int file = open(path, O_RDONLY);
|
||||
if (file == -1) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to open the file %s (%s).", path, strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Write the string to the file
|
||||
Result result = write_fd(fd, string);
|
||||
// Read the file
|
||||
Status status = ReadFileDescriptor(file, _content);
|
||||
|
||||
// Close the file
|
||||
close(fd);
|
||||
close(file);
|
||||
|
||||
return result;
|
||||
return status;
|
||||
}
|
||||
|
||||
Result copy_file(const char* src_path, const char* dst_path, mode_t mode) {
|
||||
// Open the source file
|
||||
int src_fd = open(src_path, O_RDONLY);
|
||||
if (src_fd == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to open the source file '%s' (%s).", src_path, strerror(errno));
|
||||
Status WriteFile(const char* path, const char* content) {
|
||||
// Open the file
|
||||
int file = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (file == -1) {
|
||||
Log(LOG_LEVEL_ERROR, "Failed to open the file %s (%s).", path, strerror(errno));
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Open the destination file
|
||||
int dst_fd = open(dst_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
||||
if (dst_fd == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to open the destination file '%s' (%s).", dst_path, strerror(errno));
|
||||
// Write the content
|
||||
Status status = WriteFileDescriptor(file, content);
|
||||
|
||||
close(src_fd);
|
||||
return FAILURE;
|
||||
}
|
||||
// Close the file
|
||||
close(file);
|
||||
|
||||
// Copy the file
|
||||
char buffer[4096];
|
||||
ssize_t bytes_read;
|
||||
|
||||
while ((bytes_read = read(src_fd, buffer, sizeof(buffer))) > 0) {
|
||||
ssize_t bytes_written = 0;
|
||||
|
||||
while (bytes_written < bytes_read) {
|
||||
ssize_t result = write(dst_fd, buffer + bytes_written, bytes_read - bytes_written);
|
||||
if (result == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to write to the destination file '%s' (%s).", dst_path, strerror(errno));
|
||||
|
||||
close(src_fd);
|
||||
close(dst_fd);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
bytes_written += result;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if an error occurred
|
||||
if (bytes_read == -1) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to read from the source file '%s' (%s).", src_path, strerror(errno));
|
||||
|
||||
close(src_fd);
|
||||
close(dst_fd);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Close the files
|
||||
close(src_fd);
|
||||
close(dst_fd);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Result format_size(uint64_t size, char** out_string) {
|
||||
*out_string = NULL;
|
||||
|
||||
// Determine the unit
|
||||
const char* unit;
|
||||
double value;
|
||||
|
||||
if (size < 1024ULL) {
|
||||
unit = "B";
|
||||
value = size;
|
||||
} else if (size < 1024ULL * 1024) {
|
||||
unit = "KiB";
|
||||
value = (double)size / 1024;
|
||||
} else if (size < 1024ULL * 1024 * 1024) {
|
||||
unit = "MiB";
|
||||
value = (double)size / (1024 * 1024);
|
||||
} else if (size < 1024ULL * 1024 * 1024 * 1024) {
|
||||
unit = "GiB";
|
||||
value = (double)size / (1024 * 1024 * 1024);
|
||||
} else if (size < 1024ULL * 1024 * 1024 * 1024 * 1024) {
|
||||
unit = "TiB";
|
||||
value = (double)size / (1024 * 1024 * 1024 * 1024);
|
||||
} else {
|
||||
unit = "PiB";
|
||||
value = (double)size / (1024 * 1024 * 1024 * 1024 * 1024);
|
||||
}
|
||||
|
||||
// Format the string
|
||||
return format(out_string, "%.2f%s", value, unit);
|
||||
}
|
||||
|
||||
Result parse_size(const char* string, uint64_t* out_size) {
|
||||
// Parse the size
|
||||
char* endptr;
|
||||
uint64_t size = strtoull(string, &endptr, 10);
|
||||
|
||||
if (endptr == string) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to parse the size '%s'.", string);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Determine the unit
|
||||
if (*endptr == '\0') {
|
||||
// No unit
|
||||
*out_size = size;
|
||||
} else if (strcmp(endptr, "K") == 0 || strcmp(endptr, "KB") == 0 || strcmp(endptr, "KiB") == 0) {
|
||||
// Kilobytes
|
||||
*out_size = size * 1024;
|
||||
} else if (strcmp(endptr, "M") == 0 || strcmp(endptr, "MB") == 0 || strcmp(endptr, "MiB") == 0) {
|
||||
// Megabytes
|
||||
*out_size = size * 1024 * 1024;
|
||||
} else if (strcmp(endptr, "G") == 0 || strcmp(endptr, "GB") == 0 || strcmp(endptr, "GiB") == 0) {
|
||||
// Gigabytes
|
||||
*out_size = size * 1024 * 1024 * 1024;
|
||||
} else if (strcmp(endptr, "T") == 0 || strcmp(endptr, "TB") == 0 || strcmp(endptr, "TiB") == 0) {
|
||||
// Terabytes
|
||||
*out_size = size * 1024 * 1024 * 1024 * 1024;
|
||||
} else if (strcmp(endptr, "P") == 0 || strcmp(endptr, "PB") == 0 || strcmp(endptr, "PiB") == 0) {
|
||||
// Petabytes
|
||||
*out_size = size * 1024 * 1024 * 1024 * 1024 * 1024;
|
||||
} else {
|
||||
log_message(LOG_LEVEL_ERROR, "Unknown unit '%s'.", endptr);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
Reference in New Issue
Block a user