MiniDevil As beautiful as a shell
exec_cmd.c
Go to the documentation of this file.
1 /* ************************************************************************** */
2 /* */
3 /* ::: :::::::: */
4 /* exec_cmd.c :+: :+: :+: */
5 /* +:+ +:+ +:+ */
6 /* By: baelgadi <baelgadi@student.42.fr> +#+ +:+ +#+ */
7 /* +#+#+#+#+#+ +#+ */
8 /* Created: 2025/12/13 23:16:35 by baelgadi #+# #+# */
9 /* Updated: 2026/03/04 08:39:11 by baelgadi ### ########.fr */
10 /* */
11 /* ************************************************************************** */
12 
13 #include <sys/stat.h>
14 #include <sys/wait.h>
15 #include <signal.h>
16 #include <stdio.h>
17 #include <errno.h>
18 #include "executor.h"
19 #include "libft.h"
20 #include "env.h"
21 #include "ast.h"
22 #include "signals.h"
23 #include "get_next_line.h"
24 
32 static void handle_exec_error(char *path)
33 {
34  struct stat buf;
35  char *msg;
36 
37  if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode))
38  msg = ": Is a directory\n";
39  else if (errno == ENOENT)
40  msg = ": No such file or directory\n";
41  else if (errno == ENOEXEC)
42  msg = ": Exec format error\n";
43  else
44  msg = ": Permission denied\n";
45  ft_putstr_fd("minishell: ", STDERR_FILENO);
46  ft_putstr_fd(path, STDERR_FILENO);
47  ft_putstr_fd(msg, STDERR_FILENO);
48 }
49 
61 static void child_execute(char *path, char **args, char **envp, t_shell *shell)
62 {
64  if (execve(path, args, envp) == -1)
65  {
66  handle_exec_error(path);
67  free(path);
68  ft_free_strarray(envp);
69  free(shell->current_input);
70  free_ast(shell->current_ast);
71  free_env_list(&shell->env);
72  get_next_line(-42);
73  exit(126);
74  }
75 }
76 
85 static int wait_for_child(pid_t pid)
86 {
87  int status;
88  int exit_code;
89 
90  exit_code = 0;
91  waitpid(pid, &status, 0);
92  if (WIFEXITED(status))
93  exit_code = WEXITSTATUS(status);
94  else if (WIFSIGNALED(status))
95  {
96  if (WTERMSIG(status) == SIGINT)
97  ft_putchar_fd('\n', STDERR_FILENO);
98  else if (WTERMSIG(status) == SIGQUIT)
99  ft_putstr_fd("Quit (core dumped)\n", STDERR_FILENO);
100  exit_code = 128 + WTERMSIG(status);
101  }
102  return (exit_code);
103 }
104 
116 static int prepare_exec(char **args, t_env *env, char **path, char ***envp)
117 {
118  if (ft_strncmp(args[0], ".", 2) == 0)
119  {
120  ft_putstr_fd("minishell: .: filename argument required\n",
121  STDERR_FILENO);
122  ft_putstr_fd(".: usage: . filename [arguments]\n", STDERR_FILENO);
123  return (2);
124  }
125  if (ft_strncmp(args[0], "..", 3) == 0)
126  return (exec_cmd_not_found(args[0]));
127  *path = find_cmd_path(args[0], env);
128  if (!*path)
129  return (exec_cmd_not_found(args[0]));
130  *envp = env_to_array(env);
131  if (!*envp)
132  {
133  free(*path);
134  return (1);
135  }
136  return (0);
137 }
138 
150 int exec_external(char **args, t_shell *shell)
151 {
152  char *path;
153  char **envp;
154  pid_t pid;
155  int status;
156 
157  if (!args || !args[0])
158  return (0);
159  status = prepare_exec(args, shell->env, &path, &envp);
160  if (status != 0)
161  return (status);
162  if (shell->is_child)
163  child_execute(path, args, envp, shell);
164  pid = fork();
165  if (pid == -1)
166  {
167  perror("minishell: fork");
168  return (free(path), ft_free_strarray(envp), 1);
169  }
170  if (pid == 0)
171  child_execute(path, args, envp, shell);
172  status = wait_for_child(pid);
173  free(path);
174  ft_free_strarray(envp);
175  return (status);
176 }
AST node creation and destruction prototypes.
void free_ast(t_ast *node)
Recursively free an entire AST tree.
Definition: ast_utils.c:46
Environment variable management prototypes.
char ** env_to_array(t_env *env)
Convert the env linked list to a NULL terminated string array.
void free_env_list(t_env **env_list)
Free all nodes in the env linked list.
Definition: env_utils.c:69
static void handle_exec_error(char *path)
Print an error for when execve fails.
Definition: exec_cmd.c:32
static void child_execute(char *path, char **args, char **envp, t_shell *shell)
Replace current process with the external command (execve)
Definition: exec_cmd.c:61
int exec_external(char **args, t_shell *shell)
Fork and execute an external command.
Definition: exec_cmd.c:150
static int wait_for_child(pid_t pid)
Wait for a child process and get the correct exit status.
Definition: exec_cmd.c:85
static int prepare_exec(char **args, t_env *env, char **path, char ***envp)
Resolve the command's path and build envp array before forking.
Definition: exec_cmd.c:116
int exec_cmd_not_found(char *cmd)
Print "command not found" to STDERR.
Definition: exec_utils.c:25
Executor prototypes for commands, pipes, redirections & heredocs.
char * find_cmd_path(char *cmd, t_env *env)
Resolve a command name into its full executable path.
Definition: path.c:115
void reset_child_signals(void)
Reset signals to default behavior for the child processes.
Definition: signals.c:66
Signal handler prototypes.
Environment variable (doubly linked list)
Definition: structs.h:87
Shell state.
Definition: structs.h:164
t_env * env
Environment linked list.
Definition: structs.h:165
int is_child
Child flag (to avoid leaks)
Definition: structs.h:173
char * current_input
Current input line.
Definition: structs.h:172
struct s_ast * current_ast
Currently executing AST.
Definition: structs.h:171