I have some issue in my program.
I have a school homework where I have to reproduce some features of bash The homework is almost done however I have an issue with built_in command and pipes indeed I have a broken pipe error whenever a built_in command is the last pipeline like such : ls | echo (this line will produce a broken pipe error) where as this one echo | ls will work just fine. after some research I found out what was the problem, I have this error because for built_in command (meaning that I don't use execve to call them) I don't fork them into a child process while the other command are forked, so my guess is that the built_command close the read_end of the pipe way too fast while ls is still writing into the pipe. I handled this error with forking a process too for the built_in commands. However I was wondering if they were a solution without forking the built_in commands as this would use unnecessary resources.
void execute_routine(t_data *data, t_cmd *cmd)
{
pid_t pid_ret;
if (data -> s_pipes && !ft_strcmp(cmd -> prev_stop, "|")
&& cmd -> prev_cmd -> p_close)
close_fd(data, "bash", &data -> s_pipes -> s_pipes[1]);
if (!built_in(data, cmd, 0))
{
pid_ret = fork();
if (pid_ret < 0)
print_err_and_exit(data, NULL, "bash", 1);
if (pid_ret == 0)
forking(cmd);
cmd -> pid = pid_ret;
}
handle_pipes(data, cmd);
}
Here above, is the function that will execute each command get by the help of readline, you can see that if the command is a built_in we won't fork it and it will be handled right into that function for the case of echo here is the function :
int echo(t_data *data, t_cmd *cmd)
{
int fd;
data -> status = 1;
if (open_check_files_built_in(cmd, cmd -> tab))
return (1);
fd = where_to_write(data, cmd);
if (ft_tab_len(cmd -> args) == 1)
{
if (write_to_fd(data, "\n", fd) < 0)
return (print_err_built_in("bash", 1));
data -> status = 0;
return (1);
}
if (write_args_(data, cmd, fd))
return (1);
if (cmd -> last_in && cmd -> last_in -> type == IN)
close_fd_built_in(&cmd -> last_in -> fd);
if (cmd -> last_out)
close_fd_built_in(&cmd -> last_out -> fd);
data -> status = 0;
return (1);
}
for echo I only look for out redirection and writing into the returned fd. When I am done with the function I the pipe in that function.
void handle_pipes(t_data *data, t_cmd *cmd)
{
if (data -> s_pipes && data -> prev_pipes == -1
&& !ft_strcmp(cmd -> prev_stop, "|"))
close_fd(data, "bash", &data -> s_pipes -> read_end -> s_pipes[0]);
close_fd(data, "bash error", &data -> prev_pipes);
if (data -> inited)
{
data -> prev_pipes = data -> pipes[0];
close_fd(data, "bash pipes close", &data -> pipes[1]);
}
data -> inited = 0;
}
After that I wait all of my process with the function below
int i;
i = -1;
while (cmds[++i])
{
if (cmds[i]-> pid && waitpid(
cmds[i]-> pid, &data -> status, 0) < 0 && errno != ECHILD)
print_err_and_exit(data, NULL, "Error with waitpid", 1);
}
Like I said earlier the only differences between built_in command and the others is that built_in commands are not forked and directly handled in the parent process while the others are forked and handled in the child process. Although I have the broken pipe error signal the pipeline still output the expected result, for example ls | echo bonjour would still output bonjour to STDOUT but the error SIGPIPE would be sent to waitpid by the process handling the ls command, while echo bonjour | ls will also work fine and return a status code of 0 and not 13.