I really need help and any suggestions will be very welcomed. Me and a mate have coded a mini version of the Shell and I did parsing and executing parts. All is working properly except for some cases that probably are hiding some logic that I can't catch and I'm actually stuck. In particular when launching cat | cat | ls
cmd the ls
output is ok but the cat
behavior is not what expected. Instead of waiting for the stdin (not having any argument) the prompt is suddenly returned. That probably means that there's an issue with pipes not closing at the right place, but I'm not able to find where exactly. Here below you will find the executing part. If anyone please could help with kindness and a noncompetitive attitude will be very appreciated. Here is the github repo for any further details GitHub Repo
void executing_commands(t_minish *data)
{
t_cmd *cmd;
int process_status;
process_status = 0;
cmd = data->cmds;
if (!cmd->full_cmd)
return ;
creating_pipes(data);
while (cmd && cmd->full_cmd)
cmd = creating_child(&cmd, data);
closing_all_fd(data);
cmd = data->cmds;
while (cmd)
{
waitpid(data->child, &process_status, 0);
if (data->cmds && !check_parent_builtin(&cmd))
g_status = WEXITSTATUS(process_status);
cmd = cmd->next;
}
}
t_cmd *creating_child(t_cmd **cmd, t_minish *data)
{
int pid;
if (check_parent_builtin(cmd))
executing_builtin(data, cmd);
else
{
pid = fork();
if (ft_memcmp((*cmd)->full_cmd[0], "minishell", 10))
set_signals(EXEC);
data->child = pid;
if (pid == -1)
{
closing_all_fd(data);
error_manager(2, data, NULL);
}
else if (pid == 0)
child_process(data, cmd);
}
return ((*cmd)->next);
}
void child_process(t_minish *data, t_cmd **cmd)
{
switching_input_output(data, cmd);
closing_all_fd(data);
if (check_child_builtin(cmd))
executing_builtin(data, cmd);
else
launching_command(data, cmd);
}
void switching_input_output(t_minish *data, t_cmd **cmd)
{
if ((*cmd)->output > 1)
{
if (dup2((*cmd)->output, STDOUT_FILENO) < 0)
error_manager(6, data, cmd);
close((*cmd)->output);
}
if ((*cmd)->input)
{
if (dup2((*cmd)->input, STDIN_FILENO) < 0)
error_manager(6, data, cmd);
close((*cmd)->input);
}
if ((*cmd)->file_in)
{
if (dup2((*cmd)->file_in, STDIN_FILENO) < 0)
error_manager(6, data, cmd);
close((*cmd)->file_in);
}
if ((*cmd)->file_out)
{
if (dup2((*cmd)->file_out, STDOUT_FILENO) < 0)
error_manager(6, data, cmd);
close((*cmd)->file_out);
}
}
void launching_command(t_minish *data, t_cmd **cmd)
{
if (execve((*cmd)->full_path, (*cmd)->full_cmd, data->env_table) == -1)
error_manager(3, data, cmd);
}
void closing_all_fd(t_minish *data)
{
t_cmd *cmd;
cmd = data->cmds;
while (cmd)
{
if (cmd->input)
close(cmd->input);
if (cmd->output > 1)
close(cmd->output);
cmd = cmd->next;
}
}
void closing_fd_if_redirections(t_minish *data)
{
t_cmd *cmd;
cmd = data->cmds;
while (cmd)
{
if (cmd->file_in && cmd->input)
close(cmd->input);
cmd = cmd->next;
}
}
void creating_pipes(t_minish *data)
{
int fd[2];
t_cmd *cmd;
cmd = data->cmds;
while (cmd->next != NULL)
{
if (pipe(fd) == -1)
error_manager(1, data, NULL);
cmd->output = fd[1];
cmd->next->input = fd[0];
if (!cmd->next->next)
cmd->next->last = 1;
cmd = cmd->next;
}
closing_fd_if_redirections(data);
}
I tried not to create all the pipes needed all in a sudden in order to better control closing in parent and child processes with just a pipe for each loop but still not working
… the prompt is suddenly returned. That probably means that there's an issue with pipes not closing at the right place …
Your probability estimation went wrong. The error is that the shell does not wait for all the commands in the pipeline, because, though you rightly try to wait for each command in the while (cmd)
loop in executing_commands
, there is only one storage location data->child
for the whole pipeline, so a child PID is overwritten by the following, and at the end the shell can only wait for the last command.
Of course the remedy is to store child
per cmd
rather than per data
.