/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* exec_command.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: jschaft +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/04/24 13:48:00 by jschaft #+# #+# */ /* Updated: 2024/06/21 15:57:28 by mcolonna ### ########.fr */ /* */ /* ************************************************************************** */ #include "include.h" typedef struct s_exec_command_global { t_memclass mc; int nb_calls; t_pipes *pipes; } t_exec_command_global; static void close_all_pipes(t_exec_command_global *global) { int i; i = 0; if (global->pipes[i].pipe[0] != 0) if (close(global->pipes[i].pipe[0]) < 0) minishell_error("errno"); while (++i < global->nb_calls) { if (close(global->pipes[i].pipe[0]) < 0) minishell_error("errno"); if (close(global->pipes[i].pipe[1]) < 0) minishell_error("errno"); } if (global->pipes[i].pipe[1] != 1) if (close(global->pipes[i].pipe[1]) < 0) minishell_error("errno"); } // Execute a program with specific stdin and stdout: // - inout[0] is stdin // - inout[0] is stdout // If call.program doesn't start with "./" or "/", find the program in $PATH. // (TODO) // If the program wasn't to found in $PATH, or the fork didn't work, // write the error and return the error status. static int execute_call( t_exec_command_global *global, t_call call, const int inout[2], char *const envp[]) { const char **path = get_path(global->mc, envp); pid_t pid; const char *program_path; program_path = search_path(global->mc, path, call.program); if (!program_path) return (minishell_error(str_join(fatal_error, global->mc, "command not found: ", str_join(fatal_error, global->mc, call.program, "\n"))), 127); pid = fork(); if (pid < 0) return (minishell_error("errno"), errno); if (pid == 0) { if (dup2(inout[0], 0) < 0 || dup2(inout[1], 1) < 0) return (minishell_error("errno"), errno); close_all_pipes(global); execve(program_path, call.argv, envp); return (minishell_error("errno"), errno); } return (0); } static int create_pipes(t_exec_command_global *global, t_command command) { int i; global->pipes = mem_alloc( err_remember, global->mc, sizeof(t_pipes) * (global->nb_calls + 1)); if (err_get()) return (minishell_error("errno"), errno); i = 0; global->pipes[i].pipe[0] = command.input_fd; while (++i < global->nb_calls) if (pipe(global->pipes[i].pipe) < 0) return (minishell_error("errno"), errno); global->pipes[i].pipe[1] = command.output_fd; return (0); } static int exec_each_call(t_exec_command_global *global, t_command command, char *const envp[]) { int i; int r; int inout[2]; i = -1; while (++i < global->nb_calls) { inout[0] = global->pipes[i].pipe[0]; inout[1] = global->pipes[i + 1].pipe[1]; if (is_builtin(command.calls[i].program)) r = exec_builtin(command.calls[i]); else r = execute_call(global, command.calls[i], inout, envp); if (r) return (r); } return (r); } // FIXME line jump if command not found int execute_command(t_env *env, t_command command) { t_exec_command_global global; int r; r = 0; global.mc = env->mc_command; global.nb_calls = 0; while (command.calls[global.nb_calls].program != NULL) global.nb_calls++; if (global.nb_calls == 0) return (minishell_error("no program given"), 1); r = create_pipes(&global, command); if (r) return (r); r = exec_each_call(&global, command, env->envp); close_all_pipes(&global); while (wait(NULL) != -1) ; if (errno != ECHILD) return (minishell_error("errno"), errno); return (r); }