#include "execution.h" #include #include #include #include #include #include "../utils/ast/ast.h" /** * @brief converts a linked list of command arguments to an argv array. Don't * forget to free the result * * @param cmd_list Linked list of command arguments * @return char** Array of command arguments suitable for execvp. Terminated by * NULL */ static char **list_to_argv(struct list *cmd_list) { size_t len = 0; struct list *cur = cmd_list; while (cur) { len++; cur = cur->next; } char **argv = calloc(len + 1, sizeof(char *)); if (!argv) { return NULL; } cur = cmd_list; for (size_t i = 0; i < len; i++) { argv[i] = (char *)cur->data; cur = cur->next; } argv[len] = NULL; return argv; } /** * @brief Executes a command represented by an ast_cmd structure * * @param cmd The command to execute * @return int The exit status of the command */ static int exec_command(struct ast_cmd *cmd) { if (!cmd || !(cmd->cmd)) { return -1; } char **argv = list_to_argv(cmd->cmd); if (!argv || !(argv[0])) { free(argv); return -1; } pid_t pid = fork(); if (pid < 0) // Fork failed { perror("fork"); free(argv); return -1; } if (pid == 0) // If child process { execvp(argv[0], argv); perror("execvp"); // If execvp returns, there was an error exit(EXIT_FAILURE); // Exit child process } int status = 0; waitpid(pid, &status, 0); free(argv); if (WIFEXITED(status)) { return WEXITSTATUS(status); } return -1; // Should not happen } /** * @brief Executes the AST returned by the parser * * @param ast The AST to execute * @return int The exit status of the last executed command. */ int execution(struct ast *ast) { if (!ast) { return 0; } switch (ast->type) { case AST_END: { return 0; } case AST_CMD: { struct ast_cmd *cmd = ast->data->ast_cmd; // Cast implicit return exec_command(cmd); // It's recursive } case AST_IF: { struct ast_if *if_node = ast->data->ast_if; // We cast the union to ast_if int cond = execution(if_node->condition); if (cond == 0) // True { return execution(if_node->then_clause); } else // False { return execution(if_node->else_clause); } } default: { return -1; // Should not happen } } }