diff --git a/exec/include/exec/spawn_cmd/_redirection.h b/exec/include/exec/spawn_cmd/_redirection.h new file mode 100644 index 00000000..b70092de --- /dev/null +++ b/exec/include/exec/spawn_cmd/_redirection.h @@ -0,0 +1,49 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* _redirection.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/29 17:24:19 by maiboyer #+# #+# */ +/* Updated: 2024/07/29 19:09:56 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef _REDIRECTION_H +#define _REDIRECTION_H + +#include "me/types.h" + +typedef struct s_exec_redirect t_exec_redirect; +typedef struct s_exec_redirect_fd t_exec_redirect_fd; +typedef struct s_exec_redirect_heredoc t_exec_redirect_heredoc; + +struct s_exec_redirect_heredoc +{ +}; + +struct s_exec_redirect_fd +{ + int infile_fd; + int outfile_fd; + t_str file_path; +}; + +union u_exec_redirect_data { + t_exec_redirect_heredoc heredoc; + t_exec_redirect_fd fd; +}; +enum e_exec_redirect_kind +{ + EXEC_REDIR_FD, + EXEC_REDIR_HEREDOC, +}; + +struct s_exec_redirect +{ + union u_exec_redirect_data data; + enum e_exec_redirect_kind kind; +}; + +#endif /* _REDIRECTION_H */ diff --git a/exec/include/exec/spawn_cmd/pipe.h b/exec/include/exec/spawn_cmd/pipe.h new file mode 100644 index 00000000..c8350f94 --- /dev/null +++ b/exec/include/exec/spawn_cmd/pipe.h @@ -0,0 +1,30 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pipe.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/01/04 17:57:29 by maiboyer #+# #+# */ +/* Updated: 2024/01/04 17:59:30 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PIPE_H +# define PIPE_H + +# include "me/types.h" + +/// @brief Pipe structure +typedef struct s_pipe +{ + int read; + int write; +} t_pipe; + +/// @brief Create a pipe +/// @param[out] out the created pipe +/// @return the error +t_error create_pipe(t_pipe *out); + +#endif /* PIPE_H */ diff --git a/exec/include/exec/spawn_cmd/process.h b/exec/include/exec/spawn_cmd/process.h new file mode 100644 index 00000000..7b23d5d0 --- /dev/null +++ b/exec/include/exec/spawn_cmd/process.h @@ -0,0 +1,173 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* process.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/01/03 15:43:08 by maiboyer #+# #+# */ +/* Updated: 2024/07/11 18:59:04 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef PROCESS_H +# define PROCESS_H + +# include "me/types.h" +# include "me/vec/vec_str.h" +# include "me/vec/vec_u8.h" + +typedef t_i32 t_pid; +typedef t_i32 t_exit_code; + +enum e_redirection +{ + R_INHERITED = 0, + R_PIPED = 1, + R_FD = 2, +}; + +union u_redirection +{ + struct s_fd_redirection + { + int value; + } fd; + struct s_piped_redirection + { + } piped; + struct s_inherited_redirection + { + } inherited; +}; + +/// @brief Redirection for spawning a process +typedef struct s_redirection +{ + enum e_redirection tag; + union u_redirection vals; +} t_redirection; + +/// @brief Create a piped redirection +/// @param void +/// @return the redirection +static inline t_redirection piped(void) +{ + return ((t_redirection){ + .tag = R_PIPED, + }); +} + +/// @brief Create an inherited redirection (inherit from the parent process) +/// @param void +/// @return the redirection +static inline t_redirection inherited(void) +{ + return ((t_redirection){ + .tag = R_INHERITED, + }); +} + +/// @brief Create a file descriptor redirection +/// @param fd file descriptor to redirect +/// @return the redirection +static inline t_redirection fd(int fd) +{ + return ((t_redirection){.tag = R_FD, \ + .vals = (union u_redirection){\ + .fd = {.value = fd}, \ + }}); +} + +/// @brief Wrapped file descriptor tag +enum e_wrapped_fd_tag +{ + READ_ONLY, + WRITE_ONLY, + READ_WRITE, + INVALID, +}; + +/// @brief Wrapped file descriptor +union u_wrapped_fd +{ + struct s_read_only + { + int fd; + } ro; + struct s_write_only + { + int fd; + } wo; + struct s_read_write + { + int fd; + } rw; +}; + +/// @brief Wrapped file descriptor +typedef struct s_wrapped_fd +{ + enum e_wrapped_fd_tag tag; + union u_wrapped_fd vals; +} t_wrapped_fd; + +/// @brief Create a Read only wrapped file descriptor +/// @param fd file descriptor to wrap +/// @return the wrapped file descriptor +static inline t_wrapped_fd ro(int fd) +{ + return ((t_wrapped_fd){.tag = READ_ONLY, \ + .vals = (union u_wrapped_fd){\ + .ro = {.fd = fd}, \ + }}); +} + +/// @brief Create a Write only wrapped file descriptor +/// @param fd file descriptor to wrap +/// @return the wrapped file descriptor +static inline t_wrapped_fd wo(int fd) +{ + return ((t_wrapped_fd){.tag = WRITE_ONLY, + .vals = (union u_wrapped_fd){.wo = {.fd = fd}}}); +} + +/// @brief Spawn information +typedef struct s_spawn_info +{ + t_redirection stdin; + t_redirection stdout; + t_redirection stderr; + t_vec_str arguments; + t_vec_str environement; + t_str binary_path; + void (*forked_free)(void *); + void *forked_free_args; +} t_spawn_info; + +/// @brief Process information +typedef struct s_process +{ + t_wrapped_fd stdin; + t_wrapped_fd stdout; + t_wrapped_fd stderr; + t_pid pid; +} t_process; +/// @struct Process output +/// @brief Process output information +typedef struct s_process_output +{ + t_pid pid; + t_vec_u8 stdout; + t_vec_u8 stderr; + t_exit_code exit_code; +} t_process_output; + +/// @brief Spawn a new process with the given information +/// @param info the information to spawn the process +/// @param process data returned by the function +/// @return true if an error occured, false otherwise +t_error spawn_process(t_spawn_info info, + t_process *process); + +#endif /* PROCESS_H */ diff --git a/exec/src/run_ast.c b/exec/src/run_ast.c index 4abb48ef..f1159fe6 100644 --- a/exec/src/run_ast.c +++ b/exec/src/run_ast.c @@ -6,18 +6,18 @@ /* By: maiboyer +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/07/11 17:22:29 by maiboyer #+# #+# */ -/* Updated: 2024/07/28 19:19:09 by maiboyer ### ########.fr */ +/* Updated: 2024/07/29 19:04:56 by maiboyer ### ########.fr */ /* */ /* ************************************************************************** */ #include "app/state.h" #include "ast/ast.h" #include "exec/run.h" +#include "exec/spawn_cmd/pipe.h" +#include "exec/spawn_cmd/process.h" #include "me/convert/numbers_to_str.h" #include "me/hashmap/hashmap_env.h" #include "me/mem/mem.h" -#include "me/os/pipe.h" -#include "me/os/process.h" #include "me/str/str.h" #include "me/string/string.h" #include "me/types.h" @@ -629,36 +629,8 @@ t_error run_command(t_ast_command *command, t_state *state, t_command_result *ou i = 0; while (i < command->cmd_word.len) { - tmp = command->cmd_word.buffer[i]; - if (tmp->kind == AST_WORD) - { - if (_word_into_str(tmp, state, &args)) - return (ERROR); - } - if (tmp->kind == AST_EXPANSION) - { - if (run_expansion(&tmp->data.expansion, state, &exp_out)) - return (ERROR); - if (!(exp_out.exists && exp_out.value != NULL)) - continue; - if (str_split(exp_out.value, _get_ifs_value(state), &split)) - return (ERROR); - while (!vec_str_pop_front(&split, &tmp_str)) - vec_str_push(&args, tmp_str); - vec_str_free(split); - } - if (tmp->kind == AST_ARITHMETIC_EXPANSION) - { - if (run_arithmetic_expansion(&tmp->data.arithmetic_expansion, state, &arith_out)) - return (ERROR); - if (i64_to_str(arith_out, &tmp_str)) - return (ERROR); - vec_str_push(&args, tmp_str); - } - if (tmp->kind == AST_COMMAND_SUBSTITUTION) - { + if (_ast_into_str(command->cmd_word.buffer[i], state, &args)) return (ERROR); - } i++; } while (i < command->prefixes.len) diff --git a/exec/src/spawn_cmd/gnu_source.h b/exec/src/spawn_cmd/gnu_source.h new file mode 100644 index 00000000..848090fd --- /dev/null +++ b/exec/src/spawn_cmd/gnu_source.h @@ -0,0 +1,18 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* gnu_source.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/07/10 17:53:46 by maiboyer #+# #+# */ +/* Updated: 2024/07/10 17:54:49 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef GNU_SOURCE_H +# define GNU_SOURCE_H + +# define _GNU_SOURCE + +#endif /* GNU_SOURCE_H */ diff --git a/exec/src/spawn_cmd/pipe.c b/exec/src/spawn_cmd/pipe.c new file mode 100644 index 00000000..5c5d90ed --- /dev/null +++ b/exec/src/spawn_cmd/pipe.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* pipe.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/01/04 17:59:48 by maiboyer #+# #+# */ +/* Updated: 2024/07/29 19:05:12 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/spawn_cmd/pipe.h" + +t_error exec_create_pipe(t_pipe *out) +{ + int fds[2]; + + if (pipe(fds)) + return (ERROR); + out->read = fds[0]; + out->write = fds[1]; + return (NO_ERROR); +} diff --git a/exec/src/spawn_cmd/process.c b/exec/src/spawn_cmd/process.c new file mode 100644 index 00000000..e0ef1496 --- /dev/null +++ b/exec/src/spawn_cmd/process.c @@ -0,0 +1,124 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* process.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/01/03 16:22:41 by maiboyer #+# #+# */ +/* Updated: 2024/07/29 19:06:23 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/spawn_cmd/process.h" +#include "me/mem/mem.h" +#include "me/os/pipe.h" +#include "me/printf/printf.h" +#include "me/str/str.h" +#include "me/string/string.h" +#include "me/types.h" +#include "me/vec/vec_ast.h" +#include "me/vec/vec_str.h" +#include +#include +#include + +bool exec_find_path(const t_str *s); +bool exec_find_null(const t_str *s); +bool exec_str_start_with(t_const_str s, t_const_str prefix); +t_error exec_handle_redirections(t_spawn_info *info, t_process *process); + +t_error exec_spawn_process_exec(t_spawn_info info, t_process *process) +{ + bool res; + + if (info.forked_free) + info.forked_free(info.forked_free_args); + if (!vec_str_any(&info.arguments, exec_find_null, &res) && res) + vec_str_push(&info.arguments, NULL); + res = false; + if (!vec_str_any(&info.environement, exec_find_null, &res) && res) + vec_str_push(&info.environement, NULL); + execve(info.binary_path, info.arguments.buffer, info.environement.buffer); + return (NO_ERROR); +} + +t_error exec_in_path(t_spawn_info *info, t_process *process, t_const_str path_raw, t_string *s) +{ + t_vec_str path; + t_usize idx; + + (void)(process); + if (str_split(path_raw + 5, ":", &path)) + return (string_free(*s), ERROR); + idx = 0; + while (idx < path.len) + { + string_clear(s); + me_printf_str(s, "%s/%s", path.buffer[idx++], info->binary_path); + if (access(s->buf, X_OK | R_OK) == 0) + return (vec_str_free(path), NO_ERROR); + } + return (vec_str_free(path), ERROR); +} + +t_error exec_find_binary(t_spawn_info *info, t_process *process) +{ + t_usize p_idx; + t_string s; + + (void)(process); + if (info->binary_path == NULL) + return (ERROR); + s = string_new(256); + if (exec_str_start_with(info->binary_path, "/") || str_find_chr(info->binary_path, '/') != NULL) + string_push(&s, info->binary_path); + else + { + if (vec_str_find(&info->environement, exec_find_path, &p_idx)) + return (string_free(s), ERROR); + if (exec_in_path(info, process, info->environement.buffer[p_idx], &s)) + return (ERROR); + } + if (access(s.buf, X_OK | R_OK) == 0) + { + mem_free(info->binary_path); + info->binary_path = s.buf; + return (NO_ERROR); + } + return (string_free(s), ERROR); +} + +static void exec_cleanup(t_spawn_info info, t_process *process, bool cleanup_process) +{ + if (cleanup_process && process->stdin.tag != INVALID) + close(process->stdin.vals.ro.fd); + if (cleanup_process && process->stdout.tag != INVALID) + close(process->stdout.vals.ro.fd); + if (cleanup_process && process->stderr.tag != INVALID) + close(process->stderr.vals.ro.fd); + close(info.stdin.vals.fd.value); + close(info.stdout.vals.fd.value); + close(info.stderr.vals.fd.value); + vec_str_free(info.arguments); + vec_str_free(info.environement); + mem_free(info.binary_path); +} + +t_error exec_spawn_process(t_spawn_info info, t_vec_ast *redirection, t_process *process) +{ + if (exec_handle_redirections(&info, process)) + return (exec_cleanup(info, process, true), ERROR); + if (exec_find_binary(&info, process)) + return (exec_cleanup(info, process, true), ERROR); + process->pid = fork(); + if (process->pid == 0) + (exec_spawn_process_exec(info, process), exit(1)); + else + { + exec_cleanup(info, process, false); + if (process->pid == -1) + return (ERROR); + } + return (NO_ERROR); +} diff --git a/exec/src/spawn_cmd/process_inner.c b/exec/src/spawn_cmd/process_inner.c new file mode 100644 index 00000000..75d8b24f --- /dev/null +++ b/exec/src/spawn_cmd/process_inner.c @@ -0,0 +1,19 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* process_inner.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/01/04 22:27:00 by maiboyer #+# #+# */ +/* Updated: 2024/07/29 19:05:38 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "exec/spawn_cmd/pipe.h" +#include "exec/spawn_cmd/process.h" +#include "me/types.h" + +t_error handle_redirections(t_spawn_info *info, t_process *process) +{ +} diff --git a/exec/src/spawn_cmd/process_iter_funcs.c b/exec/src/spawn_cmd/process_iter_funcs.c new file mode 100644 index 00000000..379c7d8a --- /dev/null +++ b/exec/src/spawn_cmd/process_iter_funcs.c @@ -0,0 +1,41 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* process_iter_funcs.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: maiboyer +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/01/04 22:25:44 by maiboyer #+# #+# */ +/* Updated: 2024/07/29 17:22:42 by maiboyer ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "me/types.h" +#include +#include + +bool exec_find_null(const t_str *s) +{ + return (s == NULL); +} + +bool exec_str_start_with(t_const_str s, t_const_str prefix) +{ + while (*prefix && *s) + { + if (*prefix++ != *s++) + return (false); + } + return (*prefix == '\0'); +} + +bool exec_find_path(const t_str *s) +{ + t_str ss; + + if (*s == NULL) + return (false); + ss = *s; + return (ss[0] == 'P' && ss[1] == 'A' && ss[2] == 'T' && ss[3] == 'H' && \ + ss[4] == '='); +}