diff --git a/Makefile b/Makefile index 892938b..bdedc6e 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,11 @@ CC = clang CFLAGS = -Wall -Wextra $(INCLUDES) -g # add -Werror, del -g VPATH = $(DIR_SRCS) -DIR_SRCS = srcs srcs/builtins srcs/lexing \ +DIR_SRCS = srcs srcs/builtins \ + srcs/lexing \ srcs/parsing srcs/parsing/valid_syntax \ - srcs/parsing/expansions srcs/parsing/redirections + srcs/parsing/expansions srcs/parsing/redirections \ + srcs/exec INCLUDES = -I$(HEADERS_D) -I$(LIBFT_D) @@ -32,7 +34,8 @@ SRCS = main.c init.c free.c generic.c \ words_expansions.c expand_token.c rejoin_after_expand.c new_token_for_each_field.c \ ft_split_quotes.c ft_strdup_quotes.c \ redirections.c here_doc.c \ - exec_cmd_line.c \ + exec_cmd_line.c pipeline.c \ + find_access.c subshell_exec.c subshell_wait.c simple_cmd_builtin.c \ cd.c pwd.c export.c unset.c exit.c env.c echo.c DIR_OBJS = builds diff --git a/headers/minishell_prototypes.h b/headers/minishell_prototypes.h index b91f750..51b2492 100644 --- a/headers/minishell_prototypes.h +++ b/headers/minishell_prototypes.h @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/08 02:59:58 by lperrey #+# #+# */ -/* Updated: 2021/11/18 17:52:50 by hulamy ### ########.fr */ +/* Updated: 2021/11/18 21:32:54 by hulamy ### ########.fr */ /* */ /* ************************************************************************** */ @@ -44,6 +44,11 @@ int redirections(t_token *token_list, t_cmd **cmd_arr); // Exec int exec_cmd_line(t_all *c); +int pipeline(t_all *c); +int cmd_find_access(t_cmd *cmd, char *path[]); +int cmd_exec_in_subshell(t_cmd *cmd, t_all *c); +void wait_subshell(pid_t last_cmd_pid, int *last_exit_status); +int simple_command_builtin(t_cmd *cmd, t_all *c); // Builtins int builtin_cd(int argc, char *argv[], t_all *c); diff --git a/libft b/libft index 56b4037..d58ee38 160000 --- a/libft +++ b/libft @@ -1 +1 @@ -Subproject commit 56b403736934a9ef2552671986afb77223f3cfeb +Subproject commit d58ee38bab0a9e0449d98efc9522b124c71632fd diff --git a/srcs/exec/exec_cmd_line.c b/srcs/exec/exec_cmd_line.c new file mode 100644 index 0000000..bbd417c --- /dev/null +++ b/srcs/exec/exec_cmd_line.c @@ -0,0 +1,25 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exec_cmd_line.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/18 13:29:25 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01 + +int exec_cmd_line(t_all *c) +{ + if (!pipeline(c)) + { + free_pipeline(&c->cmd_arr); + return (0); + } + return (1); +} diff --git a/srcs/exec/find_access.c b/srcs/exec/find_access.c new file mode 100644 index 0000000..2f2f53a --- /dev/null +++ b/srcs/exec/find_access.c @@ -0,0 +1,113 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* find_access.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/18 13:20:20 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int search_cmd_path(char *cmd_name, char **cmd_path, + char *path[]); +static t_builtin_f search_builtin(char *cmd_name); +static int handle_access_error(char *file_name); + +// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_02 +// faire des test sur la valeur de errno selon les cas (if directory, if pathname invalid, ...) + +int cmd_find_access(t_cmd *cmd, char *path[]) +{ + if (ft_strchr(cmd->argv[0], '/')) + { + if (access(cmd->argv[0], X_OK) == -1) + cmd->error = handle_access_error(cmd->argv[0]); + else + { + cmd->path = ft_strdup(cmd->argv[0]); + if (!cmd->path) + return (0); + } + } + else + { + cmd->builtin_func = search_builtin(cmd->argv[0]); + if (cmd->builtin_func) + return (1); + if (search_cmd_path(cmd->argv[0], &cmd->path, path) == -1) + return (0); + if (!cmd->path) + { + cmd->error = 127; + ft_putstr_fd("minishell: ", 2); + ft_putstr_fd(cmd->argv[0], 2); + ft_putstr_fd(": command not found\n", 2); + } + } + return (1); +} + + +static int search_cmd_path(char *cmd_name, char **cmd_path, char *path[]) +{ + int i; + + if (!path) + return (1); + cmd_name = ft_strjoin("/", cmd_name); + if (!cmd_name) + return (ft_reti_perror(-1, "search_cmd_path()")); + i = 0; + while (path[i]) + { + *cmd_path = ft_strjoin(path[i], cmd_name); + if (!*cmd_path) + return (ft_reti_perror(-1, "search_cmd_path()")); + if (access(*cmd_path, X_OK) == 0) + break ; + else + { + free(*cmd_path); + *cmd_path = NULL; // TODO : free_null() + } + i++; + } + free(cmd_name); + return (1); +} + +static t_builtin_f search_builtin(char *cmd_name) +{ + if (ft_strncmp(cmd_name, "echo", 4 + 1) == 0) + return (&builtin_echo); + else if (ft_strncmp(cmd_name, "cd", 2 + 1) == 0) + return (&builtin_cd); + else if (ft_strncmp(cmd_name, "pwd", 3 + 1) == 0) + return (&builtin_pwd); + else if (ft_strncmp(cmd_name, "export", 6 + 1) == 0) + return (&builtin_export); + else if (ft_strncmp(cmd_name, "unset", 5 + 1) == 0) + return (&builtin_unset); + else if (ft_strncmp(cmd_name, "env", 3 + 1) == 0) + return (&builtin_env); + else if (ft_strncmp(cmd_name, "exit", 4 + 1) == 0) + return (&builtin_exit); + return (NULL); +} + +static int handle_access_error(char *file_name) +{ + int tmp; + + tmp = errno; + ft_perror_io("minishell: ", file_name); + errno = tmp; + if (errno == EACCES) + return (127); + return (1); + // 126 +} diff --git a/srcs/exec/pipeline.c b/srcs/exec/pipeline.c new file mode 100644 index 0000000..576d3ae --- /dev/null +++ b/srcs/exec/pipeline.c @@ -0,0 +1,95 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pipeline.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/18 14:12:36 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int open_pipes(t_cmd *pipeline[]); +static int pipeline_find_access(t_cmd *pipeline[], char *path[]); +static pid_t pipeline_exec(t_cmd *pipeline[], t_all *c); + +int pipeline(t_all *c) +{ + if (!open_pipes(c->cmd_arr)) + return (0); + if (!pipeline_find_access(c->cmd_arr, c->path)) + return (0); + if (ft_2d_arrlen(c->cmd_arr) == 1 && c->cmd_arr[0]->builtin_func) + simple_command_builtin(c->cmd_arr[0], c); + else + wait_subshell(pipeline_exec(c->cmd_arr, c), &c->last_exit_status); + free_pipeline(&c->cmd_arr); + return (1); +} + +static int open_pipes(t_cmd *pipeline[]) +{ + int i; + int pipes[2]; + + i = 0; + while (pipeline[i] && pipeline[i + 1]) + { + if (pipe(pipes) == -1) + return (ft_reti_perror(0, "pipe()")); + if (pipeline[i]->fd_out == STDOUT_FILENO) + pipeline[i]->fd_out = pipes[STDOUT_FILENO]; + else + if (close(pipes[STDOUT_FILENO]) == -1) + perror("close()"); + if (pipeline[i]->fd_in == STDIN_FILENO) + pipeline[i + 1]->fd_in = pipes[STDIN_FILENO]; + else + if (close(pipes[STDIN_FILENO]) == -1) + perror("close()"); + i++; + } + return (1); +} + +static int pipeline_find_access(t_cmd *pipeline[], char *path[]) +{ + int i; + + i = 0; + while (pipeline[i]) + { + if (!cmd_find_access(pipeline[i], path)) + return (0); + i++; + } + return (1); +} + +// TODO : Change exit status as in documentation : +// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_02 +static pid_t pipeline_exec(t_cmd *pipeline[], t_all *c) +{ + int i; + int ret; + + i = 0; + while (pipeline[i]) + { + if (!pipeline[i]->error) + { + ret = cmd_exec_in_subshell(pipeline[i], c); + if (ret != EXIT_SUCCESS) + free_exit(c, ret); + } + i++; + } + close_pipeline_fd(c->cmd_arr); + i -= 1; + if (pipeline[i]->error) + c->last_exit_status = pipeline[i]->error; + return (pipeline[i]->pid); +} diff --git a/srcs/exec/simple_cmd_builtin.c b/srcs/exec/simple_cmd_builtin.c new file mode 100644 index 0000000..902dfa8 --- /dev/null +++ b/srcs/exec/simple_cmd_builtin.c @@ -0,0 +1,63 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* simple_cmd_builtin.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/18 14:08:56 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int restore_stdio(int stdin_dup, int stdout_dup); + +int simple_command_builtin(t_cmd *cmd, t_all *c) +{ + int stdin_dup; + int stdout_dup; + + stdin_dup = 0; + stdout_dup = 0; + if (cmd->fd_in != STDIN_FILENO) + { + stdin_dup = dup(STDIN_FILENO); + if (stdin_dup == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup()")); + if (dup2(cmd->fd_in, STDIN_FILENO) == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup2()")); + } + if (cmd->fd_out != STDOUT_FILENO) + { + stdout_dup = dup(STDOUT_FILENO); + if (stdout_dup == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup()")); + if (dup2(cmd->fd_out, STDOUT_FILENO) == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup2()")); + } + c->last_exit_status = cmd->builtin_func(ft_2d_arrlen(cmd->argv), cmd->argv, c); + if (!restore_stdio(stdin_dup, stdout_dup)) + return (EXIT_FAILURE); + return (EXIT_SUCCESS); +} + +static int restore_stdio(int stdin_dup, int stdout_dup) +{ + if (stdin_dup) + { + if (dup2(stdin_dup, STDIN_FILENO) == -1) + return (ft_reti_perror(0, "dup2()")); + if (close(stdin_dup) == -1) + return (ft_reti_perror(0, "close()")); + } + if (stdout_dup) + { + if (dup2(stdout_dup, STDOUT_FILENO) == -1) + return (ft_reti_perror(0, "dup2()")); + if (close(stdout_dup) == -1) + return (ft_reti_perror(0, "close()")); + } + return (1); +} diff --git a/srcs/exec/subshell_exec.c b/srcs/exec/subshell_exec.c new file mode 100644 index 0000000..2f8b8df --- /dev/null +++ b/srcs/exec/subshell_exec.c @@ -0,0 +1,37 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* subshell_exec.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/18 13:37:17 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +int cmd_exec_in_subshell(t_cmd *cmd, t_all *c) +{ + cmd->pid = fork(); + if (cmd->pid == -1) + perror("fork()"); + if (cmd->pid == 0) + { + c->signal_behaviour.sa_handler = SIG_DFL; + sigaction(SIGINT, &c->signal_behaviour, NULL); + if (cmd->fd_in != STDIN_FILENO) + if (dup2(cmd->fd_in, STDIN_FILENO) == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup2()")); + if (cmd->fd_out != STDOUT_FILENO) + if (dup2(cmd->fd_out, STDOUT_FILENO) == -1) + return (ft_reti_perror(EXIT_FAILURE, "dup2()")); + close_pipeline_fd(c->cmd_arr); + if (cmd->builtin_func) + free_exit(c, cmd->builtin_func(ft_2d_arrlen(cmd->argv), cmd->argv, c)); + else if (execve(cmd->path, cmd->argv, c->envp) == -1) + return (ft_reti_perror_io(EXIT_FAILURE, "execve() ", cmd->argv[0])); + } + return (EXIT_SUCCESS); +} diff --git a/srcs/exec/subshell_wait.c b/srcs/exec/subshell_wait.c new file mode 100644 index 0000000..359d720 --- /dev/null +++ b/srcs/exec/subshell_wait.c @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* subshell_wait.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lperrey +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ +/* Updated: 2021/11/18 14:29:31 by lperrey ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "minishell.h" + +static int handle_wait_error(void); + +void wait_subshell(pid_t last_cmd_pid, int *last_exit_status) +{ + int wstatus; + int ret; + + wstatus = 0; + if (last_cmd_pid > 0) + { + if (waitpid(last_cmd_pid, &wstatus, 0) == -1) + perror("waitpid()"); + if (WIFEXITED(wstatus)) + *last_exit_status = WEXITSTATUS(wstatus); + if (WIFSIGNALED(wstatus)) + { + write(STDIN_FILENO, "\n", 1); + *last_exit_status = 128 + WTERMSIG(wstatus); + } + } + ret = 0; + while (ret != -1) + { + ret = wait(&wstatus); + if (ret == -1) + ret = handle_wait_error(); + } +} + +static int handle_wait_error(void) +{ + if (errno == ECHILD) + return (-1); + else if (errno == EINTR) + return (0); + else + perror("wait()"); + return (-1); +} diff --git a/srcs/free.c b/srcs/free.c index b933fc4..aec90fa 100644 --- a/srcs/free.c +++ b/srcs/free.c @@ -6,7 +6,7 @@ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/10/10 23:53:17 by lperrey #+# #+# */ -/* Updated: 2021/11/17 01:25:35 by lperrey ### ########.fr */ +/* Updated: 2021/11/18 03:09:46 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,7 +16,7 @@ int free_exit(t_all *c, int exit_status) { free(c->prompt_base); free(c->prompt); - ft_lstclear((t_list **)&c->token_list, free); // a voir avec Hugo, il y a un truc qui me semble superflu dans la fonction + ft_lstclear((t_list **)&c->token_list, free); ft_free_2d_arr(c->envp); ft_free_2d_arr(c->path); free_pipeline(&c->cmd_arr); diff --git a/srcs/parsing/expansions/new_token_for_each_field.c b/srcs/parsing/expansions/new_token_for_each_field.c index 38298b9..90db9a9 100644 --- a/srcs/parsing/expansions/new_token_for_each_field.c +++ b/srcs/parsing/expansions/new_token_for_each_field.c @@ -56,7 +56,7 @@ static t_token *insert_tokens(t_token *t, t_token *insert_lst) t->id = 0; free(t->content); - t->content = NULL; + t->content = NULL; // TODO : free_null() if (!insert_lst) return (t); diff --git a/srcs/shell_loop.c b/srcs/shell_loop.c index dae18d9..d6ec04a 100644 --- a/srcs/shell_loop.c +++ b/srcs/shell_loop.c @@ -31,6 +31,8 @@ void shell_loop(t_all *c) add_history(line_input); // Lexing c->token_list = input_to_tokens(line_input); + free(line_input); + line_input = NULL; // TODO : free_null() if (!c->token_list) continue ; // Parsing