I'm trying to reproduce the behavior of bash pipes using pipe and dup2, and it works fine for one pipe, because the first and the last have just either input or output redirected, but when I add multiple in a row it doesn't work (when both input and output are redirected to the pipe), the inputs and outputs seem to mess up with each other, so do we need to sleep between each command? I saw while reading documentation that executables are run at the same time and that we shouldn't wait for the previous child process to end so I don't wait. Here's the wrong part of my code:
#include "shell.h"
static int pfd[2];
void ms_terminate(int ret) {
close(pfd[0]);
close(pfd[1]);
clean_exit(ret);
}
pid_t execute(const t_shcmd *cmd, char *const *envp, bool in, bool out) {
pid_t cpid = 0;
if (!ft_strcmp(cmd->av[0], "cd")) {
int fd_in = dup(0), fd_out = dup(1);
if (in) dup2(pfd[0], 0);
if (out) dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
builtin_cd(cmd->ac, cmd->av);
dup2(fd_in, 0);
dup2(fd_out, 1);
close(fd_in);
close(fd_out);
}
else if (!(cpid = fork())) {
if (in) dup2(pfd[0], 0);
if (out) dup2(pfd[1], 1);
close(pfd[0]);
close(pfd[1]);
execve(*cmd->av, cmd->av, envp);
clean_exit(EXIT_FAILURE);
}
if (cpid == -1)
ms_terminate(EXIT_FAILURE);
return cpid;
}
void execute_pipeline(const t_shcmd *cmd, char *const *envp) {
pid_t cpid;
if (!(cpid = fork())) {
execute(cmd, envp, false, true);
while ((cmd = cmd->pipe)->pipe)
execute(cmd, envp, true, true);
execute(cmd, envp, true, false);
ms_terminate(EXIT_SUCCESS);
}
if (cpid == -1) ms_terminate(EXIT_FAILURE);
while (wait(NULL) > 0);
}
void ms_execute(const t_shcmd *cmd, char *const *envp) {
pid_t cpid;
pipe(pfd);
while (cmd) {
if (cmd->pipe)
execute_pipeline(cmd, envp);
else {
cpid = execute(cmd, envp, false, false);
wait(NULL);
}
cmd = cmd->next;
}
close(pfd[0]);
close(pfd[1]);
}
the struct t_shcmd is basically a special chained list declared like this, and obtained by my parser (the problem doesn't come from the parser btw, it comes from the above code):
typedef struct s_shcmd t_shcmd;
struct s_shcmd {
t_shcmd *next, *pipe;
int ac;
char *av[];
};
CodePudding user response:
Think of a pipe like a real pipe.
If you want information from prog1 to go to prog2, you will need a pipe.
If you also want information from prog2 to go to prog3, you will need another pipe.
So prog1 | prog2 | prog3 requires two pipes.
Note: Make sure to close all the pipe ends that aren't needed. prog1 should only have one of the four pipe ends open, prog2 should only have two, and prog3 should only have the final one open.

