#include "utils.h" #include #include #include #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) { log_message(LOG_ERROR, "Failed to calculate the length of the formatted string."); return NULL; } // Allocate a buffer for the formatted string char* buffer = calloc(length, sizeof(char)); if (buffer == NULL) { log_message(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_message(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 = "\033[0;31m"; 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** outb, char** errb, const char* file, ...) { // Count the number of arguments int argc = 1; // The first argument is the file name va_list args; va_start(args, file); 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_ERROR, "Failed to allocate memory for the arguments array."); return -1; } // Fill the arguments array va_start(args, file); argv[0] = strdup(file); if (argv[0] == NULL) { log_message(LOG_ERROR, "Failed to allocate memory for the file name."); free(argv); va_end(args); return -1; } for (int i = 1; i < argc; i++) { argv[i] = strdup(va_arg(args, const char*)); if (argv[i] == NULL) { log_message(LOG_ERROR, "Failed to allocate memory for the argument %d.", i); for (int j = 0; j < i; j++) free(argv[j]); free(argv); va_end(args); return -1; } } argv[argc] = NULL; va_end(args); // Create a pipe for the standard output int outp[2]; if (pipe(outp) != 0) { log_message(LOG_ERROR, "Failed to create a pipe for the standard output."); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } // Create a pipe for the standard error int errp[2]; if (pipe(errp) != 0) { log_message(LOG_ERROR, "Failed to create a pipe for the standard error."); close(outp[0]); close(outp[1]); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } // Fork the process pid_t pid = fork(); if (pid == -1) { log_message(LOG_ERROR, "Failed to fork the process (%s).", strerror(errno)); close(outp[0]); close(outp[1]); close(errp[0]); close(errp[1]); for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return -1; } if (pid == 0) { // Redirect the standard output close(outp[0]); dup2(outp[1], STDOUT_FILENO); close(outp[1]); // Redirect the standard error close(errp[0]); dup2(errp[1], STDERR_FILENO); close(errp[1]); // Execute the command execvp(file, argv); // If execvp returns, an error occurred printf("Failed to execute the command %s (%s).\n", file, strerror(errno)); exit(1); } // Close the write end of the pipes close(outp[1]); close(errp[1]); // Wait for the child process to finish int status; waitpid(pid, &status, 0); if (outb != NULL) *outb = read_file(outp[0]); if (errb != NULL) *errb = read_file(errp[0]); // Close the read end of the pipes close(outp[0]); close(errp[0]); // Free the arguments array for (int i = 0; i < argc; i++) free(argv[i]); free(argv); return WEXITSTATUS(status); } char* read_file(int fd) { char buffer[4096]; // Read the file ssize_t n; size_t length = 0; char* data = NULL; // Read blocks of data from the file while ((n = read(fd, buffer, sizeof(buffer))) > 0) { char* new_data = realloc(data, length + n + 1); if (new_data == NULL) { log_message(LOG_ERROR, "Failed to allocate memory for the file data."); free(data); return NULL; } data = new_data; // Copy and null-terminate the data memcpy(data + length, buffer, n); data[length + n] = '\0'; length += n; } // Check for read errors if (n < 0) { log_message(LOG_ERROR, "Failed to read the file (%s).", strerror(errno)); free(data); return NULL; } return data; }