Мне действительно нужна помощь, и любые предложения будут очень приветствоваться. Мы с приятелем написали мини-версию Shell, а я разобрал и выполнил части. Все работает правильно, за исключением некоторых случаев, которые, вероятно, скрывают какую-то логику, которую я не могу уловить, и я действительно застрял. В частности, при запуске cat | cat | ls
cmd вывод ls
в порядке, но поведение cat
не соответствует ожидаемому. Вместо ожидания стандартного ввода (без аргументов) неожиданно возвращается подсказка. Это, вероятно, означает, что есть проблема с трубами, которые не закрываются в нужном месте, но я не могу найти, где именно. Ниже вы найдете исполнительную часть. Если кто-нибудь, пожалуйста, может помочь с добротой и неконкурентным отношением, мы будем очень признательны. Вот репозиторий github для получения дополнительной информации 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);
}
Я пытался не создавать все каналы, необходимые внезапно, чтобы лучше контролировать закрытие в родительских и дочерних процессах, используя только канал для каждого цикла, но все еще не работающий
… подсказка внезапно возвращается. Это, вероятно, означает, что есть проблема с трубами, которые не закрываются в нужном месте …
Ваша оценка вероятности пошла не так. Ошибка в том, что оболочка не ждет всех команд в конвейере, потому что, хотя вы правильно пытаетесь дождаться каждой команды в цикле while (cmd)
в executing_commands
, для всего конвейера есть только одно место хранения data->child
, поэтому дочерний элемент PID перезаписывается следующим, и в конце оболочка может ждать только последней команды.
Конечно, решение состоит в том, чтобы хранить child
по cmd
, а не по data
.
Я думал обо всех возможных причинах почти неделю, но никогда не думал о том, что сохранение PID в данных вместо cmd вызывало бесконечную перезапись PID. Так много еще предстоит узнать, и я так благодарен вам за это объяснение. Я изменил код, и он работает отлично.