From bb9f0e6f64830bba13f5e46b71455ffbf6d5e80f Mon Sep 17 00:00:00 2001 From: Lilia-42 Date: Sun, 1 Sep 2024 14:07:07 +0200 Subject: [PATCH] Refactor execution.c to files of max 5 functions --- Makefile | 19 +- inc/execution.h | 43 +- src/add_word.c | 98 ++++ src/assignments.c | 89 +++ src/exe_find.c | 65 +++ src/exe_helpers.c | 81 +++ src/exe_pipeline.c | 133 +++++ src/exe_prepare.c | 91 ++++ src/execute.c | 47 ++ src/execute_builtin.c | 115 ++++ src/execute_cmd.c | 114 ++++ src/execute_raw.c | 93 ++++ src/execution.c | 1187 ----------------------------------------- src/expand.c | 91 ++++ src/expand_split.c | 79 +++ src/redir_file.c | 83 +++ src/redir_here.c | 112 ++++ src/redirection.c | 89 +++ 18 files changed, 1439 insertions(+), 1190 deletions(-) create mode 100644 src/add_word.c create mode 100644 src/assignments.c create mode 100644 src/exe_find.c create mode 100644 src/exe_helpers.c create mode 100644 src/exe_pipeline.c create mode 100644 src/exe_prepare.c create mode 100644 src/execute.c create mode 100644 src/execute_builtin.c create mode 100644 src/execute_cmd.c create mode 100644 src/execute_raw.c delete mode 100644 src/execution.c create mode 100644 src/expand.c create mode 100644 src/expand_split.c create mode 100644 src/redir_file.c create mode 100644 src/redir_here.c create mode 100644 src/redirection.c diff --git a/Makefile b/Makefile index 26c0c02..62925dc 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,25 @@ SOURCES := main.c \ token_categorize.c \ token_finish.c \ parsing.c \ - execution.c \ + \ + execute.c \ + add_word.c \ + assignments.c \ + exe_find.c \ + exe_helpers.c \ + exe_pipeline.c \ + exe_prepare.c \ + execute_builtin.c \ + execute_cmd.c \ + execute_raw.c \ + expand.c \ + expand_split.c \ + redirection.c \ + redir_file.c \ + redir_here.c \ + \ helpers.c \ vars_helpers.c \ - \ builtins/cd.c \ builtins/echo.c \ builtins/pwd.c \ diff --git a/inc/execution.h b/inc/execution.h index 9aa5207..bc27ae1 100644 --- a/inc/execution.h +++ b/inc/execution.h @@ -6,11 +6,52 @@ /* By: ljiriste +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/08/02 17:40:19 by ljiriste #+# #+# */ -/* Updated: 2024/08/26 11:42:37 by ljiriste ### ########.fr */ +/* Updated: 2024/09/01 14:03:42 by lnikolov ### ########.fr */ /* */ /* ************************************************************************** */ #ifndef EXECUTION_H # define EXECUTION_H +# include "minishell_structs.h" +# include + +extern volatile sig_atomic_t g_last_signal; + +void free_split(char **fields); +int set_quote(char *quote, char c); +int is_token_type(const t_parse_tree_node *node, const char *type); + +int dup_pipes(const t_execution_env *env); +int dup_redirections(const t_vec *redirections); + +char **quoted_split(const char *str); +int unquote_field(char *field); +int add_word(t_vec *exp_str, const char *word, + const t_execution_env *env, int enquote_result); +char **expand(t_parse_tree_node *simple_command, const t_execution_env *env); + +char *find_exe(const char *exe_name, const t_execution_env *env); +int prepare_env(t_execution_env *env, + const t_vec *redirections, t_vec *assignments); + +int ex_builtin(char **fields, __attribute__((unused)) + t_vec *assignments, const t_vec *redirections, t_execution_env *env); +int ex_fields(char **fields, t_vec *assignments, + const t_vec *redirections, t_execution_env *env); +int ex_command(t_parse_tree_node *command, t_execution_env *env); +int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth); +int ex_program(t_parse_tree_node *program, t_execution_env *env); + +char *get_word(const t_parse_tree_node *parent); +int add_redirection_here(t_vec *redirections, + t_parse_tree_node *io_here, int fd, const t_execution_env *env); +int add_redirection_file(t_vec *redirections, + t_parse_tree_node *io_file, int fd, t_execution_env *env); + +int save_redirections(t_vec *redirections, + t_parse_tree_node *simple_command, t_execution_env *env); +int save_assignments(t_vec *assignments, t_parse_tree_node *simple_command, + const t_execution_env *env); + #endif // EXECUTION_H diff --git a/src/add_word.c b/src/add_word.c new file mode 100644 index 0000000..6db9d3d --- /dev/null +++ b/src/add_word.c @@ -0,0 +1,98 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* add_word.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include + +static int is_expandable(const char *str) +{ + return (str[0] == '$' + && (ft_isalpha(str[1]) + || str[1] == '_' + || str[1] == '?')); +} + +static char *get_value(const char *word, size_t *i, const t_execution_env *env) +{ + char *var; + char *value; + const char *const_val; + + if (word[*i] == '?') + { + ++*i; + value = ft_itoa(env->ret_val); + } + else + { + var = get_var_name(word + *i); + if (!var) + return (NULL); + *i += ft_strlen(var); + const_val = get_env_var_value(env, var); + free(var); + if (!const_val) + return (ft_strdup("")); + value = ft_strdup(const_val); + } + return (value); +} + +static int append_value(t_vec *exp_str, const char *value, int enquote_result) +{ + int error; + + if (!value) + return (1); + if (enquote_result) + { + error = ft_vec_append(exp_str, "'") != success; + error = error + || ft_vec_append_range(exp_str, value, ft_strlen(value)) != success; + error = error || ft_vec_append(exp_str, "'") != success; + return (error); + } + return (ft_vec_append_range(exp_str, value, ft_strlen(value)) != success); +} + +int add_word(t_vec *exp_str, const char *word, + const t_execution_env *env, int enquote_result) +{ + size_t i; + char quote; + const char space = ' '; + char *value; + + quote = '\0'; + i = 0; + while (word[i]) + { + set_quote("e, word[i]); + if (is_expandable(word + (i++)) && quote != '\'') + { + value = get_value(word, &i, env); + if (append_value(exp_str, value, enquote_result)) + { + free(value); + return (1); + } + free(value); + } + else + if (ft_vec_append(exp_str, word + i - 1) != success) + return (1); + } + return (ft_vec_append(exp_str, &space) != success); +} \ No newline at end of file diff --git a/src/assignments.c b/src/assignments.c new file mode 100644 index 0000000..8042f94 --- /dev/null +++ b/src/assignments.c @@ -0,0 +1,89 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* assignments.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov + +static void clear_old(t_vec *assignments, const char *new) +{ + size_t i; + char **assignment; + + i = assignments->size; + while (i > 0) + { + --i; + assignment = ft_vec_access(assignments, i); + if (cmp_var_name(*assignment, new)) + continue ; + ft_vec_erase(assignments, i, free); + } + return ; +} + +static int add_assignment(t_vec *assignments, const char *assignment, + const t_execution_env *env) +{ + t_vec advanced_copy; + char *copy; + + if (ft_vec_init(&advanced_copy, sizeof(char)) != success) + return (1); + if (add_word(&advanced_copy, assignment, env, 0)) + return (1); + *(char *)ft_vec_access(&advanced_copy, advanced_copy.size - 1) = '\0'; + copy = advanced_copy.vec; + unquote_field(copy); + clear_old(assignments, copy); + if (ft_vec_append(assignments, ©) == success) + return (0); + free(copy); + return (1); +} + +static int save_assignments_prefix(t_vec *assignments, t_parse_tree_node *prefix, + const t_execution_env *env) +{ + size_t i; + t_parse_tree_node *subnode; + + i = 0; + while (i < prefix->children.size) + { + subnode = ft_vec_access(&prefix->children, i); + if (is_token_type(subnode, "ASSIGNMENT_WORD")) + { + if (add_assignment(assignments, subnode->token.str, env)) + return (1); + } + else if (is_token_type(subnode, "cmd_prefix")) + if (save_assignments_prefix(assignments, subnode, env)) + return (1); + ++i; + } + return (0); +} + +int save_assignments(t_vec *assignments, t_parse_tree_node *simple_command, + const t_execution_env *env) +{ + t_parse_tree_node *subnode; + + if (ft_vec_init(assignments, sizeof(char *)) != success) + return (1); + subnode = ft_vec_access(&simple_command->children, 0); + if (is_token_type(subnode, "cmd_prefix")) + return (save_assignments_prefix(assignments, subnode, env)); + return (0); +} diff --git a/src/exe_find.c b/src/exe_find.c new file mode 100644 index 0000000..694e112 --- /dev/null +++ b/src/exe_find.c @@ -0,0 +1,65 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exe_find.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov + +int is_contained_in_dir(const char *exe_name, const char *dir_name) +{ + DIR *dir; + struct dirent *dir_entry; + + dir = opendir(dir_name); + if (!dir) + return (0); + dir_entry = readdir(dir); + while (dir_entry) + { + if (!ft_strcmp(dir_entry->d_name, exe_name)) + { + closedir(dir); + return (1); + } + dir_entry = readdir(dir); + } + closedir(dir); + return (0); +} + +char *find_exe(const char *exe_name, const t_execution_env *env) +{ + const char *path; + char **paths; + size_t i; + char *res; + + path = get_env_var_value(env, "PATH"); + if (!path) + return (NULL); + paths = ft_split(path, ":"); + if (!paths) + return (NULL); + res = NULL; + i = 0; + while (paths[i] && !res) + { + if (is_contained_in_dir(exe_name, paths[i])) + if (ft_strcat_alloc(&res, paths[i])) + if (ft_strcat_alloc(&res, "/")) + ft_strcat_alloc(&res, exe_name); + ++i; + } + free_split(paths); + return (res); +} diff --git a/src/exe_helpers.c b/src/exe_helpers.c new file mode 100644 index 0000000..9e3e0d0 --- /dev/null +++ b/src/exe_helpers.c @@ -0,0 +1,81 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exe_helpers.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov + +// Returns 1 when quote is set (or unset) +// and 0 when quote is left in current state +int set_quote(char *quote, char c) +{ + if (c == '"' || c == '\'') + { + if (*quote == '\0') + *quote = c; + else if (*quote == c) + *quote = '\0'; + else + return (0); + return (1); + } + return (0); +} + +int is_token_type(const t_parse_tree_node *node, const char *type) +{ + return (!ft_strcmp(node->token.type, type)); +} + +// Returns 1 if any unquoting happened else returns 0 +int unquote_field(char *field) +{ + int res; + size_t i; + char quote; + + res = 0; + quote = 0; + i = 0; + while (field && field[i]) + { + if (field[i] == '"' || field[i] == '\'') + { + if (!set_quote("e, field[i])) + { + ++i; + continue ; + } + res = 1; + ft_memmove(field + i, field + i + 1, ft_strlen(field + i + 1) + 1); + } + else + ++i; + } + return (res); +} + +void free_split(char **fields) +{ + size_t i; + + if (!fields) + return ; + i = 0; + while (fields[i]) + { + free(fields[i]); + ++i; + } + free(fields); + return ; +} \ No newline at end of file diff --git a/src/exe_pipeline.c b/src/exe_pipeline.c new file mode 100644 index 0000000..bf8e0bb --- /dev/null +++ b/src/exe_pipeline.c @@ -0,0 +1,133 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exe_pipeline.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include +#include + +static void killall(t_vec *child_pids, int sig_num) +{ + pid_t child_pid; + size_t i; + + i = 0; + while (i < child_pids->size) + { + child_pid = *(pid_t *)ft_vec_access(child_pids, i); + kill(child_pid, sig_num); + ++i; + } + return ; +} + +static void wait_for_all_to_end(t_vec *child_pids) +{ + size_t i; + pid_t pid; + int sig_num; + + sig_num = 0; + i = child_pids->size; + while (i > 0) + { + --i; + pid = *(pid_t *)ft_vec_access(child_pids, i); + if (g_last_signal == 0) + waitpid(pid, NULL, 0); + if (g_last_signal) + { + sig_num = g_last_signal; + g_last_signal = 0; + killall(child_pids, g_last_signal); + i = child_pids->size; + } + ft_vec_forget(child_pids, i); + } + ft_vec_free(child_pids, NULL); + if (g_last_signal == 0) + g_last_signal = sig_num; + return ; +} + +static void wait_for_return(t_execution_env *env) +{ + pid_t last_pid; + int status; + + if (env->last_was_builtin) + env->ret_val = env->builtin_ret_val; + else + { + if (env->child_pids.size == 0) + return ; + last_pid = *(pid_t *)ft_vec_access(&env->child_pids, + env->child_pids.size - 1); + waitpid(last_pid, &status, 0); + if (g_last_signal == 0) + if (WIFEXITED(status)) + env->ret_val = WEXITSTATUS(status); + } + wait_for_all_to_end(&env->child_pids); + return ; +} + +static int advance_pipeline(t_parse_tree_node *pipeline, + t_execution_env *env, int depth) +{ + int pipe_fds[2]; + int res; + + if (pipe(pipe_fds)) + return (1); + res = ft_vec_append(&env->fds_to_close, &pipe_fds[0]); + res = res || ft_vec_append(&env->fds_to_close, &env->stdout_fd); + ft_swap_int(&pipe_fds[1], &env->stdout_fd); + res = res + || ex_pipeline(ft_vec_access(&pipeline->children, 0), env, depth + 1); + ft_swap_int(&pipe_fds[1], &env->stdout_fd); + close(pipe_fds[1]); + if (res == 0) + { + ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1); + ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1); + } + ft_swap_int(&pipe_fds[0], &env->stdin_fd); + res = res || ex_command(ft_vec_access(&pipeline->children, 2), env); + ft_swap_int(&pipe_fds[0], &env->stdin_fd); + close(pipe_fds[0]); + return (res); +} + +int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth) +{ + if (g_last_signal != 0) + return (0); + if (pipeline->children.size == 1) + { + if (ex_command(ft_vec_access(&pipeline->children, 0), env)) + return (1); + } + else + { + if (advance_pipeline(pipeline, env, depth)) + { + killall(&env->child_pids, SIGTERM); + return (1); + } + } + if (depth == 0) + wait_for_return(env); + return (0); +} diff --git a/src/exe_prepare.c b/src/exe_prepare.c new file mode 100644 index 0000000..8c6abfd --- /dev/null +++ b/src/exe_prepare.c @@ -0,0 +1,91 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* exe_prepare.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include + +int dup_pipes(const t_execution_env *env) +{ + if (dup2(env->stdin_fd, STDIN_FILENO) == -1) + return (1); + if (dup2(env->stdout_fd, STDOUT_FILENO) == -1) + return (1); + if (env->stdin_fd != STDIN_FILENO) + close(env->stdin_fd); + if (env->stdout_fd != STDOUT_FILENO) + close(env->stdout_fd); + return (0); +} + +int dup_redirections(const t_vec *redirections) +{ + size_t i; + const t_redirection *redir; + + i = 0; + while (i < redirections->size) + { + redir = ft_vec_caccess(redirections, i); + dup2(redir->from_to_fds[1], redir->from_to_fds[0]); + close(redir->from_to_fds[1]); + ++i; + } + return (0); +} + +static int add_exported(t_vec *assignments, const t_execution_env *env) +{ + size_t i; + char *var; + const t_vec *exported; + + exported = &env->vars->exported; + i = 0; + while (i < exported->size) + { + var = ft_strdup(*(char *const *)ft_vec_caccess(exported, i)); + if (ft_vec_append(assignments, &var) != success) + return (1); + ++i; + } + return (0); +} + +static void close_fds(t_vec *fds_to_close) +{ + int fd; + size_t i; + + i = 0; + while (i < fds_to_close->size) + { + fd = *(int *)ft_vec_access(fds_to_close, i); + close(fd); + ++i; + } + return ; +} + +int prepare_env(t_execution_env *env, + const t_vec *redirections, t_vec *assignments) +{ + int res; + + close_fds(&env->fds_to_close); + res = dup_pipes(env); + res = dup_redirections(redirections) || res; + res = add_exported(assignments, env) || res; + return (res); +} \ No newline at end of file diff --git a/src/execute.c b/src/execute.c new file mode 100644 index 0000000..09e482f --- /dev/null +++ b/src/execute.c @@ -0,0 +1,47 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execute.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov children.size == 1) + return (ex_pipeline(ft_vec_access(&program->children, 0), env, 0)); + if (ex_program(ft_vec_access(&program->children, 0), env)) + return (1); + if (is_token_type(ft_vec_caccess(&program->children, 1), "AND_IF")) + { + if (env->ret_val == 0) + return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0)); + } + else + { + if (env->ret_val != 0) + return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0)); + } + return (0); +} + +int execute(t_tree *parse_tree, t_execution_env *env) +{ + int res; + + res = ex_program(parse_tree, env); + if (g_last_signal != 0) + { + env->ret_val = 128 + g_last_signal; + g_last_signal = 0; + } + return (res); +} diff --git a/src/execute_builtin.c b/src/execute_builtin.c new file mode 100644 index 0000000..e3dbab9 --- /dev/null +++ b/src/execute_builtin.c @@ -0,0 +1,115 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execute_builtin.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include + +static int save_std_filenos(int fds[3]) +{ + fds[0] = dup(STDIN_FILENO); + if (fds[0] < 0) + return (1); + fds[1] = dup(STDOUT_FILENO); + if (fds[1] < 0) + { + close(fds[0]); + return (1); + } + fds[2] = dup(STDERR_FILENO); + if (fds[2] < 0) + { + close(fds[0]); + close(fds[1]); + return (1); + } + return (0); +} + +static int restore_std_filenos(int fds[3]) +{ + if (dup2(fds[0], STDIN_FILENO) == -1) + return (1); + if (dup2(fds[1], STDOUT_FILENO) == -1) + return (1); + if (dup2(fds[2], STDERR_FILENO) == -1) + return (1); + close(fds[0]); + close(fds[1]); + close(fds[2]); + return (0); +} + +static void close_pipes(const t_execution_env *env) +{ + close(env->stdin_fd); + close(env->stdout_fd); + return ; +} + +static size_t count_fields(char **fields) +{ + size_t i; + + i = 0; + while (fields[i]) + ++i; + return (i); +} + +static void close_redirections(const t_vec *redirections) +{ + size_t i; + const t_redirection *redir; + + i = 0; + while (i < redirections->size) + { + redir = ft_vec_caccess(redirections, i); + close(redir->from_to_fds[0]); + ++i; + } + return ; +} + +int ex_builtin(char **fields, __attribute__((unused)) + t_vec *assignments, const t_vec *redirections, t_execution_env *env) +{ + int fds[3]; + + save_std_filenos(fds); + dup_pipes(env); + dup_redirections(redirections); + if (!ft_strcmp(fields[0], "cd")) + env->builtin_ret_val = cd(count_fields(fields), fields, env); + else if (!ft_strcmp(fields[0], "echo")) + env->builtin_ret_val = echo(count_fields(fields), fields); + else if (!ft_strcmp(fields[0], "pwd")) + env->builtin_ret_val = pwd(); + else if (!ft_strcmp(fields[0], "env")) + env->builtin_ret_val = ft_env(count_fields(fields), env); + else if (!ft_strcmp(fields[0], "export")) + env->builtin_ret_val = export(count_fields(fields), fields, env); + else if (!ft_strcmp(fields[0], "unset")) + env->builtin_ret_val = unset(count_fields(fields), fields, env); + else if (!ft_strcmp(fields[0], "exit")) + env->builtin_ret_val = execute_exit(count_fields(fields), fields, env); + else + return (1); + close_redirections(redirections); + close_pipes(env); + restore_std_filenos(fds); + return (0); +} \ No newline at end of file diff --git a/src/execute_cmd.c b/src/execute_cmd.c new file mode 100644 index 0000000..9256724 --- /dev/null +++ b/src/execute_cmd.c @@ -0,0 +1,114 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execute_cmd.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include +#include + +static void close_redirection(void *v_redir) +{ + t_redirection *redir; + + redir = v_redir; + close(redir->from_to_fds[1]); + return ; +} + +static int assignments_to_env(const t_vec *assignments, t_execution_env *env) +{ + size_t i; + const char *var_line; + char *var_name; + + i = 0; + while (i < assignments->size) + { + var_line = *(char **)ft_vec_caccess(assignments, i); + var_name = get_var_name(var_line); + if (!var_name) + return (1); + if (set_env_var_value(env, var_name, + var_line + ft_strlen(var_name) + 1)) + { + free(var_name); + return (1); + } + free(var_name); + ++i; + } + return (0); +} + +static int ex_simple_command(t_parse_tree_node *simple_command, t_execution_env *env) +{ + t_vec redirections; + t_vec assignments; + char **fields; + int res; + + res = save_redirections(&redirections, simple_command, env); + res = save_assignments(&assignments, simple_command, env) || res; + fields = NULL; + if (!res) + fields = expand(simple_command, env); + if (!fields || res) + res = 1; + else if (!*fields) + res = assignments_to_env(&assignments, env); + else + res = ex_fields(fields, &assignments, &redirections, env); + free_split(fields); + ft_vec_free(&redirections, close_redirection); + ft_vec_free(&assignments, free_str); + return (res); +} + +static int subshell(t_parse_tree_node *program, t_execution_env *env) +{ + int res; + int status; + pid_t pid; + + pid = fork(); + if (pid == 0) + { + env->subshell = 1; + res = ex_program(program, env); + env->exit = 1; + return (res); + } + else if (pid < 0) + return (1); + waitpid(pid, &status, 0); + if (!WIFEXITED(status)) + return (1); + env->ret_val = WEXITSTATUS(status); + return (0); +} + +int ex_command(t_parse_tree_node *command, t_execution_env *env) +{ + t_parse_tree_node *comp_command; + + if (env->exit) + return (0); + if (is_token_type(ft_vec_caccess(&command->children, 0), "simple_command")) + return (ex_simple_command(ft_vec_access(&command->children, 0), env)); + else + { + comp_command = ft_vec_access(&command->children, 0); + return (subshell(ft_vec_access(&comp_command->children, 1), env)); + } +} diff --git a/src/execute_raw.c b/src/execute_raw.c new file mode 100644 index 0000000..6b01f1e --- /dev/null +++ b/src/execute_raw.c @@ -0,0 +1,93 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* execute_raw.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include +#include +#include + +static int is_builtin(const char *str) +{ + if (!ft_strcmp(str, "cd")) + return (1); + if (!ft_strcmp(str, "echo")) + return (1); + if (!ft_strcmp(str, "pwd")) + return (1); + if (!ft_strcmp(str, "env")) + return (1); + if (!ft_strcmp(str, "export")) + return (1); + if (!ft_strcmp(str, "unset")) + return (1); + if (!ft_strcmp(str, "exit")) + return (1); + return (0); +} + +static int contains_path(const char *str) +{ + return (ft_strchr(str, '/') != NULL); +} + +static int file_exists(const char *path) +{ + return (!access(path, F_OK)); +} + +static char *get_path(const char *cmd, t_execution_env *env) +{ + char *path; + + path = NULL; + if (contains_path(cmd) && file_exists(cmd)) + path = ft_strdup(cmd); + else if (!contains_path(cmd)) + path = find_exe(cmd, env); + if (!path) + env->ret_val = 127; + return (path); +} + +int ex_fields(char **fields, t_vec *assignments, + const t_vec *redirections, t_execution_env *env) +{ + pid_t pid; + char *path; + + env->last_was_builtin = is_builtin(fields[0]); + if (env->last_was_builtin) + return (ex_builtin(fields, assignments, redirections, env)); + path = get_path(fields[0], env); + if (!path) + return (1); + pid = fork(); + if (pid == 0) + { + if (prepare_env(env, redirections, assignments) == 0) + execve(path, fields, assignments->vec); + exit(-1); + } + free(path); + if (pid < 0) + return (1); + if (ft_vec_append(&env->child_pids, &pid) != success) + { + kill(pid, SIGTERM); + return (1); + } + return (0); +} diff --git a/src/execution.c b/src/execution.c deleted file mode 100644 index 8ee7e80..0000000 --- a/src/execution.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* ************************************************************************** */ -/* */ -/* ::: :::::::: */ -/* execution.c :+: :+: :+: */ -/* +:+ +:+ +:+ */ -/* By: lnikolov -#include -#include -#include - -#include -#include -#include - -int is_token_type(const t_parse_tree_node *node, const char *type) -{ - return (!ft_strcmp(node->token.type, type)); -} - -void clear_old(t_vec *assignments, const char *new) -{ - size_t i; - char **assignment; - - i = assignments->size; - while (i > 0) - { - --i; - assignment = ft_vec_access(assignments, i); - if (cmp_var_name(*assignment, new)) - continue ; - ft_vec_erase(assignments, i, free); - } - return ; -} - -int add_word(t_vec *exp_str, const char *word, - const t_execution_env *env, int quote); - -int add_assignment(t_vec *assignments, const char *assignment, - const t_execution_env *env) -{ - t_vec advanced_copy; - char *copy; - - if (ft_vec_init(&advanced_copy, sizeof(char)) != success) - return (1); - if (add_word(&advanced_copy, assignment, env, 0)) - return (1); - *(char *)ft_vec_access(&advanced_copy, advanced_copy.size - 1) = '\0'; - copy = advanced_copy.vec; - unquote_field(copy); - clear_old(assignments, copy); - if (ft_vec_append(assignments, ©) == success) - return (0); - free(copy); - return (1); -} - -int save_assignments_prefix(t_vec *assignments, t_parse_tree_node *prefix, - const t_execution_env *env) -{ - size_t i; - t_parse_tree_node *subnode; - - i = 0; - while (i < prefix->children.size) - { - subnode = ft_vec_access(&prefix->children, i); - if (is_token_type(subnode, "ASSIGNMENT_WORD")) - { - if (add_assignment(assignments, subnode->token.str, env)) - return (1); - } - else if (is_token_type(subnode, "cmd_prefix")) - if (save_assignments_prefix(assignments, subnode, env)) - return (1); - ++i; - } - return (0); -} - -int save_assignments(t_vec *assignments, t_parse_tree_node *simple_command, - const t_execution_env *env) -{ - t_parse_tree_node *subnode; - - if (ft_vec_init(assignments, sizeof(char *)) != success) - return (1); - subnode = ft_vec_access(&simple_command->children, 0); - if (is_token_type(subnode, "cmd_prefix")) - return (save_assignments_prefix(assignments, subnode, env)); - return (0); -} - -char *get_word(const t_parse_tree_node *parent) -{ - char *res; - const t_parse_tree_node *word = ft_vec_caccess(&parent->children, 0); - - res = ft_strdup(word->token.str); - return (res); -} - -int expand_filename(char **filename, const t_execution_env *env) -{ - t_vec advanced_copy; - - if (ft_vec_init(&advanced_copy, sizeof(char)) != success) - return (1); - if (add_word(&advanced_copy, *filename, env, 0)) - { - ft_vec_free(&advanced_copy, NULL); - return (1); - } - free(*filename); - *filename = advanced_copy.vec; - filename[0][advanced_copy.size - 1] = '\0'; - unquote_field(*filename); - return (0); -} - -static void handle_fds(int *fd, int *sec_fd, const char *filename, - const t_parse_tree_node *operator) -{ - if (*fd < 0) - { - if (is_token_type(operator, "LESS")) - *fd = STDIN_FILENO; - else - *fd = STDOUT_FILENO; - } - if (is_token_type(operator, "LESS")) - *sec_fd = open(filename, O_RDONLY); - else if (is_token_type(operator, "GREAT")) - *sec_fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, - S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); - else - *sec_fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, - S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); - return ; -} - -int add_redirection_file(t_vec *redirections, - t_parse_tree_node *io_file, int fd, t_execution_env *env) -{ - t_redirection redir; - const t_parse_tree_node *operator; - char *filename; - int sec_fd; - - filename = get_word(ft_vec_caccess(&io_file->children, 1)); - if (!filename) - return (1); - expand_filename(&filename, env); - operator = ft_vec_caccess(&io_file->children, 0); - handle_fds(&fd, &sec_fd, filename, operator); - if (sec_fd < 0) - { - free(filename); - env->ret_val = 1; - return (1); - } - redir = (t_redirection){.from_to_fds[0] = fd, .from_to_fds[1] = sec_fd}; - free(filename); - return (ft_vec_append(redirections, &redir) != success); -} - -static int write_line_to_pipe(int pipe_fd, const char *line, - const t_execution_env *env, int expand) -{ - size_t i; - char *var; - const char *value; - - i = 0; - while (line[i]) - { - if (line[i] != '$' || !expand) - { - ft_dprintf(pipe_fd, "%c", line[i]); - ++i; - continue ; - } - ++i; - var = get_var_name(line + i); - if (!var) - return (1); - value = get_env_var_value(env, var); - if (value) - ft_dprintf(pipe_fd, "%s", value); - i += ft_strlen(var); - free(var); - } - return (0); -} - -static char *here_file_getline(void) -{ - ft_printf("> "); - return (get_next_line(STDIN_FILENO)); -} - -// In case of an error the pipe_fd is repurposed to indicate the error. -// This is done to save a few lines -int here_file_to_pipe(int pipe_fd, char *delimiter, - const t_execution_env *env) -{ - int expand; - char *line; - - expand = !unquote_field(delimiter); - line = here_file_getline(); - while (line && ft_strncmp(line, delimiter, ft_strlen(line) - 1)) - { - if (write_line_to_pipe(pipe_fd, line, env, expand)) - { - pipe_fd = -1; - break ; - } - free(line); - line = here_file_getline(); - } - if (!line) - ft_printf - ("minishell: warning: here-document delimited by EOF instead of %s\n", - delimiter); - get_next_line(-1); - free(line); - return (pipe_fd == -1); -} - -int add_redirection_here(t_vec *redirections, - t_parse_tree_node *io_here, int fd, const t_execution_env *env) -{ - char *delimiter; - int pipe_fds[2]; - int err; - t_redirection redir; - - delimiter = get_word(ft_vec_caccess(&io_here->children, 1)); - if (!delimiter) - return (1); - if (fd == -1) - fd = STDIN_FILENO; - if (pipe(pipe_fds)) - { - free(delimiter); - return (1); - } - err = here_file_to_pipe(pipe_fds[1], delimiter, env); - close(pipe_fds[1]); - free(delimiter); - if (err) - return (1); - redir = (t_redirection){.from_to_fds[0] = fd, - .from_to_fds[1] = pipe_fds[0]}; - return (ft_vec_append(redirections, &redir) != success); -} - -int add_redirection(t_vec *redirections, - t_parse_tree_node *redirect, t_execution_env *env) -{ - int fd; - t_parse_tree_node *subnode; - - fd = -1; - subnode = ft_vec_access(&redirect->children, 0); - if (redirect->children.size == 2) - { - fd = ft_atoi(subnode->token.str); - if (fd < 0) - fd = -2; - subnode = ft_vec_access(&redirect->children, 1); - } - if (is_token_type(subnode, "io_file")) - return (add_redirection_file(redirections, subnode, fd, env)); - else - return (add_redirection_here(redirections, subnode, fd, env)); -} - -int save_redirections_psfix(t_vec *redirections, - t_parse_tree_node *node, t_execution_env *env) -{ - size_t i; - t_parse_tree_node *subnode; - - i = 0; - while (i < node->children.size) - { - subnode = ft_vec_access(&node->children, i); - if (is_token_type(subnode, "io_redirect")) - { - if (add_redirection(redirections, subnode, env)) - return (1); - } - else if (is_token_type(subnode, "cmd_suffix") - || is_token_type(subnode, "cmd_prefix")) - if (save_redirections_psfix(redirections, subnode, env)) - return (1); - ++i; - } - return (0); -} - -int save_redirections(t_vec *redirections, - t_parse_tree_node *simple_command, t_execution_env *env) -{ - t_parse_tree_node *subnode; - - if (ft_vec_init(redirections, sizeof(t_redirection)) != success) - return (1); - subnode = ft_vec_access(&simple_command->children, 0); - if (is_token_type(subnode, "cmd_prefix")) - if (save_redirections_psfix(redirections, subnode, env)) - return (1); - subnode = ft_vec_access(&simple_command->children, - simple_command->children.size - 1); - if (is_token_type(subnode, "cmd_suffix")) - if (save_redirections_psfix(redirections, subnode, env)) - return (1); - return (0); -} - -static char *get_value(const char *word, size_t *i, const t_execution_env *env) -{ - char *var; - char *value; - const char *const_val; - - if (word[*i] == '?') - { - ++*i; - value = ft_itoa(env->ret_val); - } - else - { - var = get_var_name(word + *i); - if (!var) - return (NULL); - *i += ft_strlen(var); - const_val = get_env_var_value(env, var); - free(var); - if (!const_val) - return (ft_strdup("")); - value = ft_strdup(const_val); - } - return (value); -} - -static int append_value(t_vec *exp_str, const char *value, int enquote_result) -{ - int error; - - if (!value) - return (1); - if (enquote_result) - { - error = ft_vec_append(exp_str, "'") != success; - error = error - || ft_vec_append_range(exp_str, value, ft_strlen(value)) != success; - error = error || ft_vec_append(exp_str, "'") != success; - return (error); - } - return (ft_vec_append_range(exp_str, value, ft_strlen(value)) != success); -} - -// Returns 1 when quote is set (or unset) -// and 0 when quote is left in current state -int set_quote(char *quote, char c) -{ - if (c == '"' || c == '\'') - { - if (*quote == '\0') - *quote = c; - else if (*quote == c) - *quote = '\0'; - else - return (0); - return (1); - } - return (0); -} - -int is_expandable(const char *str) -{ - return (str[0] == '$' - && (ft_isalpha(str[1]) - || str[1] == '_' - || str[1] == '?')); -} - -int add_word(t_vec *exp_str, const char *word, - const t_execution_env *env, int enquote_result) -{ - size_t i; - char quote; - const char space = ' '; - char *value; - - quote = '\0'; - i = 0; - while (word[i]) - { - set_quote("e, word[i]); - if (is_expandable(word + (i++)) && quote != '\'') - { - value = get_value(word, &i, env); - if (append_value(exp_str, value, enquote_result)) - { - free(value); - return (1); - } - free(value); - } - else - if (ft_vec_append(exp_str, word + i - 1) != success) - return (1); - } - return (ft_vec_append(exp_str, &space) != success); -} - -int expand_cmd(t_vec *exp_str, - const t_parse_tree_node *node, const t_execution_env *env) -{ - size_t i; - const t_parse_tree_node *subnode; - - i = 0; - while (i < node->children.size) - { - subnode = ft_vec_caccess(&node->children, i); - if (is_token_type(subnode, "cmd_suffix")) - { - if (expand_cmd(exp_str, subnode, env)) - return (1); - } - else if (is_token_type(subnode, "WORD")) - if (add_word(exp_str, subnode->token.str, env, 0)) - return (1); - ++i; - } - return (0); -} - -size_t get_next_word_size(const char *str) -{ - size_t n; - char quote; - - quote = 0; - n = 0; - while (str[n]) - { - if (str[n] == ' ' && !quote) - break ; - set_quote("e, str[n]); - ++n; - } - return (n); -} - -// Returns 1 if any unquoting happened else returns 0 -int unquote_field(char *field) -{ - int res; - size_t i; - char quote; - - res = 0; - quote = 0; - i = 0; - while (field && field[i]) - { - if (field[i] == '"' || field[i] == '\'') - { - if (!set_quote("e, field[i])) - { - ++i; - continue ; - } - res = 1; - ft_memmove(field + i, field + i + 1, ft_strlen(field + i + 1) + 1); - } - else - ++i; - } - return (res); -} - -void unquote(char **fields) -{ - size_t i; - - i = 0; - while (fields[i]) - { - unquote_field(fields[i]); - ++i; - } - return ; -} - -int process_word(const char *str, t_vec *fields, size_t *i) -{ - size_t n; - char *new_str; - - while (str[*i] == ' ') - ++*i; - n = get_next_word_size(str + *i); - if (n == 0) - return (0); - new_str = ft_strndup(str + *i, n); - if (!new_str) - return (1); - if (ft_vec_append(fields, &new_str) != success) - { - free(new_str); - return (1); - } - *i += n; - return (0); -} - -char **quoted_split(const char *str) -{ - size_t i; - t_vec fields; - const void *g_nullptr = NULL; - - if (ft_vec_init(&fields, sizeof(char *)) != success) - return (NULL); - i = 0; - while (str[i]) - { - if (process_word(str, &fields, &i)) - { - ft_vec_free(&fields, free); - return (NULL); - } - } - if (ft_vec_append(&fields, &g_nullptr) != success) - { - ft_vec_free(&fields, free); - return (NULL); - } - return (fields.vec); -} - -int expand_child(t_parse_tree_node *subnode, - t_vec *expanded_str, const t_execution_env *env) -{ - if ((is_token_type(subnode, "cmd_name") - || is_token_type(subnode, "cmd_word") - || is_token_type(subnode, "cmd_suffix")) - && expand_cmd(expanded_str, subnode, env)) - return (1); - return (0); -} - -char **expand(t_parse_tree_node *simple_command, const t_execution_env *env) -{ - const char g_null_char = '\0'; - size_t i; - char **fields; - t_vec expanded_str; - - ft_vec_init(&expanded_str, sizeof(char)); - i = 0; - while (i < simple_command->children.size) - { - if (expand_child(ft_vec_access(&simple_command->children, i++), - &expanded_str, env)) - { - ft_vec_free(&expanded_str, NULL); - return (NULL); - } - } - if (ft_vec_append(&expanded_str, &g_null_char) != success) - { - ft_vec_free(&expanded_str, NULL); - return (NULL); - } - fields = quoted_split(expanded_str.vec); - ft_vec_free(&expanded_str, NULL); - unquote(fields); - return (fields); -} - -int assignments_to_env(const t_vec *assignments, t_execution_env *env) -{ - size_t i; - const char *var_line; - char *var_name; - - i = 0; - while (i < assignments->size) - { - var_line = *(char **)ft_vec_caccess(assignments, i); - var_name = get_var_name(var_line); - if (!var_name) - return (1); - if (set_env_var_value(env, var_name, - var_line + ft_strlen(var_name) + 1)) - { - free(var_name); - return (1); - } - free(var_name); - ++i; - } - return (0); -} - -void free_split(char **fields) -{ - size_t i; - - if (!fields) - return ; - i = 0; - while (fields[i]) - { - free(fields[i]); - ++i; - } - free(fields); - return ; -} - -int contains_path(const char *str) -{ - return (ft_strchr(str, '/') != NULL); -} - -int file_exists(const char *path) -{ - return (!access(path, F_OK)); -} - -int is_contained_in_dir(const char *exe_name, const char *dir_name) -{ - DIR *dir; - struct dirent *dir_entry; - - dir = opendir(dir_name); - if (!dir) - return (0); - dir_entry = readdir(dir); - while (dir_entry) - { - if (!ft_strcmp(dir_entry->d_name, exe_name)) - { - closedir(dir); - return (1); - } - dir_entry = readdir(dir); - } - closedir(dir); - return (0); -} - -char *find_exe(const char *exe_name, const t_execution_env *env) -{ - const char *path; - char **paths; - size_t i; - char *res; - - path = get_env_var_value(env, "PATH"); - if (!path) - return (NULL); - paths = ft_split(path, ":"); - if (!paths) - return (NULL); - res = NULL; - i = 0; - while (paths[i] && !res) - { - if (is_contained_in_dir(exe_name, paths[i])) - if (ft_strcat_alloc(&res, paths[i])) - if (ft_strcat_alloc(&res, "/")) - ft_strcat_alloc(&res, exe_name); - ++i; - } - free_split(paths); - return (res); -} - -int dup_pipes(const t_execution_env *env) -{ - if (dup2(env->stdin_fd, STDIN_FILENO) == -1) - return (1); - if (dup2(env->stdout_fd, STDOUT_FILENO) == -1) - return (1); - if (env->stdin_fd != STDIN_FILENO) - close(env->stdin_fd); - if (env->stdout_fd != STDOUT_FILENO) - close(env->stdout_fd); - return (0); -} - -void close_pipes(const t_execution_env *env) -{ - close(env->stdin_fd); - close(env->stdout_fd); - return ; -} - -int dup_redirections(__attribute__((unused)) const t_vec *redirections) -{ - size_t i; - const t_redirection *redir; - - i = 0; - while (i < redirections->size) - { - redir = ft_vec_caccess(redirections, i); - dup2(redir->from_to_fds[1], redir->from_to_fds[0]); - close(redir->from_to_fds[1]); - ++i; - } - return (0); -} - -void close_redirections(const t_vec *redirections) -{ - size_t i; - const t_redirection *redir; - - i = 0; - while (i < redirections->size) - { - redir = ft_vec_caccess(redirections, i); - close(redir->from_to_fds[0]); - ++i; - } - return ; -} - -int add_exported(t_vec *assignments, const t_execution_env *env) -{ - size_t i; - char *var; - const t_vec *exported; - - exported = &env->vars->exported; - i = 0; - while (i < exported->size) - { - var = ft_strdup(*(char *const *)ft_vec_caccess(exported, i)); - if (ft_vec_append(assignments, &var) != success) - return (1); - ++i; - } - return (0); -} - -int is_builtin(const char *str) -{ - if (!ft_strcmp(str, "cd")) - return (1); - if (!ft_strcmp(str, "echo")) - return (1); - if (!ft_strcmp(str, "pwd")) - return (1); - if (!ft_strcmp(str, "env")) - return (1); - if (!ft_strcmp(str, "export")) - return (1); - if (!ft_strcmp(str, "unset")) - return (1); - if (!ft_strcmp(str, "exit")) - return (1); - return (0); -} - -size_t count_fields(char **fields) -{ - size_t i; - - i = 0; - while (fields[i]) - ++i; - return (i); -} - -int save_std_filenos(int fds[3]) -{ - fds[0] = dup(STDIN_FILENO); - if (fds[0] < 0) - return (1); - fds[1] = dup(STDOUT_FILENO); - if (fds[1] < 0) - { - close(fds[0]); - return (1); - } - fds[2] = dup(STDERR_FILENO); - if (fds[2] < 0) - { - close(fds[0]); - close(fds[1]); - return (1); - } - return (0); -} - -int restore_std_filenos(int fds[3]) -{ - if (dup2(fds[0], STDIN_FILENO) == -1) - return (1); - if (dup2(fds[1], STDOUT_FILENO) == -1) - return (1); - if (dup2(fds[2], STDERR_FILENO) == -1) - return (1); - close(fds[0]); - close(fds[1]); - close(fds[2]); - return (0); -} - -int ex_builtin(char **fields, __attribute__((unused)) - t_vec *assignments, __attribute__((unused)) const t_vec *redirections, - t_execution_env *env) -{ - int fds[3]; - - save_std_filenos(fds); - dup_pipes(env); - dup_redirections(redirections); - if (!ft_strcmp(fields[0], "cd")) - env->builtin_ret_val = cd(count_fields(fields), fields, env); - else if (!ft_strcmp(fields[0], "echo")) - env->builtin_ret_val = echo(count_fields(fields), fields); - else if (!ft_strcmp(fields[0], "pwd")) - env->builtin_ret_val = pwd(); - else if (!ft_strcmp(fields[0], "env")) - env->builtin_ret_val = ft_env(count_fields(fields), env); - else if (!ft_strcmp(fields[0], "export")) - env->builtin_ret_val = export(count_fields(fields), fields, env); - else if (!ft_strcmp(fields[0], "unset")) - env->builtin_ret_val = unset(count_fields(fields), fields, env); - else if (!ft_strcmp(fields[0], "exit")) - env->builtin_ret_val = execute_exit(count_fields(fields), fields, env); - else - return (1); - close_redirections(redirections); - close_pipes(env); - restore_std_filenos(fds); - return (0); -} - -void close_fds(t_vec *fds_to_close) -{ - int fd; - size_t i; - - i = 0; - while (i < fds_to_close->size) - { - fd = *(int *)ft_vec_access(fds_to_close, i); - close(fd); - ++i; - } - return ; -} - -char *get_path(const char *cmd, t_execution_env *env) -{ - char *path; - - path = NULL; - if (contains_path(cmd) && file_exists(cmd)) - path = ft_strdup(cmd); - else if (!contains_path(cmd)) - path = find_exe(cmd, env); - if (!path) - env->ret_val = 127; - return (path); -} - -int prepare_env(t_execution_env *env, - const t_vec *redirections, t_vec *assignments) -{ - int res; - - close_fds(&env->fds_to_close); - res = dup_pipes(env); - res = dup_redirections(redirections) || res; - res = add_exported(assignments, env) || res; - return (res); -} - -int ex_fields(char **fields, t_vec *assignments, - const t_vec *redirections, t_execution_env *env) -{ - pid_t pid; - char *path; - - env->last_was_builtin = is_builtin(fields[0]); - if (env->last_was_builtin) - return (ex_builtin(fields, assignments, redirections, env)); - path = get_path(fields[0], env); - if (!path) - return (1); - pid = fork(); - if (pid == 0) - { - if (prepare_env(env, redirections, assignments) == 0) - execve(path, fields, assignments->vec); - exit(-1); - } - free(path); - if (pid < 0) - return (1); - if (ft_vec_append(&env->child_pids, &pid) != success) - { - kill(pid, SIGTERM); - return (1); - } - return (0); -} - -void close_redirection(void *v_redir) -{ - t_redirection *redir; - - redir = v_redir; - close(redir->from_to_fds[1]); - return ; -} - -int ex_simple_command(t_parse_tree_node *simple_command, t_execution_env *env) -{ - t_vec redirections; - t_vec assignments; - char **fields; - int res; - - res = save_redirections(&redirections, simple_command, env); - res = save_assignments(&assignments, simple_command, env) || res; - fields = NULL; - if (!res) - fields = expand(simple_command, env); - if (!fields || res) - res = 1; - else if (!*fields) - res = assignments_to_env(&assignments, env); - else - res = ex_fields(fields, &assignments, &redirections, env); - free_split(fields); - ft_vec_free(&redirections, close_redirection); - ft_vec_free(&assignments, free_str); - return (res); -} - -t_ft_stat v_strcopy(void *v_dest, const void *v_src) -{ - char **dest; - const char *const *src; - - dest = v_dest; - src = v_src; - if (!*src) - { - *dest = NULL; - return (success); - } - *dest = ft_strdup(*src); - if (!*dest) - return (alloc_fail); - return (success); -} - -t_ft_stat v_copy_redir(void *v_dest, const void *v_src) -{ - t_redirection *dest; - const t_redirection *src; - - dest = v_dest; - src = v_src; - *dest = *src; - return (success); -} - -int ex_program(t_parse_tree_node *program, t_execution_env *env); - -int subshell(t_parse_tree_node *program, t_execution_env *env) -{ - int res; - int status; - pid_t pid; - - pid = fork(); - if (pid == 0) - { - env->subshell = 1; - res = ex_program(program, env); - env->exit = 1; - return (res); - } - else if (pid < 0) - return (1); - waitpid(pid, &status, 0); - if (!WIFEXITED(status)) - return (1); - env->ret_val = WEXITSTATUS(status); - return (0); -} - -int ex_command(t_parse_tree_node *command, t_execution_env *env) -{ - t_parse_tree_node *comp_command; - - if (env->exit) - return (0); - if (is_token_type(ft_vec_caccess(&command->children, 0), "simple_command")) - return (ex_simple_command(ft_vec_access(&command->children, 0), env)); - else - { - comp_command = ft_vec_access(&command->children, 0); - return (subshell(ft_vec_access(&comp_command->children, 1), env)); - } -} - -void killall(t_vec *child_pids, int sig_num) -{ - pid_t child_pid; - size_t i; - - i = 0; - while (i < child_pids->size) - { - child_pid = *(pid_t *)ft_vec_access(child_pids, i); - kill(child_pid, sig_num); - ++i; - } - return ; -} - -void wait_for_all_to_end(t_vec *child_pids) -{ - size_t i; - pid_t pid; - int sig_num; - - sig_num = 0; - i = child_pids->size; - while (i > 0) - { - --i; - pid = *(pid_t *)ft_vec_access(child_pids, i); - if (g_last_signal == 0) - waitpid(pid, NULL, 0); - if (g_last_signal) - { - sig_num = g_last_signal; - g_last_signal = 0; - killall(child_pids, g_last_signal); - i = child_pids->size; - } - ft_vec_forget(child_pids, i); - } - ft_vec_free(child_pids, NULL); - if (g_last_signal == 0) - g_last_signal = sig_num; - return ; -} - -void wait_for_return(t_execution_env *env) -{ - pid_t last_pid; - int status; - - if (env->last_was_builtin) - env->ret_val = env->builtin_ret_val; - else - { - if (env->child_pids.size == 0) - return ; - last_pid = *(pid_t *)ft_vec_access(&env->child_pids, - env->child_pids.size - 1); - waitpid(last_pid, &status, 0); - if (g_last_signal == 0) - if (WIFEXITED(status)) - env->ret_val = WEXITSTATUS(status); - } - wait_for_all_to_end(&env->child_pids); - return ; -} - -int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth); - -int advance_pipeline(t_parse_tree_node *pipeline, - t_execution_env *env, int depth) -{ - int pipe_fds[2]; - int res; - - if (pipe(pipe_fds)) - return (1); - res = ft_vec_append(&env->fds_to_close, &pipe_fds[0]); - res = res || ft_vec_append(&env->fds_to_close, &env->stdout_fd); - ft_swap_int(&pipe_fds[1], &env->stdout_fd); - res = res - || ex_pipeline(ft_vec_access(&pipeline->children, 0), env, depth + 1); - ft_swap_int(&pipe_fds[1], &env->stdout_fd); - close(pipe_fds[1]); - if (res == 0) - { - ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1); - ft_vec_forget(&env->fds_to_close, env->fds_to_close.size - 1); - } - ft_swap_int(&pipe_fds[0], &env->stdin_fd); - res = res || ex_command(ft_vec_access(&pipeline->children, 2), env); - ft_swap_int(&pipe_fds[0], &env->stdin_fd); - close(pipe_fds[0]); - return (res); -} - -int ex_pipeline(t_parse_tree_node *pipeline, t_execution_env *env, int depth) -{ - if (g_last_signal != 0) - return (0); - if (pipeline->children.size == 1) - { - if (ex_command(ft_vec_access(&pipeline->children, 0), env)) - return (1); - } - else - { - if (advance_pipeline(pipeline, env, depth)) - { - killall(&env->child_pids, SIGTERM); - return (1); - } - } - if (depth == 0) - wait_for_return(env); - return (0); -} - -int ex_program(t_parse_tree_node *program, t_execution_env *env) -{ - if (program->children.size == 1) - return (ex_pipeline(ft_vec_access(&program->children, 0), env, 0)); - if (ex_program(ft_vec_access(&program->children, 0), env)) - return (1); - if (is_token_type(ft_vec_caccess(&program->children, 1), "AND_IF")) - { - if (env->ret_val == 0) - return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0)); - } - else - { - if (env->ret_val != 0) - return (ex_pipeline(ft_vec_access(&program->children, 2), env, 0)); - } - return (0); -} - -int execute(t_tree *parse_tree, t_execution_env *env) -{ - int res; - - res = ex_program(parse_tree, env); - if (g_last_signal != 0) - { - env->ret_val = 128 + g_last_signal; - g_last_signal = 0; - } - return (res); -} diff --git a/src/expand.c b/src/expand.c new file mode 100644 index 0000000..a8c0674 --- /dev/null +++ b/src/expand.c @@ -0,0 +1,91 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* expand.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov children.size) + { + subnode = ft_vec_caccess(&node->children, i); + if (is_token_type(subnode, "cmd_suffix")) + { + if (expand_cmd(exp_str, subnode, env)) + return (1); + } + else if (is_token_type(subnode, "WORD")) + if (add_word(exp_str, subnode->token.str, env, 0)) + return (1); + ++i; + } + return (0); +} + +static int expand_child(t_parse_tree_node *subnode, + t_vec *expanded_str, const t_execution_env *env) +{ + if ((is_token_type(subnode, "cmd_name") + || is_token_type(subnode, "cmd_word") + || is_token_type(subnode, "cmd_suffix")) + && expand_cmd(expanded_str, subnode, env)) + return (1); + return (0); +} + +char **expand(t_parse_tree_node *simple_command, const t_execution_env *env) +{ + const char g_null_char = '\0'; + size_t i; + char **fields; + t_vec expanded_str; + + ft_vec_init(&expanded_str, sizeof(char)); + i = 0; + while (i < simple_command->children.size) + { + if (expand_child(ft_vec_access(&simple_command->children, i++), + &expanded_str, env)) + { + ft_vec_free(&expanded_str, NULL); + return (NULL); + } + } + if (ft_vec_append(&expanded_str, &g_null_char) != success) + { + ft_vec_free(&expanded_str, NULL); + return (NULL); + } + fields = quoted_split(expanded_str.vec); + ft_vec_free(&expanded_str, NULL); + unquote(fields); + return (fields); +} \ No newline at end of file diff --git a/src/expand_split.c b/src/expand_split.c new file mode 100644 index 0000000..e2a2fe6 --- /dev/null +++ b/src/expand_split.c @@ -0,0 +1,79 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* expand_split.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov + +static size_t get_next_word_size(const char *str) +{ + size_t n; + char quote; + + quote = 0; + n = 0; + while (str[n]) + { + if (str[n] == ' ' && !quote) + break ; + set_quote("e, str[n]); + ++n; + } + return (n); +} + +static int process_word(const char *str, t_vec *fields, size_t *i) +{ + size_t n; + char *new_str; + + while (str[*i] == ' ') + ++*i; + n = get_next_word_size(str + *i); + if (n == 0) + return (0); + new_str = ft_strndup(str + *i, n); + if (!new_str) + return (1); + if (ft_vec_append(fields, &new_str) != success) + { + free(new_str); + return (1); + } + *i += n; + return (0); +} + +char **quoted_split(const char *str) +{ + size_t i; + t_vec fields; + const void *g_nullptr = NULL; + + if (ft_vec_init(&fields, sizeof(char *)) != success) + return (NULL); + i = 0; + while (str[i]) + { + if (process_word(str, &fields, &i)) + { + ft_vec_free(&fields, free); + return (NULL); + } + } + if (ft_vec_append(&fields, &g_nullptr) != success) + { + ft_vec_free(&fields, free); + return (NULL); + } + return (fields.vec); +} \ No newline at end of file diff --git a/src/redir_file.c b/src/redir_file.c new file mode 100644 index 0000000..b19e1c9 --- /dev/null +++ b/src/redir_file.c @@ -0,0 +1,83 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* redir_file.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include +#include + +static void handle_fds(int *fd, int *sec_fd, const char *filename, + const t_parse_tree_node *operator) +{ + if (*fd < 0) + { + if (is_token_type(operator, "LESS")) + *fd = STDIN_FILENO; + else + *fd = STDOUT_FILENO; + } + if (is_token_type(operator, "LESS")) + *sec_fd = open(filename, O_RDONLY); + else if (is_token_type(operator, "GREAT")) + *sec_fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, + S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); + else + *sec_fd = open(filename, O_CREAT | O_WRONLY | O_APPEND, + S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); + return ; +} + +static int expand_filename(char **filename, const t_execution_env *env) +{ + t_vec advanced_copy; + + if (ft_vec_init(&advanced_copy, sizeof(char)) != success) + return (1); + if (add_word(&advanced_copy, *filename, env, 0)) + { + ft_vec_free(&advanced_copy, NULL); + return (1); + } + free(*filename); + *filename = advanced_copy.vec; + filename[0][advanced_copy.size - 1] = '\0'; + unquote_field(*filename); + return (0); +} + +int add_redirection_file(t_vec *redirections, + t_parse_tree_node *io_file, int fd, t_execution_env *env) +{ + t_redirection redir; + const t_parse_tree_node *operator; + char *filename; + int sec_fd; + + filename = get_word(ft_vec_caccess(&io_file->children, 1)); + if (!filename) + return (1); + expand_filename(&filename, env); + operator = ft_vec_caccess(&io_file->children, 0); + handle_fds(&fd, &sec_fd, filename, operator); + if (sec_fd < 0) + { + free(filename); + env->ret_val = 1; + return (1); + } + redir = (t_redirection){.from_to_fds[0] = fd, .from_to_fds[1] = sec_fd}; + free(filename); + return (ft_vec_append(redirections, &redir) != success); +} + diff --git a/src/redir_here.c b/src/redir_here.c new file mode 100644 index 0000000..cdaacbb --- /dev/null +++ b/src/redir_here.c @@ -0,0 +1,112 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* redir_here.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov +#include +#include + + + +static char *here_file_getline(void) +{ + ft_printf("> "); + return (get_next_line(STDIN_FILENO)); +} + +static int write_line_to_pipe(int pipe_fd, const char *line, + const t_execution_env *env, int expand) +{ + size_t i; + char *var; + const char *value; + + i = 0; + while (line[i]) + { + if (line[i] != '$' || !expand) + { + ft_dprintf(pipe_fd, "%c", line[i]); + ++i; + continue ; + } + ++i; + var = get_var_name(line + i); + if (!var) + return (1); + value = get_env_var_value(env, var); + if (value) + ft_dprintf(pipe_fd, "%s", value); + i += ft_strlen(var); + free(var); + } + return (0); +} + +// In case of an error the pipe_fd is repurposed to indicate the error. +// This is done to save a few lines +int here_file_to_pipe(int pipe_fd, char *delimiter, + const t_execution_env *env) +{ + int expand; + char *line; + + expand = !unquote_field(delimiter); + line = here_file_getline(); + while (line && ft_strncmp(line, delimiter, ft_strlen(line) - 1)) + { + if (write_line_to_pipe(pipe_fd, line, env, expand)) + { + pipe_fd = -1; + break ; + } + free(line); + line = here_file_getline(); + } + if (!line) + ft_printf + ("minishell: warning: here-document delimited by EOF instead of %s\n", + delimiter); + get_next_line(-1); + free(line); + return (pipe_fd == -1); +} + +int add_redirection_here(t_vec *redirections, + t_parse_tree_node *io_here, int fd, const t_execution_env *env) +{ + char *delimiter; + int pipe_fds[2]; + int err; + t_redirection redir; + + delimiter = get_word(ft_vec_caccess(&io_here->children, 1)); + if (!delimiter) + return (1); + if (fd == -1) + fd = STDIN_FILENO; + if (pipe(pipe_fds)) + { + free(delimiter); + return (1); + } + err = here_file_to_pipe(pipe_fds[1], delimiter, env); + close(pipe_fds[1]); + free(delimiter); + if (err) + return (1); + redir = (t_redirection){.from_to_fds[0] = fd, + .from_to_fds[1] = pipe_fds[0]}; + return (ft_vec_append(redirections, &redir) != success); +} \ No newline at end of file diff --git a/src/redirection.c b/src/redirection.c new file mode 100644 index 0000000..9f4bbce --- /dev/null +++ b/src/redirection.c @@ -0,0 +1,89 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* redirection.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: lnikolov children, 0); + + res = ft_strdup(word->token.str); + return (res); +} + +static int add_redirection(t_vec *redirections, + t_parse_tree_node *redirect, t_execution_env *env) +{ + int fd; + t_parse_tree_node *subnode; + + fd = -1; + subnode = ft_vec_access(&redirect->children, 0); + if (redirect->children.size == 2) + { + fd = ft_atoi(subnode->token.str); + if (fd < 0) + fd = -2; + subnode = ft_vec_access(&redirect->children, 1); + } + if (is_token_type(subnode, "io_file")) + return (add_redirection_file(redirections, subnode, fd, env)); + else + return (add_redirection_here(redirections, subnode, fd, env)); +} + +static int save_redirections_psfix(t_vec *redirections, + t_parse_tree_node *node, t_execution_env *env) +{ + size_t i; + t_parse_tree_node *subnode; + + i = 0; + while (i < node->children.size) + { + subnode = ft_vec_access(&node->children, i); + if (is_token_type(subnode, "io_redirect")) + { + if (add_redirection(redirections, subnode, env)) + return (1); + } + else if (is_token_type(subnode, "cmd_suffix") + || is_token_type(subnode, "cmd_prefix")) + if (save_redirections_psfix(redirections, subnode, env)) + return (1); + ++i; + } + return (0); +} + +int save_redirections(t_vec *redirections, + t_parse_tree_node *simple_command, t_execution_env *env) +{ + t_parse_tree_node *subnode; + + if (ft_vec_init(redirections, sizeof(t_redirection)) != success) + return (1); + subnode = ft_vec_access(&simple_command->children, 0); + if (is_token_type(subnode, "cmd_prefix")) + if (save_redirections_psfix(redirections, subnode, env)) + return (1); + subnode = ft_vec_access(&simple_command->children, + simple_command->children.size - 1); + if (is_token_type(subnode, "cmd_suffix")) + if (save_redirections_psfix(redirections, subnode, env)) + return (1); + return (0); +} -- 2.30.2