So I have an assignment where I have to process n commands that are in pipe. These commands are Linux based. If my understanding is correct, I know I have to create a for loop that continuously forks() the child of the main process, and execute those children, which are then connected by pipes. Here's my code so far.
void main(void)
{
char **cmds[3];
char *c1[] = { "ls", "-l", "/etc", 0 };
char *c2[] = { "head", "-n", "10", 0 };
char *c3[] = { "tail", "-n", "5", 0 };
cmds[0] = (char **)c1;
cmds[1] = (char **)c2;
cmds[2] = (char **)c3;
int pid, status;
pid = fork();
if(pid == 0){//child proccess
int fd[2];
int infd;
int i;
for(i = 0; i < 2; i++){
pipe(fd);
int ppid;
ppid = fork();
if(ppid > 0){
dup2(fd[1], 1);
close(fd[0]);
//executes the nth command
execvp(*(cmds+i)[0], *(cmds+i));
}else if(ppid == 0){
dup2(fd[0], 0);
close(fd[1]);
//executes the n+1th command
execvp(*(cmds+i+1)[0], *(cmds+i+1));
}
}
}else if (pid > 0){//parents proccess
while((pid = wait(&status)) != -1);
}
}
As the program stands right now, I'm able to only pipe the first and second commands, but for some reason the 3rd command goes completely undetected. How would I fix this?
The following are the three processes you want to create:
stdin -> ls -> pipe1
pipe1 -> head -> pipe2
pipe2 -> tail -> stdout
You have at most one pipe created at time, but head
needs to communicate with two.
Base your loop around the creation of processes, not around the creation of pipes. That means you will need to carry pipe information from one pass to the other.
pid_t pids[ num_cmds ];
int next_stdin_fd = 0;
for (int i = 0; i < num_cmds; ++i ) {
int stdin_fd = next_stdin_fd;
int stdout_fd;
if ( i == num_programs - 1 ) {
next_stdin_fd = -1;
stdout_fd = 1;
} else {
int pipe_fds[2];
pipe( pipe_fds );
next_stdin_fd = pipe_fds[ 0 ];
stdout_fd = pipe_fds[ 1 ];
}
pids[ i ] = fork();
if ( pid == 0 ) {
if ( stdin_fd != 0 ) {
dup2( stdin_fd, 0 );
close( stdin_fd );
}
if ( stdout_fd != 1 ) {
dup2( stdout_fd, 1 );
close( stdout_fd );
}
if ( next_stdin_fd != -1 ) {
close( next_stdin_fd );
}
execvp( *cmds[i], cmds[i]+1 );
}
if ( stdout_fd != 1 ) {
close( stdout_fd );
}
}
for (int i = 0; i < num_cmds; ++i ) {
int status;
waitpid( pids[ i ], &status, 0 );
}
Error checking omitted for brevity.