diff options
Diffstat (limited to 'src/eval')
| -rw-r--r-- | src/eval/cmd.c | 98 | ||||
| -rw-r--r-- | src/eval/error.c | 56 | ||||
| -rw-r--r-- | src/eval/eval.c | 93 | ||||
| -rw-r--r-- | src/eval/redir.c | 80 |
4 files changed, 241 insertions, 86 deletions
diff --git a/src/eval/cmd.c b/src/eval/cmd.c new file mode 100644 index 0000000..9468cb2 --- /dev/null +++ b/src/eval/cmd.c @@ -0,0 +1,98 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* cmd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/06/14 10:41:31 by charles #+# #+# */ +/* Updated: 2020/06/15 11:09:38 by charles ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "eval.h" + +/* +** \brief Wrap a function in a fork +** \param fd_in fork input file descriptor +** \param fd_out fork output file descriptor +** \param passed param of the wrapped function +** \param wrapped function to wrap +*/ + +int fork_wrap( + int fd_in, + int fd_out, + void *passed, + int (*wrapped)(void *param)) +{ + int status; + pid_t child_pid; + + if ((child_pid = fork()) == -1) + return (-1); + if (child_pid == 0) + { + if ((fd_in != MS_NO_FD && dup2(fd_in, STDIN_FILENO) == -1) || + (fd_out != MS_NO_FD && dup2(fd_out, STDOUT_FILENO) == -1)) + exit(EXIT_FAILURE); + if ((status = wrapped(passed)) == -1) + exit(EXIT_FAILURE); + exit(status); + } + wait(&child_pid); + return (WEXITSTATUS(child_pid)); +} + +int forked_cmd(void *void_param) +{ + t_fork_param_cmd *param; + + param = void_param; + + if (param->builtin != NULL) + return (param->builtin(param->argv, param->env)); + else + return (execve(param->exec_path, param->argv, (char**)param->env->data)); +} + +int eval_cmd(t_env env, t_path path, t_ast *ast) +{ + t_fork_param_cmd param; + int fd_in; + int fd_out; + char **argv; + + fd_in = MS_NO_FD; + fd_out = MS_NO_FD; + if (!redir_extract(ast->redirs, env, &fd_in, &fd_out)) + { + ast->redirs = NULL; + return (-1); + } + ast->redirs = NULL; + + if ((argv = preprocess(&ast->cmd_argv, env)) == NULL) + { + ast->cmd_argv = NULL; + return (-1); + } + + param.builtin = builtin_search_func(argv[0]); + if (param.builtin == NULL) + { + param.exec_path = exec_search_path(path, env_search(env, "PATH"), argv[0]); + if (param.exec_path == NULL) + { + error_eval_put(ERROR_CMD_NOT_FOUND, argv[0]); + ft_split_destroy(argv); + return (-1); // return error status + } + } + + param.argv = argv; + param.env = env; + int ret = fork_wrap(fd_in, fd_out, ¶m, &forked_cmd); + ft_split_destroy(argv); + return (ret); +} diff --git a/src/eval/error.c b/src/eval/error.c new file mode 100644 index 0000000..016a751 --- /dev/null +++ b/src/eval/error.c @@ -0,0 +1,56 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* error.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/06/14 11:02:52 by charles #+# #+# */ +/* Updated: 2020/06/14 12:19:14 by charles ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "eval.h" + +static t_error g_errors[] = +{ + {ERROR_AMBIGUOUS_REDIR, 1, "ambiguous redirect"}, + {ERROR_OPEN, 1, NULL}, + {ERROR_CMD_NOT_FOUND, 127, "command not found"}, + {ERROR_SYNTAX, 2, "syntax error near unexpected token "}, +}; + +t_error *st_error_get(enum e_error id) +{ + size_t i; + t_error *match; + + match = NULL; + i = 0; + while (i < sizeof(g_errors) / sizeof(t_error)) + { + if (g_errors[i].id == id) + match = &g_errors[i]; + i++; + } + return (match); +} + +void error_eval_put(enum e_error id, char *unexpected) +{ + t_error *err; + + err = st_error_get(id); + ft_putstr_fd("minishell: ", STDERR_FILENO); + ft_putstr_fd(unexpected, STDERR_FILENO); + ft_putstr_fd(": ", STDERR_FILENO); + if (err->msg == NULL) + ft_putendl_fd(strerror(errno), STDERR_FILENO); + else + ft_putendl_fd(err->msg, STDERR_FILENO); +} + +int error_status(enum e_error id) +{ + return (st_error_get(id)->status); +} diff --git a/src/eval/eval.c b/src/eval/eval.c index 1e0a8d7..c1b580f 100644 --- a/src/eval/eval.c +++ b/src/eval/eval.c @@ -6,96 +6,17 @@ /* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2020/04/01 17:05:21 by charles #+# #+# */ -/* Updated: 2020/06/14 10:34:11 by charles ### ########.fr */ +/* Updated: 2020/06/14 10:42:37 by charles ### ########.fr */ /* */ /* ************************************************************************** */ -/* #<{(| */ -/* ** \file eval.c */ -/* ** \brief Evaluation of an AST */ -/* |)}># */ -/* */ +/* +** \file eval.c +** \brief Evaluation of an AST +*/ + /* #include "eval.h" */ -/* */ -/* #<{(| */ -/* ** \brief Wrap a function in a fork */ -/* ** \param fd_in fork input file descriptor */ -/* ** \param fd_out fork output file descriptor */ -/* ** \param passed param of the wrapped function */ -/* ** \param wrapped function to wrap */ -/* |)}># */ -/* */ -/* int fork_wrap( */ -/* int fd_in, */ -/* int fd_out, */ -/* void *passed, */ -/* int (*wrapped)(void *param)) */ -/* { */ -/* int status; */ -/* pid_t child_pid; */ -/* */ -/* if ((child_pid = fork()) == -1) */ -/* return (-1); */ -/* if (child_pid == 0) */ -/* { */ -/* if (dup2(STDIN_FILENO, fd_in) == -1 || */ -/* dup2(STDOUT_FILENO, fd_out) == -1) */ -/* exit(EXIT_FAILURE); */ -/* if ((status = wrapped(passed)) == -1) */ -/* exit(EXIT_FAILURE); */ -/* exit(status); */ -/* } */ -/* wait(&child_pid); */ -/* return (WEXITSTATUS(child_pid)); */ -/* } */ -/* */ -/* int run_builtin(t_eval_state *state, char **argv) */ -/* { */ -/* return (builtin_dispatch_run(argv, state->env)); */ -/* } */ -/* */ -/* #<{(| */ -/* ** \brief execve syscall wrapper passed it to fork_wrap */ -/* ** \param param function params */ -/* ** \return execve return value */ -/* |)}># */ -/* */ -/* int execve_wrapper(void *param) */ -/* { */ -/* return (execve( */ -/* ((t_fork_param_execve*)param)->exec_path, */ -/* ((t_fork_param_execve*)param)->argv, */ -/* ((t_fork_param_execve*)param)->envp */ -/* )); */ -/* } */ -/* */ -/* #<{(| */ -/* ** \brief Evaluate a command */ -/* ** \param state Evaluation state */ -/* ** \param cmd Command to evaluate */ -/* ** \return Executable status or -1 on error */ -/* |)}># */ -/* */ -/* static int eval_cmd(int fd_in, int fd_out, t_eval_state *state, t_cmd *cmd) */ -/* { */ -/* t_fork_param_execve param; */ -/* */ -/* if (builtin_check_exec_name(cmd->argv[0])) */ -/* return (run_builtin(state, cmd->argv)); */ -/* param.exec_path = exec_search_path( */ -/* state->path, env_search(state->env, "PATH"), cmd->argv[0]); */ -/* if (param.exec_path == NULL) */ -/* return (-1); */ -/* if (cmd->in != NULL && (fd_in = open(cmd->in, O_RDONLY)) == -1) */ -/* return (-1); */ -/* if (cmd->out != NULL && (fd_out = open(cmd->out, */ -/* (cmd->is_append ? O_APPEND : O_WRONLY) | O_CREAT)) == -1) */ -/* return (-1); */ -/* param.argv = cmd->argv; */ -/* param.envp = (char**)state->env->data; */ -/* return (fork_wrap(fd_in, fd_out, ¶m, &execve_wrapper)); */ -/* } */ -/* */ + /* #<{(| */ /* ** \brief Evaluate a line */ /* ** \param state State of the evaluation */ diff --git a/src/eval/redir.c b/src/eval/redir.c new file mode 100644 index 0000000..c6f98d4 --- /dev/null +++ b/src/eval/redir.c @@ -0,0 +1,80 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* redir.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: charles <charles.cabergs@gmail.com> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/06/15 11:05:34 by charles #+# #+# */ +/* Updated: 2020/06/15 11:44:38 by charles ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "eval.h" + +static enum e_token_tag st_lst_tag(t_ftlst *lst) +{ + return (((t_token*)lst->data)->tag); +} + +static bool st_open_replace(int *fd, char *filename, int oflag) +{ + if (*fd != MS_NO_FD) + close(*fd); + if (oflag & O_CREAT) + *fd = open(filename, oflag, 0644); + else + *fd = open(filename, oflag); + if (*fd == -1) + { + error_eval_put(ERROR_OPEN, filename); + free(filename); + return (false); + } + return (true); +} + +bool redir_extract( + t_ftlst *redirs, + t_env env, + int *fd_in, + int *fd_out) +{ + t_ftlst *after; + t_ftlst *curr; + char *filename; + + if (redirs == NULL) + return (true); + if (!(st_lst_tag(redirs) & TAG_IS_REDIR) || redirs->next == NULL + || !(st_lst_tag(redirs->next) & TAG_IS_STR)) + return (false); + curr = redirs->next; + while (curr != NULL && st_lst_tag(curr) & TAG_IS_STR) + { + if (curr->next == NULL || st_lst_tag(curr->next) & TAG_IS_REDIR) + { + after = curr->next; + curr->next = NULL; + } + curr = curr->next; + } + if ((filename = preprocess_filename(&redirs->next, env)) == NULL) + { + token_destroy_lst2(redirs, after); + return (false); + } + if ((st_lst_tag(redirs) == TAG_REDIR_IN + && !st_open_replace(fd_in, filename, O_RDONLY)) + || (st_lst_tag(redirs) == TAG_REDIR_OUT + && !st_open_replace(fd_out, filename, O_WRONLY | O_CREAT | O_TRUNC)) + || (st_lst_tag(redirs) == TAG_REDIR_APPEND + && !st_open_replace(fd_out, filename, O_WRONLY | O_CREAT | O_APPEND))) + { + token_destroy_lst2(redirs, after); + return (false); + } + token_destroy_lst(redirs); + free(filename); + return (redir_extract(after, env, fd_in, fd_out)); +} |
