#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; } /* static open_all_redir(const struct ast_list redir_list) { while (redir_list){ struct ast_redir *redir = (struct ast_redir*)redir_list->data; int target_fd; if (redir->io_number != -1) { target_fd = redir->io_number; } else { // assign target_fd depending on redir type } int saved_fd = dup(target_fd); // if redir type is not with '&' // then we open("filename") // else, no need to open, just new_fd = atoi(filename) open(); dup2(target_fd, new_fd); close(new_fd); // append target_fd and saved_fd to a list // in order to be able to restore all the fds } } */ /* 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; } */ // --- Builtins --- static int builtin_echo(char **argv) { bool newline = true; int i = 1; if (argv[1] && strcmp(argv[1], "-n") == 0) { newline = false; i++; } for (; argv[i]; i++) { printf("%s", argv[i]); if (argv[i + 1]) printf(" "); } if (newline) printf("\n"); fflush(stdout); return 0; } static int builtin_true(char **argv) { (void)argv; return 0; } static int builtin_false(char **argv) { (void)argv; return 1; } static int builtin_exit(char **argv) { int exit_val = 0; if (argv[1]) exit_val = atoi(argv[1]); exit(exit_val); return exit_val; } static int builtin_cd(char **argv) { const char *path = argv[1]; if (!path) { path = getenv("HOME"); if (!path) { fprintf(stderr, "cd: HOME not set\n"); return 1; } } if (chdir(path) != 0) { perror("cd"); return 1; } return 0; } /** * @brief Tries to execute a builtin command if the command matches a builtin * * @param argv Array of command arguments * @return int Exit status of the builtin command, or -1 if not a builtin */ static int try_builtin(char **argv) { if (!argv || !argv[0]) return 0; if (strcmp(argv[0], "echo") == 0) return builtin_echo(argv); if (strcmp(argv[0], "true") == 0) return builtin_true(argv); if (strcmp(argv[0], "false") == 0) return builtin_false(argv); if (strcmp(argv[0], "exit") == 0) return builtin_exit(argv); if (strcmp(argv[0], "cd") == 0) return builtin_cd(argv); return -1; }