/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* exec_cmd_line.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: lperrey +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2021/11/16 01:57:38 by lperrey #+# #+# */ /* Updated: 2021/11/18 12:31:04 by lperrey ### ########.fr */ /* */ /* ************************************************************************** */ #include "minishell.h" // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01 // Bien penser à mettre les ptr à NULL aprés free en cas d'erreur (pour ne pas double free si appel à free_exit()) int pipeline(t_all *c); int open_pipes(t_cmd *pipeline[]); int pipeline_find_access(t_cmd *pipeline[], char *path[]); pid_t pipeline_exec(t_cmd *pipeline[], t_all *c); int cmd_exec_in_subshell(t_cmd *cmd, t_all *c); int simple_cmd_builtin(t_cmd *cmd, t_all *c); void wait_subshell(pid_t last_cmd_pid, int *last_exit_status); int exec_cmd_line(t_all *c) { if (!pipeline(c)) { free_pipeline(&c->cmd_arr); return (0); } return (1); } 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(pipeline) == 1 && c->cmd_arr[0]->builtin_func) simple_cmd_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); } int simple_cmd_builtin(t_cmd *cmd, t_all *c) { // TODO return (1); } 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); } // 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 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 } 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 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); } 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); } 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 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); } int handle_wait_error(void) { if (errno == ECHILD) return (-1); else if (errno == EINTR) return (0); else perror("wait()"); return (-1); } 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); } ret = 0; while (ret != -1) { ret = wait(&wstatus); if (ret == -1) ret = handle_wait_error(); } if (WIFSIGNALED(wstatus)) { write(STDIN_FILENO, "\n", 1); *last_exit_status = 128 + WTERMSIG(wstatus); } } 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); }