From df6ed1c5cc20c4db3325eb55710e913cb5706332 Mon Sep 17 00:00:00 2001 From: marcnava-42cursus Date: Wed, 11 Feb 2026 02:29:45 +0100 Subject: [PATCH] Executor working, need to validate with the parser fixed, all norme fixed --- include/executor.h | 45 ++-- src/executor/command_exec.c | 86 ++++++++ src/executor/executor.c | 368 +++++--------------------------- src/executor/path_resolver.c | 77 +++++++ src/executor/pipeline_helpers.c | 73 +++++++ src/executor/process_helpers.c | 97 +++++++++ 6 files changed, 420 insertions(+), 326 deletions(-) create mode 100644 src/executor/command_exec.c create mode 100644 src/executor/path_resolver.c create mode 100644 src/executor/pipeline_helpers.c create mode 100644 src/executor/process_helpers.c diff --git a/include/executor.h b/include/executor.h index f2a49f4..a8a9416 100644 --- a/include/executor.h +++ b/include/executor.h @@ -19,23 +19,38 @@ # define READ_PIPE 0 # define WRITE_PIPE 1 - -typedef struct s_pipeline -{ - int prev_read_fd; - int pipefd[2]; -} t_pipeline; - - -/******************************************************************************/ -/* Functions */ -/******************************************************************************/ - -// executor.c - # define PIPE_ERROR -1 # define FORK_ERROR -1 -extern uint8_t execute(t_list *command, t_minishell *minishell); +typedef struct s_pipeline +{ + int prev_read_fd; + int pipefd[2]; +} t_pipeline; + +typedef struct s_exec_state +{ + uint8_t exit_status; + t_pipeline pipeline; + t_list *current_command; + pid_t last_child_pid; +} t_exec_state; + +extern uint8_t execute(t_list *command, t_minishell *minishell); +extern uint8_t executor_execute_command(t_command *cmd, t_minishell *msh); +extern char *executor_resolve_command_path(const t_command *cmd, + t_minishell *msh); +extern bool executor_is_builtin_command(const t_command *cmd, + t_minishell *msh); +extern int executor_create_pipe_if_needed(t_list *node, t_pipeline *pl); +extern bool executor_is_fork_required(t_list *node, const t_pipeline *pl, + t_minishell *msh); +extern void executor_setup_child_input(t_pipeline *pipeline); +extern void executor_setup_child_output(t_list *node, t_pipeline *pl); +extern void executor_child_process(t_list *node, t_pipeline *pl, + t_minishell *msh); +extern void executor_parent_cleanup(t_list *node, t_pipeline *pl); +extern uint8_t executor_wait_for_children(pid_t last_child_pid); +extern void executor_cmdfree(t_command *command); #endif /* EXECUTOR_H */ diff --git a/src/executor/command_exec.c b/src/executor/command_exec.c new file mode 100644 index 0000000..aecfb39 --- /dev/null +++ b/src/executor/command_exec.c @@ -0,0 +1,86 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* command_exec.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san + +static uint8_t resolve_execve_status(void) +{ + if (errno == ENOENT) + return (127); + if (errno == EACCES || errno == ENOEXEC || errno == EISDIR) + return (126); + return (EXIT_FAILURE); +} + +static uint8_t execute_builtin( + const t_command *command, + t_minishell *minishell +) +{ + const t_builtin_func builtin + = ft_hashmap_get(minishell->builtins, command->argv[0]); + + return (builtin(*command, minishell)); +} + +static void handle_execve_error( + const t_command *command, + char **envp +) +{ + uint8_t exit_status; + + exit_status = resolve_execve_status(); + free_envp(envp); + perror(command->path); + exit(exit_status); +} + +static void execute_external_command( + const t_command *command, + t_minishell *minishell +) +{ + char **envp; + + envp = get_envp(minishell); + if (envp == NULL) + { + perror("get_envp"); + exit(EXIT_FAILURE); + } + execve(command->path, command->argv, envp); + handle_execve_error(command, envp); +} + +uint8_t executor_execute_command( + t_command *command, + t_minishell *minishell +) +{ + if (command == NULL || command->argv == NULL || command->argv[0] == NULL) + return (EXIT_SUCCESS); + if (executor_is_builtin_command(command, minishell)) + return (execute_builtin(command, minishell)); + if (command->path != NULL) + free(command->path); + command->path = executor_resolve_command_path(command, minishell); + if (command->path == NULL) + { + ft_eprintf("minishell: %s: command not found\n", command->argv[0]); + return (127); + } + execute_external_command(command, minishell); + return (EXIT_FAILURE); +} diff --git a/src/executor/executor.c b/src/executor/executor.c index 5e16667..9ef3eca 100644 --- a/src/executor/executor.c +++ b/src/executor/executor.c @@ -6,287 +6,66 @@ /* By: sede-san -static bool is_path_explicit(const char *command_name); -static char *resolve_path_from_env(const char *command_name, - t_minishell *minishell); -static char *resolve_command_path(const t_command *command, - t_minishell *minishell); -static uint8_t resolve_execve_status(void); -static inline uint8_t execute_builtin( - const t_command *command, +static void init_exec_state( + t_exec_state *state, + t_list *command_list +) +{ + state->exit_status = EXIT_SUCCESS; + state->pipeline.prev_read_fd = -1; + state->current_command = command_list; + state->last_child_pid = -1; +} + +static bool fork_current_command( + t_exec_state *state, t_minishell *minishell ) { - const t_builtin_func builtin - = ft_hashmap_get(minishell->builtins, command->argv[0]); - - return (builtin(*command, minishell)); -} - -static void handle_execve_error( - const t_command *command, - char **envp -) -{ - const uint8_t exit_status = resolve_execve_status(); - - free_envp(envp); - perror(command->path); - exit(exit_status); -} - -static void execute_external_command( - const t_command *command, - t_minishell *minishell -) -{ - char **envp; - - envp = get_envp(minishell); - if (envp == NULL) - { - perror("get_envp"); - exit(EXIT_FAILURE); - } - execve(command->path, command->argv, envp); - handle_execve_error(command, envp); -} - -static bool is_path_explicit( - const char *command_name -) -{ - return (command_name != NULL && ft_strchr(command_name, '/') != NULL); -} - -static char *resolve_path_from_env( - const char *command_name, - t_minishell *minishell -) -{ - char *command_path; - char **path_env; - char *path_value; - size_t i; - - path_value = get_env("PATH", minishell); - if (path_value == NULL) - return (NULL); - path_env = ft_split(path_value, ':'); - if (path_env == NULL) - return (NULL); - command_path = NULL; - i = -1; - while (!command_path && path_env[++i] != NULL) - { - command_path = ft_strnjoin(3, path_env[i], "/", command_name); - if (command_path != NULL && access(command_path, X_OK) != EXIT_SUCCESS) - { - free(command_path); - command_path = NULL; - } - } - ft_free_split(path_env); - return (command_path); -} - -static char *resolve_command_path( - const t_command *command, - t_minishell *minishell -) -{ - const char *command_name; - char *command_path; - - if (command == NULL || command->argv == NULL || command->argv[0] == NULL) - return (NULL); - command_name = command->argv[0]; - if (is_path_explicit(command_name) - && access(command_name, X_OK) == EXIT_SUCCESS) - return (ft_strdup(command_name)); - command_path = resolve_path_from_env(command_name, minishell); - return (command_path); -} - -static uint8_t resolve_execve_status(void) -{ - if (errno == ENOENT) - return (127); - if (errno == EACCES || errno == ENOEXEC || errno == EISDIR) - return (126); - return (EXIT_FAILURE); -} - -static uint8_t execute_command( - t_command *command, - t_minishell *minishell -) -{ - char *resolved_path; - - if (command == NULL || command->argv == NULL || command->argv[0] == NULL) - return (EXIT_SUCCESS); - if (is_builtin(command->argv[0], minishell)) - return (execute_builtin(command, minishell)); - resolved_path = resolve_command_path(command, minishell); - if (resolved_path == NULL) - { - ft_eprintf("minishell: %s: command not found\n", command->argv[0]); - return (127); - } - command->path = resolved_path; - execute_external_command(command, minishell); - return (EXIT_FAILURE); //! should never reach here -} - -static bool is_builtin_command( - const t_command *command, - t_minishell *minishell -) -{ - if (command == NULL || command->argv == NULL || command->argv[0] == NULL) - return (false); - return (is_builtin(command->argv[0], minishell)); -} - -static void cmdfree_argv( - char **argv -) -{ - size_t i; - - if (argv == NULL) - { - return ; - } - i = 0; - while (argv[i] != NULL) - { - free(argv[i]); - i++; - } - free(argv); -} - -static void cmdfree( - t_command *command -) -{ - if (command == NULL) - return ; - cmdfree_argv(command->argv); - free(command->path); - free(command); -} - -static int create_pipe_if_needed( - t_list *current_command, - t_pipeline *pipeline -) -{ - if (!current_command->next) - return (0); - if (pipe(pipeline->pipefd) == PIPE_ERROR) - return (perror("pipe"), PIPE_ERROR); - return (0); -} - -static bool is_fork_required( - t_list *current_command, - const t_pipeline *pipeline, - t_minishell *minishell -) { - const t_command *command = current_command->content; - - return (pipeline->prev_read_fd != -1 - || current_command->next != NULL - || !is_builtin_command(command, minishell)); -} - -static void setup_child_input( - t_pipeline *pipeline -) -{ - if (pipeline->prev_read_fd != -1) - { - dup2(pipeline->prev_read_fd, STDIN_FILENO); - close(pipeline->prev_read_fd); - } -} - -static void setup_child_output( - t_list *current_command, - t_pipeline *pipeline -) -{ - if (current_command->next) - { - dup2(pipeline->pipefd[WRITE_PIPE], STDOUT_FILENO); - close(pipeline->pipefd[READ_PIPE]); - close(pipeline->pipefd[WRITE_PIPE]); - } -} - -static void child_process( - t_list *current_command, - t_pipeline *pipeline, - t_minishell *minishell -) -{ - uint8_t exit_status; - t_command *command; - - command = current_command->content; - setup_child_input(pipeline); - setup_child_output(current_command, pipeline); - exit_status = execute_command(command, minishell); - exit(exit_status); -} - -static void parent_cleanup( - t_list *current_command, - t_pipeline *pipeline -) -{ - if (pipeline->prev_read_fd != -1) - close(pipeline->prev_read_fd); - if (current_command->next) - { - close(pipeline->pipefd[WRITE_PIPE]); - pipeline->prev_read_fd = pipeline->pipefd[READ_PIPE]; - } - else - pipeline->prev_read_fd = -1; -} - -static uint8_t wait_for_children( - pid_t last_child_pid -) -{ - uint8_t exit_status; - int status; pid_t pid; - exit_status = EXIT_SUCCESS; - while (last_child_pid > 0 && (pid = wait(&status)) > 0) + pid = fork(); + if (pid == FORK_ERROR) + return (perror("fork"), state->exit_status = EXIT_FAILURE, false); + if (pid == 0) + executor_child_process(state->current_command, &state->pipeline, + minishell); + state->last_child_pid = pid; + return (true); +} + +static bool run_current_command( + t_exec_state *state, + t_minishell *minishell +) +{ + bool should_fork; + t_command *command; + + if (executor_create_pipe_if_needed(state->current_command, + &state->pipeline) == PIPE_ERROR) + return (state->exit_status = EXIT_FAILURE, false); + should_fork = executor_is_fork_required(state->current_command, + &state->pipeline, minishell); + if (should_fork) { - if (pid == last_child_pid) - { - if (WIFEXITED(status)) - exit_status = WEXITSTATUS(status); - else if (WIFSIGNALED(status)) - exit_status = 128 + WTERMSIG(status); - } + if (!fork_current_command(state, minishell)) + return (false); } - return (exit_status); + else + { + command = state->current_command->content; + state->exit_status = executor_execute_command(command, minishell); + } + executor_parent_cleanup(state->current_command, &state->pipeline); + state->current_command = state->current_command->next; + return (true); } uint8_t execute( @@ -294,50 +73,17 @@ uint8_t execute( t_minishell *minishell ) { - uint8_t exit_status; - t_pipeline pipeline; - t_list *current_command; - pid_t pid; - pid_t last_child_pid; - t_command *command; - bool should_fork; + t_exec_state state; - pipeline.prev_read_fd = -1; - exit_status = EXIT_SUCCESS; - last_child_pid = -1; - current_command = command_list; - while (current_command) + init_exec_state(&state, command_list); + while (state.current_command) { - if (create_pipe_if_needed(current_command, &pipeline) == PIPE_ERROR) - { - exit_status = EXIT_FAILURE; + if (!run_current_command(&state, minishell)) break ; - } - should_fork = is_fork_required(current_command, &pipeline, minishell); - if (should_fork) - { - pid = fork(); - if (pid == FORK_ERROR) - { - perror("fork"); - exit_status = EXIT_FAILURE; - break ; - } - if (pid == 0) - child_process(current_command, &pipeline, minishell); - last_child_pid = pid; - } - else - { - command = current_command->content; - exit_status = execute_command(command, minishell); - } - parent_cleanup(current_command, &pipeline); - current_command = current_command->next; } - if (last_child_pid > 0) - exit_status = wait_for_children(last_child_pid); - minishell->exit_status = exit_status; - ft_lstclear(&command_list, (void (*)(void *))cmdfree); - return (exit_status); + if (state.last_child_pid > 0) + state.exit_status = executor_wait_for_children(state.last_child_pid); + minishell->exit_status = state.exit_status; + ft_lstclear(&command_list, (void (*)(void *))executor_cmdfree); + return (state.exit_status); } diff --git a/src/executor/path_resolver.c b/src/executor/path_resolver.c new file mode 100644 index 0000000..67cb80e --- /dev/null +++ b/src/executor/path_resolver.c @@ -0,0 +1,77 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* path_resolver.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san argv == NULL || command->argv[0] == NULL) + return (NULL); + command_name = command->argv[0]; + if (is_path_explicit(command_name)) + return (resolve_explicit_path(command_name)); + return (resolve_path_from_env(command_name, minishell)); +} diff --git a/src/executor/pipeline_helpers.c b/src/executor/pipeline_helpers.c new file mode 100644 index 0000000..9136868 --- /dev/null +++ b/src/executor/pipeline_helpers.c @@ -0,0 +1,73 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pipeline_helpers.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san next) + return (0); + if (pipe(pipeline->pipefd) == PIPE_ERROR) + return (perror("pipe"), PIPE_ERROR); + return (0); +} + +bool executor_is_builtin_command( + const t_command *command, + t_minishell *minishell +) +{ + if (command == NULL || command->argv == NULL || command->argv[0] == NULL) + return (false); + return (is_builtin(command->argv[0], minishell)); +} + +bool executor_is_fork_required( + t_list *current_command, + const t_pipeline *pipeline, + t_minishell *minishell +) +{ + const t_command *command; + + command = current_command->content; + return (pipeline->prev_read_fd != -1 || current_command->next != NULL + || !executor_is_builtin_command(command, minishell)); +} + +void executor_setup_child_input( + t_pipeline *pipeline +) +{ + if (pipeline->prev_read_fd != -1) + { + dup2(pipeline->prev_read_fd, STDIN_FILENO); + close(pipeline->prev_read_fd); + } +} + +void executor_setup_child_output( + t_list *current_command, + t_pipeline *pipeline +) +{ + if (current_command->next) + { + dup2(pipeline->pipefd[WRITE_PIPE], STDOUT_FILENO); + close(pipeline->pipefd[READ_PIPE]); + close(pipeline->pipefd[WRITE_PIPE]); + } +} diff --git a/src/executor/process_helpers.c b/src/executor/process_helpers.c new file mode 100644 index 0000000..d1db072 --- /dev/null +++ b/src/executor/process_helpers.c @@ -0,0 +1,97 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* process_helpers.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: sede-san content; + executor_setup_child_input(pipeline); + executor_setup_child_output(current_command, pipeline); + exit_status = executor_execute_command(command, minishell); + exit(exit_status); +} + +void executor_parent_cleanup( + t_list *current_command, + t_pipeline *pipeline +) +{ + if (pipeline->prev_read_fd != -1) + close(pipeline->prev_read_fd); + if (current_command->next) + { + close(pipeline->pipefd[WRITE_PIPE]); + pipeline->prev_read_fd = pipeline->pipefd[READ_PIPE]; + } + else + pipeline->prev_read_fd = -1; +} + +uint8_t executor_wait_for_children( + pid_t last_child_pid +) +{ + uint8_t exit_status; + int status; + pid_t pid; + + exit_status = EXIT_SUCCESS; + pid = wait(&status); + while (last_child_pid > 0 && pid > 0) + { + if (pid == last_child_pid) + { + if (WIFEXITED(status)) + exit_status = WEXITSTATUS(status); + else if (WIFSIGNALED(status)) + exit_status = 128 + WTERMSIG(status); + } + pid = wait(&status); + } + return (exit_status); +} + +static void cmdfree_argv( + char **argv +) +{ + size_t i; + + if (argv == NULL) + return ; + i = 0; + while (argv[i] != NULL) + { + free(argv[i]); + i++; + } + free(argv); +} + +void executor_cmdfree( + t_command *command +) +{ + if (command == NULL) + return ; + cmdfree_argv(command->argv); + free(command->path); + free(command); +}