Merge branch 'feature/executor-gl' into solo

This commit is contained in:
2026-02-12 21:26:12 +01:00
30 changed files with 1633 additions and 353 deletions

View File

@@ -12,23 +12,53 @@
#include "builtins.h"
u_int8_t set_builtins(
t_minishell *minishell
) {
minishell->builtins
= ft_hashmap_new(4, ft_hashmap_hashstr, ft_hashmap_strcmp);
if (minishell->builtins == NULL)
static uint8_t register_builtin(
t_minishell *minishell,
const char *name,
t_builtin_func builtin
)
{
char *key;
key = ft_strdup(name);
if (key == NULL)
return (0);
ft_hashmap_put(minishell->builtins, ft_strdup("cd"), builtin_cd);
ft_hashmap_put(minishell->builtins, ft_strdup("echo"), builtin_echo);
ft_hashmap_put(minishell->builtins, ft_strdup("exit"), builtin_exit);
ft_hashmap_put(minishell->builtins, ft_strdup("pwd"), builtin_pwd);
ft_hashmap_put(minishell->builtins, key, builtin);
if (!ft_hashmap_contains_key(minishell->builtins, name))
{
free(key);
return (0);
}
return (1);
}
u_int8_t is_builtin(
uint8_t set_builtins(
t_minishell *minishell
) {
minishell->builtins
= ft_hashmap_new(7, ft_hashmap_hashstr, ft_hashmap_strcmp);
if (minishell->builtins == NULL)
return (0);
if (!register_builtin(minishell, "cd", builtin_cd)
|| !register_builtin(minishell, "echo", builtin_echo)
|| !register_builtin(minishell, "env", builtin_env)
|| !register_builtin(minishell, "exit", builtin_exit)
|| !register_builtin(minishell, "export", builtin_export)
|| !register_builtin(minishell, "pwd", builtin_pwd)
|| !register_builtin(minishell, "unset", builtin_unset))
{
ft_hashmap_clear_keys(&minishell->builtins);
return (0);
}
return (1);
}
uint8_t is_builtin(
const char *command_name,
t_minishell *minishell
) {
if (command_name == NULL || minishell == NULL
|| minishell->builtins == NULL)
return (0);
return (ft_hashmap_contains_key(minishell->builtins, command_name));
}

View File

@@ -12,43 +12,104 @@
#include "builtins.h"
static u_int8_t handle_error(t_command cmd, t_minishell *msh, char *path);
static uint8_t handle_error(void);
static void update_pwd_vars(t_minishell *msh, char *oldpwd);
static char *get_path_from_env(
t_minishell *msh,
const char *env_name,
const char *error,
uint8_t *status
);
static char *resolve_cd_path(
t_command cmd,
t_minishell *msh,
uint8_t *status
);
u_int8_t builtin_cd(
uint8_t builtin_cd(
t_command cmd,
t_minishell *msh
){
char *path;
char *oldpwd;
uint8_t status;
bool show_pwd;
if (cmd.argc > 2)
{
ft_eputendl("minishell: cd: too many arguments");
return (2);
}
else if (cmd.argc == 1)
path = get_env("HOME", msh);
else
path = cmd.argv[1];
path = resolve_cd_path(cmd, msh, &status);
if (status != EXIT_SUCCESS)
return (status);
show_pwd = (cmd.argc == 2 && ft_strcmp(cmd.argv[1], "-") == 0);
oldpwd = getcwd(NULL, 0);
if (chdir(path) == -1)
return (handle_error(cmd, msh, path));
{
free(oldpwd);
return (handle_error());
}
update_pwd_vars(msh, oldpwd);
if (show_pwd && get_env("PWD", msh) != NULL)
ft_putendl(get_env("PWD", msh));
free(oldpwd);
return (EXIT_SUCCESS);
}
static u_int8_t handle_error(
static uint8_t handle_error(void)
{
perror("minishell: cd");
return (EXIT_FAILURE);
}
static void update_pwd_vars(
t_minishell *msh,
char *oldpwd
){
char *newpwd;
if (oldpwd != NULL)
set_env("OLDPWD", oldpwd, msh);
newpwd = getcwd(NULL, 0);
if (newpwd != NULL)
{
set_env("PWD", newpwd, msh);
free(newpwd);
}
}
static char *resolve_cd_path(
t_command cmd,
t_minishell *msh,
char *path
uint8_t *status
){
u_int8_t exit_code;
(void)msh;
exit_code = 0;
if (access(path, F_OK) != -1)
// No such file or directory
exit_code = 1;
else if (access(path, X_OK) == -1)
// Permission denied
exit_code = 2;
perror(cmd.argv[0]);
return (exit_code);
if (cmd.argc > 2)
{
ft_eputendl("minishell: cd: too many arguments");
*status = EXIT_FAILURE;
return (NULL);
}
if (cmd.argc == 2 && ft_strcmp(cmd.argv[1], "-") == 0)
return (get_path_from_env(msh, "OLDPWD",
"minishell: cd: OLDPWD not set", status));
if (cmd.argc == 1)
return (get_path_from_env(msh, "HOME",
"minishell: cd: HOME not set", status));
*status = EXIT_SUCCESS;
return (cmd.argv[1]);
}
static char *get_path_from_env(
t_minishell *msh,
const char *env_name,
const char *error,
uint8_t *status
){
char *path;
path = get_env(env_name, msh);
if (path == NULL)
{
ft_eputendl((char *)error);
*status = EXIT_FAILURE;
return (NULL);
}
*status = EXIT_SUCCESS;
return (path);
}

View File

@@ -13,7 +13,7 @@
#include "builtins.h"
#include "echo_def.h"
u_int8_t builtin_echo(
uint8_t builtin_echo(
t_command cmd,
t_minishell *msh
){

View File

@@ -13,7 +13,7 @@
#include "echo_def.h"
static void assign_flags(t_args *args, t_command cmd, size_t *i);
static u_int8_t is_valid_flag(t_args *args, char *flag);
static uint8_t is_valid_flag(t_args *args, char *flag);
static void assign_default_flags(
t_args *args
@@ -51,7 +51,7 @@ static void assign_flags(
}
}
static u_int8_t is_valid_flag(
static uint8_t is_valid_flag(
t_args *args,
char *flag
){

58
src/builtins/env/env.c vendored Normal file
View File

@@ -0,0 +1,58 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* env.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/09 22:05:00 by codex #+# #+# */
/* Updated: 2026/02/09 22:05:00 by codex ### ########.fr */
/* */
/* ************************************************************************** */
#include "builtins.h"
static void print_entry(t_map_entry *entry);
static void print_env(t_minishell *msh);
uint8_t builtin_env(
t_command cmd,
t_minishell *msh
)
{
if (cmd.argc > 1)
{
ft_eputendl("minishell: env: too many arguments");
return (EXIT_FAILURE);
}
print_env(msh);
return (EXIT_SUCCESS);
}
static void print_entry(
t_map_entry *entry
)
{
ft_putstr((char *)entry->key);
ft_putchar('=');
if (entry->value != NULL)
ft_putstr((char *)entry->value);
ft_putchar('\n');
}
static void print_env(
t_minishell *msh
)
{
t_list *entries;
t_list *current;
entries = ft_hashmap_entries(msh->variables.environment);
current = entries;
while (current != NULL)
{
print_entry((t_map_entry *)current->content);
current = current->next;
}
ft_lstclear_nodes(&entries);
}

View File

@@ -11,7 +11,19 @@
/* ************************************************************************** */
#include "builtins.h"
#include <stdint.h>
#include <limits.h>
static uint8_t get_uint8_from_num(const char *arg, uint8_t *status);
static uint8_t has_overflow(
uint64_t n,
char digit,
uint64_t limit
);
static uint8_t resolve_exit_status(
t_command cmd,
t_minishell *msh,
uint8_t *exit_status
);
uint8_t builtin_exit(
t_command cmd,
@@ -19,28 +31,78 @@ uint8_t builtin_exit(
)
{
uint8_t exit_status;
ft_eputendl("exit");
if (cmd.argc == 1)
exit_status = msh->exit_status;
else if (!ft_strisnum(cmd.argv[1]))
{
ft_eprintf(
"minishell: exit: %s: numeric argument required\n",
cmd.argv[1]);
return (2);
}
else if (cmd.argc > 2)
{
ft_eputendl("exit: too many arguments");
return (2);
}
else
exit_status = (uint8_t)ft_atol(cmd.argv[1]);
printf("builtin_exit: exit_status=%d\n", exit_status); // Debug print
msh->exit = 1;
if (isatty(STDIN_FILENO))
ft_eputendl("exit");
if (!resolve_exit_status(cmd, msh, &exit_status))
return (msh->exit_status);
msh->exit = true;
msh->exit_status = exit_status;
return (exit_status);
}
static uint8_t resolve_exit_status(
t_command cmd,
t_minishell *msh,
uint8_t *exit_status
){
if (cmd.argc == 1)
*exit_status = msh->exit_status;
else if (!get_uint8_from_num(cmd.argv[1], exit_status))
{
ft_eprintf("minishell: exit: %s: numeric argument required\n",
cmd.argv[1]);
msh->exit = true;
msh->exit_status = 2;
return (0);
}
else if (cmd.argc > 2)
{
ft_eputendl("minishell: exit: too many arguments");
msh->exit_status = EXIT_FAILURE;
return (0);
}
return (1);
}
static uint8_t get_uint8_from_num(
const char *arg,
uint8_t *status
){
uint64_t n;
uint64_t limit;
int sign;
if (arg == NULL || *arg == '\0')
return (0);
n = 0;
sign = 1;
if (*arg == '+' || *arg == '-')
if (*arg++ == '-')
sign = -1;
if (*arg == '\0')
return (0);
limit = LONG_MAX;
if (sign == -1)
limit = (uint64_t)LONG_MAX + 1;
while (*arg != '\0')
{
if (!ft_isdigit(*arg) || has_overflow(n, *arg, limit))
return (0);
n = (n * 10) + (*arg++ - '0');
}
*status = (uint8_t)(n * sign);
return (1);
}
static uint8_t has_overflow(
uint64_t n,
char digit,
uint64_t limit
){
if (n > (limit / 10))
return (1);
if (n == (limit / 10) && (uint64_t)(digit - '0') > (limit % 10))
return (1);
return (0);
}

View File

@@ -0,0 +1,79 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* export.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/09 22:05:00 by codex #+# #+# */
/* Updated: 2026/02/09 22:05:00 by codex ### ########.fr */
/* */
/* ************************************************************************** */
#include "builtins.h"
static uint8_t is_valid_identifier(const char *arg, size_t name_len);
static uint8_t export_one(char *arg, t_minishell *msh);
uint8_t builtin_export(
t_command cmd,
t_minishell *msh
)
{
uint8_t status;
size_t i;
if (cmd.argc == 1)
return (builtin_env(cmd, msh));
status = EXIT_SUCCESS;
i = 0;
while (cmd.argv[++i] != NULL)
if (export_one(cmd.argv[i], msh) != EXIT_SUCCESS)
status = EXIT_FAILURE;
return (status);
}
static uint8_t is_valid_identifier(
const char *arg,
size_t name_len
)
{
size_t i;
if (name_len == 0 || arg == NULL)
return (0);
if (!ft_isalpha(arg[0]) && arg[0] != '_')
return (0);
i = 0;
while (++i < name_len)
if (!ft_isalnum(arg[i]) && arg[i] != '_')
return (0);
return (1);
}
static uint8_t export_one(
char *arg,
t_minishell *msh
)
{
char *eq_pos;
char *name;
size_t name_len;
eq_pos = ft_strchr(arg, '=');
name_len = ft_strlen(arg);
if (eq_pos != NULL)
name_len = (size_t)(eq_pos - arg);
if (!is_valid_identifier(arg, name_len))
return (ft_eprintf("minishell: export: `%s': not a valid identifier\n",
arg), EXIT_FAILURE);
name = ft_substr(arg, 0, name_len);
if (name == NULL)
return (EXIT_FAILURE);
if (eq_pos != NULL)
set_env(name, eq_pos + 1, msh);
else
set_env(name, "", msh);
free(name);
return (EXIT_SUCCESS);
}

View File

@@ -12,15 +12,21 @@
#include "builtins.h"
u_int8_t builtin_pwd(
uint8_t builtin_pwd(
t_command cmd,
t_minishell *msh
){
char cwd[PATH_MAX];
char *cwd;
(void)cmd;
(void)msh;
if (getcwd(cwd, PATH_MAX) != NULL)
ft_putendl(cwd);
cwd = getcwd(NULL, 0);
if (cwd == NULL)
{
perror("minishell: pwd");
return (EXIT_FAILURE);
}
ft_putendl(cwd);
free(cwd);
return (EXIT_SUCCESS);
}

View File

@@ -0,0 +1,61 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* unset.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/09 22:05:00 by codex #+# #+# */
/* Updated: 2026/02/09 22:05:00 by codex ### ########.fr */
/* */
/* ************************************************************************** */
#include "builtins.h"
static uint8_t is_valid_identifier(const char *arg);
static uint8_t unset_one(char *arg, t_minishell *msh);
uint8_t builtin_unset(
t_command cmd,
t_minishell *msh
)
{
uint8_t status;
size_t i;
status = EXIT_SUCCESS;
i = 0;
while (cmd.argv[++i] != NULL)
if (unset_one(cmd.argv[i], msh) != EXIT_SUCCESS)
status = EXIT_FAILURE;
return (status);
}
static uint8_t is_valid_identifier(
const char *arg
)
{
size_t i;
if (arg == NULL || *arg == '\0')
return (0);
if (!ft_isalpha(arg[0]) && arg[0] != '_')
return (0);
i = 0;
while (arg[++i] != '\0')
if (!ft_isalnum(arg[i]) && arg[i] != '_')
return (0);
return (1);
}
static uint8_t unset_one(
char *arg,
t_minishell *msh
)
{
if (!is_valid_identifier(arg))
return (ft_eprintf("minishell: unset: `%s': not a valid identifier\n",
arg), EXIT_FAILURE);
unset_env(arg, msh);
return (EXIT_SUCCESS);
}

View File

@@ -0,0 +1,86 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* command_exec.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "executor.h"
#include "builtins.h"
#include <errno.h>
static uint8_t resolve_execve_status(void)
{
if (errno == ENOENT)
return (127);
if (errno == EACCES || errno == ENOEXEC || errno == EISDIR)
return (126);
return (EXIT_FAILURE);
}
static uint8_t execute_builtin(
const t_command *command,
t_minishell *minishell
)
{
const t_builtin_func builtin
= ft_hashmap_get(minishell->builtins, command->argv[0]);
return (builtin(*command, minishell));
}
static void handle_execve_error(
const t_command *command,
char **envp
)
{
uint8_t exit_status;
exit_status = resolve_execve_status();
free_envp(envp);
perror(command->path);
exit(exit_status);
}
static void execute_external_command(
const t_command *command,
t_minishell *minishell
)
{
char **envp;
envp = get_envp(minishell);
if (envp == NULL)
{
perror("get_envp");
exit(EXIT_FAILURE);
}
execve(command->path, command->argv, envp);
handle_execve_error(command, envp);
}
uint8_t executor_execute_command(
t_command *command,
t_minishell *minishell
)
{
if (command == NULL || command->argv == NULL || command->argv[0] == NULL)
return (EXIT_SUCCESS);
if (executor_is_builtin_command(command, minishell))
return (execute_builtin(command, minishell));
if (command->path != NULL)
free(command->path);
command->path = executor_resolve_command_path(command, minishell);
if (command->path == NULL)
{
ft_eprintf("minishell: %s: command not found\n", command->argv[0]);
return (127);
}
execute_external_command(command, minishell);
return (EXIT_FAILURE);
}

View File

@@ -6,198 +6,72 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/08 19:10:47 by sede-san #+# #+# */
/* Updated: 2026/02/08 21:32:03 by sede-san ### ########.fr */
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "executor.h"
#include "builtins.h"
static inline uint8_t execute_builtin(
const t_command *command,
static void init_exec_state(
t_exec_state *state,
t_list *command_list
)
{
state->exit_status = EXIT_SUCCESS;
state->pipeline.prev_read_fd = -1;
state->current_command = command_list;
state->last_child_pid = -1;
}
static bool fork_current_command(
t_exec_state *state,
t_minishell *minishell
)
{
const t_builtin_func builtin
= ft_hashmap_get(minishell->builtins, command->path);
pid_t pid;
return (builtin(*command, minishell));
}
static void handle_execve_error(
const t_command *command,
char **envp
)
{
free_envp(envp);
perror(command->path);
exit(EXIT_FAILURE);
}
static void execute_external_command(
const t_command *command,
t_minishell *minishell
)
{
char **envp;
envp = get_envp(minishell);
if (envp == NULL)
{
perror("get_envp");
exit(EXIT_FAILURE);
}
execve(command->path, command->argv, envp);
handle_execve_error(command, envp);
}
static uint8_t execute_command(
const t_command *command,
t_minishell *minishell
)
{
if (is_builtin(command->path, minishell))
return (execute_builtin(command, minishell));
else
{
execute_external_command(command, minishell);
return (EXIT_FAILURE); //! should never reach here
}
}
static void cmdfree_argv(
char **argv
)
{
size_t i;
if (argv == NULL)
return ;
i = 0;
while (argv[i] != NULL)
{
free(argv[i]);
i++;
}
free(argv);
}
static void cmdfree(
t_command *command
)
{
if (command == NULL)
return ;
cmdfree_argv(command->argv);
free(command->path);
free(command);
}
static int create_pipe_if_needed(
t_list *current_command,
t_pipeline *pipeline
)
{
if (!current_command->next)
return (0);
if (pipe(pipeline->pipefd) == PIPE_ERROR)
return (perror("pipe"), PIPE_ERROR);
return (0);
}
static bool is_fork_required(
t_list *current_command,
t_minishell *minishell
) {
const t_command *command = current_command->content;
return (current_command->next != NULL
|| !is_builtin(command->path, minishell));
}
static pid_t fork_process(
t_list *current_command,
t_minishell *minishell
)
{
pid_t pid;
pid = 0;
if (is_fork_required(current_command, minishell))
pid = fork();
pid = fork();
if (pid == FORK_ERROR)
perror("fork");
return (pid);
return (perror("fork"), state->exit_status = EXIT_FAILURE, false);
if (pid == 0)
executor_child_process(state->current_command, &state->pipeline,
minishell);
state->last_child_pid = pid;
return (true);
}
static void setup_child_input(
t_pipeline *pipeline
)
{
if (pipeline->prev_read_fd != -1)
{
dup2(pipeline->prev_read_fd, STDIN_FILENO);
close(pipeline->prev_read_fd);
}
}
static void setup_child_output(
t_list *current_command,
t_pipeline *pipeline
)
{
if (current_command->next)
{
dup2(pipeline->pipefd[WRITE_PIPE], STDOUT_FILENO);
close(pipeline->pipefd[READ_PIPE]);
close(pipeline->pipefd[WRITE_PIPE]);
}
}
static void child_process(
t_list *current_command,
t_pipeline *pipeline,
static bool run_current_command(
t_exec_state *state,
t_minishell *minishell
)
{
uint8_t exit_status;
const t_command *command = current_command->content;
bool should_fork;
t_command *command;
int saved_stdin;
int saved_stdout;
setup_child_input(pipeline);
setup_child_output(current_command, pipeline);
exit_status = execute_command(command, minishell);
if (is_fork_required(current_command, minishell))
exit(exit_status);
}
static void parent_cleanup(
t_list *current_command,
t_pipeline *pipeline
)
{
if (pipeline->prev_read_fd != -1)
close(pipeline->prev_read_fd);
if (current_command->next)
if (executor_create_pipe_if_needed(state->current_command,
&state->pipeline) == PIPE_ERROR)
return (state->exit_status = EXIT_FAILURE, false);
should_fork = executor_is_fork_required(state->current_command,
&state->pipeline, minishell);
if (should_fork)
{
close(pipeline->pipefd[WRITE_PIPE]);
pipeline->prev_read_fd = pipeline->pipefd[READ_PIPE];
if (!fork_current_command(state, minishell))
return (false);
}
else
pipeline->prev_read_fd = -1;
}
static uint8_t wait_for_children(void)
{
uint8_t exit_status;
int status;
exit_status = EXIT_SUCCESS;
while (wait(&status) > 0)
{
if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);
command = state->current_command->content;
if (!executor_apply_redirections(command, &saved_stdin, &saved_stdout))
state->exit_status = EXIT_FAILURE;
else
state->exit_status = executor_execute_command(command, minishell);
executor_restore_redirections(saved_stdin, saved_stdout);
}
return (exit_status);
executor_parent_cleanup(state->current_command, &state->pipeline);
state->current_command = state->current_command->next;
return (true);
}
uint8_t execute(
@@ -205,26 +79,17 @@ uint8_t execute(
t_minishell *minishell
)
{
uint8_t exit_status;
t_pipeline pipeline;
t_list *current_command;
pid_t pid;
t_exec_state state;
pipeline.prev_read_fd = -1;
current_command = command_list;
while (current_command)
init_exec_state(&state, command_list);
while (state.current_command)
{
if (create_pipe_if_needed(current_command, &pipeline) == PIPE_ERROR)
if (!run_current_command(&state, minishell))
break ;
pid = fork_process(current_command, minishell);
if (pid == FORK_ERROR)
break ;
if (pid == 0)
child_process(current_command, &pipeline, minishell);
parent_cleanup(current_command, &pipeline);
current_command = current_command->next;
}
exit_status = wait_for_children();
ft_lstclear(&command_list, (void (*)(void *))cmdfree);
return (exit_status);
if (state.last_child_pid > 0)
state.exit_status = executor_wait_for_children(state.last_child_pid);
minishell->exit_status = state.exit_status;
ft_lstclear(&command_list, (void (*)(void *))executor_cmdfree);
return (state.exit_status);
}

View File

@@ -0,0 +1,77 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* path_resolver.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "executor.h"
static bool is_path_explicit(
const char *command_name
)
{
return (command_name != NULL && ft_strchr(command_name, '/') != NULL);
}
static char *resolve_path_from_env(
const char *command_name,
t_minishell *minishell
)
{
char *command_path;
char **path_env;
char *path_value;
size_t i;
path_value = get_env("PATH", minishell);
if (path_value == NULL)
return (NULL);
path_env = ft_split(path_value, ':');
if (path_env == NULL)
return (NULL);
command_path = NULL;
i = -1;
while (!command_path && path_env[++i] != NULL)
{
command_path = ft_strnjoin(3, path_env[i], "/", command_name);
if (command_path != NULL && access(command_path, X_OK) != EXIT_SUCCESS)
{
free(command_path);
command_path = NULL;
}
}
ft_free_split(path_env);
return (command_path);
}
static char *resolve_explicit_path(
const char *command_name
)
{
if (access(command_name, F_OK) != EXIT_SUCCESS)
return (NULL);
if (access(command_name, X_OK) != EXIT_SUCCESS)
return (NULL);
return (ft_strdup(command_name));
}
char *executor_resolve_command_path(
const t_command *command,
t_minishell *minishell
)
{
const char *command_name;
if (command == NULL || command->argv == NULL || command->argv[0] == NULL)
return (NULL);
command_name = command->argv[0];
if (is_path_explicit(command_name))
return (resolve_explicit_path(command_name));
return (resolve_path_from_env(command_name, minishell));
}

View File

@@ -0,0 +1,73 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* pipeline_helpers.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "executor.h"
#include "builtins.h"
int executor_create_pipe_if_needed(
t_list *current_command,
t_pipeline *pipeline
)
{
if (!current_command->next)
return (0);
if (pipe(pipeline->pipefd) == PIPE_ERROR)
return (perror("pipe"), PIPE_ERROR);
return (0);
}
bool executor_is_builtin_command(
const t_command *command,
t_minishell *minishell
)
{
if (command == NULL || command->argv == NULL || command->argv[0] == NULL)
return (false);
return (is_builtin(command->argv[0], minishell));
}
bool executor_is_fork_required(
t_list *current_command,
const t_pipeline *pipeline,
t_minishell *minishell
)
{
const t_command *command;
command = current_command->content;
return (pipeline->prev_read_fd != -1 || current_command->next != NULL
|| !executor_is_builtin_command(command, minishell));
}
void executor_setup_child_input(
t_pipeline *pipeline
)
{
if (pipeline->prev_read_fd != -1)
{
dup2(pipeline->prev_read_fd, STDIN_FILENO);
close(pipeline->prev_read_fd);
}
}
void executor_setup_child_output(
t_list *current_command,
t_pipeline *pipeline
)
{
if (current_command->next)
{
dup2(pipeline->pipefd[WRITE_PIPE], STDOUT_FILENO);
close(pipeline->pipefd[READ_PIPE]);
close(pipeline->pipefd[WRITE_PIPE]);
}
}

View File

@@ -0,0 +1,112 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* process_helpers.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/11 00:00:00 by sede-san #+# #+# */
/* Updated: 2026/02/11 00:00:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "executor.h"
void executor_child_process(
t_list *current_command,
t_pipeline *pipeline,
t_minishell *minishell
)
{
uint8_t exit_status;
t_command *command;
command = current_command->content;
executor_setup_child_input(pipeline);
executor_setup_child_output(current_command, pipeline);
if (!executor_apply_redirections(command, NULL, NULL))
exit(EXIT_FAILURE);
exit_status = executor_execute_command(command, minishell);
exit(exit_status);
}
void executor_parent_cleanup(
t_list *current_command,
t_pipeline *pipeline
)
{
if (pipeline->prev_read_fd != -1)
close(pipeline->prev_read_fd);
if (current_command->next)
{
close(pipeline->pipefd[WRITE_PIPE]);
pipeline->prev_read_fd = pipeline->pipefd[READ_PIPE];
}
else
pipeline->prev_read_fd = -1;
}
uint8_t executor_wait_for_children(
pid_t last_child_pid
)
{
uint8_t exit_status;
int status;
pid_t pid;
exit_status = EXIT_SUCCESS;
pid = wait(&status);
while (last_child_pid > 0 && pid > 0)
{
if (pid == last_child_pid)
{
if (WIFEXITED(status))
exit_status = WEXITSTATUS(status);
else if (WIFSIGNALED(status))
exit_status = 128 + WTERMSIG(status);
}
pid = wait(&status);
}
return (exit_status);
}
static void cmdfree_argv(
char **argv
)
{
size_t i;
if (argv == NULL)
return ;
i = 0;
while (argv[i] != NULL)
{
free(argv[i]);
i++;
}
free(argv);
}
static void cmdfree_redirection(
t_redirection *redirection
)
{
if (redirection == NULL)
return ;
free(redirection->target);
free(redirection);
}
void executor_cmdfree(
t_command *command
)
{
if (command == NULL)
return ;
cmdfree_argv(command->argv);
free(command->path);
ft_lstclear(&command->redirections,
(void (*)(void *))cmdfree_redirection);
ft_lstclear(&command->heredocs, (void (*)(void *))cmdfree_redirection);
free(command);
}

111
src/executor/redirections.c Normal file
View File

@@ -0,0 +1,111 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* redirections.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/12 00:00:00 by sede-san #+# #+# */
/* Updated: 2026/02/12 00:00:00 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
#include "executor.h"
#include <errno.h>
static int open_redirection_target(
const t_redirection *redirection
)
{
if (redirection->type == TOKEN_REDIRECT_IN)
return (open(redirection->target, O_RDONLY));
if (redirection->type == TOKEN_REDIRECT_OUT)
return (open(redirection->target, O_WRONLY | O_CREAT | O_TRUNC, 0644));
if (redirection->type == TOKEN_APPEND)
return (open(redirection->target, O_WRONLY | O_CREAT | O_APPEND, 0644));
errno = EINVAL;
return (-1);
}
static bool backup_stream_if_needed(
const t_redirection *redirection,
int *saved_stdin,
int *saved_stdout
)
{
if (redirection->type == TOKEN_REDIRECT_IN && saved_stdin != NULL
&& *saved_stdin == -1)
{
*saved_stdin = dup(STDIN_FILENO);
if (*saved_stdin == -1)
return (perror("dup"), false);
}
if ((redirection->type == TOKEN_REDIRECT_OUT
|| redirection->type == TOKEN_APPEND) && saved_stdout != NULL
&& *saved_stdout == -1)
{
*saved_stdout = dup(STDOUT_FILENO);
if (*saved_stdout == -1)
return (perror("dup"), false);
}
return (true);
}
bool executor_apply_redirections(
const t_command *command,
int *saved_stdin,
int *saved_stdout
)
{
t_list *node;
t_redirection *redirection;
int fd;
if (saved_stdin != NULL)
*saved_stdin = -1;
if (saved_stdout != NULL)
*saved_stdout = -1;
if (command == NULL || command->redirections == NULL)
return (true);
node = command->redirections;
while (node != NULL)
{
redirection = (t_redirection *)node->content;
if (redirection == NULL || redirection->target == NULL)
return (false);
if (!backup_stream_if_needed(redirection, saved_stdin, saved_stdout))
return (false);
fd = open_redirection_target(redirection);
if (fd == -1)
return (perror(redirection->target), false);
if (redirection->type == TOKEN_REDIRECT_IN
&& dup2(fd, STDIN_FILENO) == -1)
return (close(fd), perror("dup2"), false);
if ((redirection->type == TOKEN_REDIRECT_OUT
|| redirection->type == TOKEN_APPEND)
&& dup2(fd, STDOUT_FILENO) == -1)
return (close(fd), perror("dup2"), false);
close(fd);
node = node->next;
}
return (true);
}
void executor_restore_redirections(
int saved_stdin,
int saved_stdout
)
{
if (saved_stdin != -1)
{
if (dup2(saved_stdin, STDIN_FILENO) == -1)
perror("dup2");
close(saved_stdin);
}
if (saved_stdout != -1)
{
if (dup2(saved_stdout, STDOUT_FILENO) == -1)
perror("dup2");
close(saved_stdout);
}
}

View File

@@ -46,7 +46,7 @@ void minishell_run(
{
add_history(line);
commands = parse(line, minishell);
execute(commands, minishell);
minishell->exit_status = execute(commands, minishell);
}
free(line);
}

View File

@@ -6,7 +6,7 @@
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/10/22 18:37:38 by sede-san #+# #+# */
/* Updated: 2026/02/12 20:55:49 by sede-san ### ########.fr */
/* Updated: 2026/02/12 21:25:39 by sede-san ### ########.fr */
/* */
/* ************************************************************************** */
@@ -488,57 +488,3 @@ t_list *ft_lstfind(
}
return (NULL);
}
// void print_command_info(
// t_command *command
// )
// {
// printf("Command:\n");
// printf(" argc: %d\n", command->argc);
// printf(" argv: [");
// for (int i = 0; i < command->argc; i++)
// {
// printf("%s", command->argv[i]);
// if (i < command->argc - 1)
// printf(", ");
// }
// printf("]\n");
// printf(" path: %s\n", command->path);
// printf(" redirections:\n");
// t_list *redirection_node = command->redirections;
// while (redirection_node != NULL)
// {
// t_redirection *redirection = (t_redirection *)redirection_node->content;
// printf(" type: %d, target: %s\n", redirection->type, redirection->target);
// redirection_node = redirection_node->next;
// }
// printf(" heredocs:\n");
// t_list *heredoc_node = command->heredocs;
// while (heredoc_node != NULL)
// {
// t_redirection *heredoc = (t_redirection *)heredoc_node->content;
// printf(" type: %d, target: %s\n", heredoc->type, heredoc->target);
// heredoc_node = heredoc_node->next;
// }
// }
// int main(int argc, char const *argv[], char **envp)
// {
// t_minishell minishell;
// t_list *commands;
// char *line;
// if (argc != 2)
// return (EXIT_FAILURE);
// minishell_init(&minishell, envp);
// line = ft_strdup(argv[1]);
// commands = parse(line, NULL);
// ft_lstiter(commands, (void (*)(void *))print_command_info);
// if (line != NULL)
// free(line);
// if (commands != NULL)
// ft_lstclear(&commands, (void (*)(void *))command_clear);
// return 0;
// }

View File

@@ -32,26 +32,37 @@ void set_envp(
char **envp,
t_minishell *msh
) {
char **splitted_env;
char *equal_sign;
char *key;
char *value;
if (msh == NULL || envp == NULL)
return ;
msh->variables.environment
= ft_hashmap_new(32, ft_hashmap_hashstr, ft_hashmap_strcmp);
if (msh == NULL)
{
ft_hashmap_clear(&msh->variables.environment, free);
if (msh->variables.environment == NULL)
return ;
}
while (*envp != NULL)
{
splitted_env = ft_split(*envp, '=');
if (splitted_env == NULL)
equal_sign = ft_strchr(*envp, '=');
if (equal_sign == NULL)
{
key = ft_strdup(*envp);
value = ft_strdup("");
}
else
{
key = ft_substr(*envp, 0, equal_sign - *envp);
value = ft_strdup(equal_sign + 1);
}
if (key == NULL || value == NULL)
{
free(key);
free(value);
ft_hashmap_clear(&msh->variables.environment, free);
return ;
}
ft_hashmap_put(msh->variables.environment,
ft_strdup(splitted_env[0]), ft_strdup(splitted_env[1]));
ft_free_split(splitted_env);
ft_hashmap_put(msh->variables.environment, key, value);
envp++;
}
}
@@ -118,7 +129,9 @@ char **get_envp(
size_t i;
env_list = ft_hashmap_entries(msh->variables.environment);
envp = (char **)malloc((msh->variables.environment->size + 1) * sizeof(char *));
envp = (char **)malloc(
(msh->variables.environment->size + 1) * sizeof(char *)
);
if (envp != NULL)
{
i = 0;

View File

@@ -0,0 +1,41 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* environment_unset.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: sede-san <sede-san@student.42madrid.com +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/02/09 22:16:00 by codex #+# #+# */
/* Updated: 2026/02/09 22:16:00 by codex ### ########.fr */
/* */
/* ************************************************************************** */
#include "minishell.h"
#include "core.h"
void unset_env(
const char *env_name,
t_minishell *msh
){
t_hashmap *new_env;
t_list *entries;
t_list *current;
t_map_entry *entry;
new_env = ft_hashmap_new(32, ft_hashmap_hashstr, ft_hashmap_strcmp);
if (new_env == NULL)
return ;
entries = ft_hashmap_entries(msh->variables.environment);
current = entries;
while (current != NULL)
{
entry = current->content;
if (ft_strcmp(entry->key, env_name) != 0)
ft_hashmap_put(new_env,
ft_strdup(entry->key), ft_strdup(entry->value));
current = current->next;
}
ft_lstclear_nodes(&entries);
ft_hashmap_clear(&msh->variables.environment, free);
msh->variables.environment = new_env;
}