#include "utils.h" #include #include #include #include #include #include #include #include #include #include char* format(const char* fmt, ...) { 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) return NULL; // Allocate a buffer for the formatted string char* buffer = calloc(length, sizeof(char)); if (buffer == NULL) { log_msg(LOG_ERROR, "Failed to allocate memory for the formatted string."); return NULL; } va_start(args, fmt); // Format the string vsnprintf(buffer, length, fmt, args); va_end(args); return buffer; } void log_msg(LogLevel level, const char* fmt, ...) { va_list args; va_start(args, fmt); const char* color; const char* level_str; // Set the color and level string based on the log level switch (level) { case LOG_DEBUG: color = "\033[0;90m"; level_str = "DEBUG"; break; case LOG_INFO: color = "\033[0;34m"; level_str = "INFO"; break; case LOG_WARN: color = "\033[0;33m"; level_str = "WARN"; break; case LOG_ERROR: color = "\033[0;31m"; level_str = "ERROR"; break; default: color = ""; level_str = "UNKNOWN"; break; } // Get the current time time_t t = time(NULL); struct tm* tm_info = localtime(&t); // Print the label fprintf(stderr, "%s[%02d/%02d/%02d %02d:%02d:%02d - %s]\033[m ", color, tm_info->tm_mday, tm_info->tm_mon + 1, (tm_info->tm_year + 1900) % 100, tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec, level_str); // Print the message vfprintf(stderr, fmt, args); // Print a newline fprintf(stderr, "\n"); // Flush the output fflush(stderr); va_end(args); } int execute(char** stdout_buffer, char** stderr_buffer, const char* file, ...) { // Count the number of arguments int argc = 1; // Include space for the file name va_list args; va_start(args, file); while (va_arg(args, char*) != NULL) argc++; va_end(args); // Allocate an array for the arguments char** argv = calloc(argc + 1, sizeof(char*)); // Include space for the NULL terminator if (argv == NULL) { log_msg(LOG_ERROR, "Failed to allocate memory for the argument array."); return -1; } // Fill the argument array va_start(args, file); argv[0] = strdup(file); for (int i = 1; i < argc; i++) argv[i] = strdup(va_arg(args, char*)); argv[argc] = NULL; va_end(args); // Create the stdout pipe for the child process int stdout_pipe[2]; if (pipe(stdout_pipe) == -1) { log_msg(LOG_ERROR, "Failed to create pipe for stdout."); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } // Create the stderr pipe for the child process int stderr_pipe[2]; if (pipe(stderr_pipe) == -1) { log_msg(LOG_ERROR, "Failed to create pipe for stderr."); close(stdout_pipe[0]); close(stdout_pipe[1]); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } // Fork the child process pid_t pid = fork(); if (pid == -1) { log_msg(LOG_ERROR, "Failed to fork child process."); close(stdout_pipe[0]); close(stdout_pipe[1]); close(stderr_pipe[0]); close(stderr_pipe[1]); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } if (pid == 0) { // Redirect stdout and stderr to the pipes dup2(stdout_pipe[1], STDOUT_FILENO); dup2(stderr_pipe[1], STDERR_FILENO); // Close the pipe file descriptors close(stdout_pipe[0]); close(stdout_pipe[1]); close(stderr_pipe[0]); close(stderr_pipe[1]); // Execute the command execvp(file, argv); // If execvp fails, log an error log_msg(LOG_ERROR, "Failed to execute command '%s'.", file); // Free the argument array for (int i = 0; i < argc; i++) free(argv[i]); free(argv); exit(1); } // Close the write end 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 stdout buffer char buffer[4096]; ssize_t bytes_read; if (stdout_buffer != NULL) { size_t stdout_length = 0; *stdout_buffer = NULL; // Read the stdout buffer while ((bytes_read = read(stdout_pipe[0], buffer, sizeof(buffer))) > 0) { char* new_stdout_buffer = realloc(*stdout_buffer, stdout_length + bytes_read + 1); // Include space for the null terminator if (new_stdout_buffer == NULL) { log_msg(LOG_ERROR, "Failed to allocate memory for the stdout buffer."); free(*stdout_buffer); close(stdout_pipe[0]); close(stderr_pipe[0]); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } *stdout_buffer = new_stdout_buffer; memcpy(*stdout_buffer + stdout_length, buffer, bytes_read); stdout_length += bytes_read; (*stdout_buffer)[stdout_length] = '\0'; } } // Close the read end of the stdout pipe close(stdout_pipe[0]); // Read the stderr buffer if (stderr_buffer != NULL) { size_t stderr_length = 0; *stderr_buffer = NULL; // Read the stderr buffer while ((bytes_read = read(stderr_pipe[0], buffer, sizeof(buffer))) > 0) { char* new_stderr_buffer = realloc(*stderr_buffer, stderr_length + bytes_read + 1); // Include space for the null terminator if (new_stderr_buffer == NULL) { log_msg(LOG_ERROR, "Failed to allocate memory for the stderr buffer."); free(*stdout_buffer); free(*stderr_buffer); close(stderr_pipe[0]); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } *stderr_buffer = new_stderr_buffer; memcpy(*stderr_buffer + stderr_length, buffer, bytes_read); stderr_length += bytes_read; (*stderr_buffer)[stderr_length] = '\0'; } } // Close the read end of the stderr pipe close(stderr_pipe[0]); // Free the argument array for (int i = 0; i < argc; i++) free(argv[i]); free(argv); // Return the exit status return WIFEXITED(status) ? WEXITSTATUS(status) : -1; } bool delete_directory(const char* directory) { // Open the directory DIR* dir = opendir(directory); if (dir == NULL) { log_msg(LOG_ERROR, "Failed to open directory '%s'.", directory); return false; } // Iterate over the directory entries struct dirent* entry; while ((entry = readdir(dir)) != NULL) { // Skip . and .. if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; // Combine the directory path with the entry name char* entry_path = format("%s/%s", directory, entry->d_name); if (entry_path == NULL) { log_msg(LOG_ERROR, "Failed to allocate memory for the entry path."); closedir(dir); return false; } // Check if the entry is a directory struct stat statbuf; int result = stat(entry_path, &statbuf); if (result != 0) { log_msg(LOG_ERROR, "Failed to get information about entry '%s'.", entry_path); free(entry_path); closedir(dir); return false; } if (S_ISDIR(statbuf.st_mode)) { // Delete the directory if (!delete_directory(entry_path)) { free(entry_path); closedir(dir); return false; } } else { // Delete the file if (unlink(entry_path) != 0) { log_msg(LOG_ERROR, "Failed to delete entry '%s'.", entry_path); free(entry_path); closedir(dir); return false; } } free(entry_path); } // Close the directory closedir(dir); // Delete the directory if (rmdir(directory) != 0) { log_msg(LOG_ERROR, "Failed to delete directory '%s'.", directory); return false; } return true; }