#define _POSIX_C_SOURCE 200809L #include "execution_helpers.h" #include #include #include #include #include #include #include #include "../expansion/expansion.h" #include "../utils/ast/ast.h" #include "../utils/hash_map/hash_map.h" #include "execution.h" static char **list_to_argv(struct list *command_list) { size_t len = 0; struct list *cur = command_list; while (cur) { len++; cur = cur->next; } char **argv = calloc(len + 1, sizeof(char *)); if (!argv) return NULL; cur = command_list; for (size_t i = 0; i < len; i++) { argv[i] = (char *)cur->data; cur = cur->next; } argv[len] = NULL; return argv; } static int try_builtin(char **argv); int exec_ast_command(struct ast_command *command, struct hash_map *vars) { (void)vars; if (!command || !(command->command)) return 1; char **argv = list_to_argv(command->command); if (!argv || !(argv[0])) { free(argv); return 0; } int builtin_ret = try_builtin(argv); if (builtin_ret != -1) { free(argv); return builtin_ret; } pid_t pid = fork(); if (pid < 0) { perror("fork"); free(argv); return 1; } if (pid == 0) { execvp(argv[0], argv); perror("execvp"); _exit(127); } int status = 0; waitpid(pid, &status, 0); free(argv); if (WIFEXITED(status)) return WEXITSTATUS(status); return 1; } int exec_ast_if(struct ast_if *if_node, struct hash_map *vars) { int cond = execution(if_node->condition, vars); if (cond == 0) return execution(if_node->then_clause, vars); else return execution(if_node->else_clause, vars); } int exec_ast_list(struct ast_list *list_node, struct hash_map *vars) { struct list *cur = list_node->children; int ret = 0; while (cur) { struct ast *child = (struct ast *)cur->data; if (!ast_is_void(child)) ret = execution(child, vars); cur = cur->next; } return ret; } int exec_ast_and_or(struct ast_and_or *ao_node, struct hash_map *vars) { int left_ret = execution(ao_node->left, vars); if (ao_node->type == AST_AND_OR_TYPE_AND) { if (left_ret == 0) return execution(ao_node->right, vars); return left_ret; } else { if (left_ret != 0) return execution(ao_node->right, vars); return left_ret; } } static int get_fd_target(const struct ast_redir *redir) { if (redir->io_number != -1) return redir->io_number; if (redir->type == AST_REDIR_TYPE_LESS || redir->type == AST_REDIR_TYPE_DLESS || redir->type == AST_REDIR_TYPE_LESSAND) return 0; return 1; } static int open_redir_file(const struct ast_redir *redir, int *flags, int *mode) { *mode = 0644; if (redir->type == AST_REDIR_TYPE_GREAT || redir->type == AST_REDIR_TYPE_CLOBBER) { *flags = O_WRONLY | O_CREAT | O_TRUNC; return open(redir->filename, *flags, *mode); } else if (redir->type == AST_REDIR_TYPE_DGREAT) { *flags = O_WRONLY | O_CREAT | O_APPEND; return open(redir->filename, *flags, *mode); } else if (redir->type == AST_REDIR_TYPE_LESS) { *flags = O_RDONLY; return open(redir->filename, *flags); } return -3; // not a file open } static int handle_and_restore_fd(int saved_fd, int fd_target) { if (saved_fd != -1) { dup2(saved_fd, fd_target); close(saved_fd); } else { close(fd_target); } return 0; } int exec_ast_redir(struct ast_redir *redir, struct hash_map *vars) { int fd_target = get_fd_target(redir); int saved_fd = dup(fd_target); int new_fd = -1, flags = 0, mode = 0644; if (redir->type == AST_REDIR_TYPE_GREAT || redir->type == AST_REDIR_TYPE_CLOBBER || redir->type == AST_REDIR_TYPE_DGREAT || redir->type == AST_REDIR_TYPE_LESS) { new_fd = open_redir_file(redir, &flags, &mode); if (new_fd == -1) { perror("open"); if (saved_fd != -1) close(saved_fd); return 1; } if (dup2(new_fd, fd_target) == -1) { perror("dup2"); close(new_fd); if (saved_fd != -1) close(saved_fd); return 1; } close(new_fd); } else if (redir->type == AST_REDIR_TYPE_GREATAND || redir->type == AST_REDIR_TYPE_LESSAND) { new_fd = atoi(redir->filename); if (dup2(new_fd, fd_target) == -1) { perror("dup2"); if (saved_fd != -1) close(saved_fd); return 1; } } int ret = execution(redir->child, vars); handle_and_restore_fd(saved_fd, fd_target); return ret; } // Dummy try_builtin for linking static int try_builtin(char **argv) { (void)argv; return -1; }