Parallel pipes not closing in C? - c

I'm trying to pipe in C in parallel but for some reason it's not closing... it's just waiting.... Not sure if I'm describing this well cuz i'm new at this, but here's the code
... some code up here
if(child_pid == 0) {
if(p0 >=0 && p1 == -1) {
dup2(p0, STDIN_FILENO);
close(p0);
close(p1);
}
else if (p0 == -1 && p1 >= 0) {
dup2(p1, STDOUT_FILENO);
close(p0);
close(p1);
}
else if (p0 >= 0 && p1 >=0) {
dup2(p0, STDIN_FILENO);
dup2(p1, STDOUT_FILENO);
close(p0);
close(p1);
}
if (input)
iofunc(input, 0);
if (output)
iofunc(output, 1);
if (sub){
command_exec (SUBSHELL_COMMAND, sub, -1, -1, -1);
exit(0);
}
else {
execvp(w[0], w);
exit(0);
}
}
else {
if (waitpid (-1, &child_status, 0) != child_pid)
child_status =-1;
close(p0);
close(p1);
return WEXITSTATUS(child_status);
}
... some code down here
when p0 == -1 && p1 >= 0, the process exits/returns, but for some reason, when p0 >= 0 && p1 == -1, the process just hangs and the pipe doesn't close. I ran a command ls | cat using two parallel child processes with ls writing to p1 and the cat reading from p0. The output was correct, but the pipe didn't close and cat never exited. What is going on?
#William I tried the following in my parent else block, but it didn't work
close(p0);
close(p1);
if (waitpid (-1, &child_status, 0) != child_pid)
child_status =-1;
#William here is the code that calls a function that calls the above code
int i = 0;
int num = 2;
int status;
pid_t pid;
pid_t pids[num];
int fd[2];
int p = pipe(fd);
int a;
int b;
//printf("pipe0:%d\n", fd[0]);
//printf("pipe1:%d\n", fd[1]);
for (i = 0; i < num; i++) {
if ((pids[i] = fork()) < 0) {
error(1,0, "child not forked");
} else if (pids[i] == 0) {
if (i == 0){
b = command_exec (c->type,
c->u.command[1],
0, f[0], p1);
}
else if (i == 1){
a = command_exec (c->type,
c->u.command[0],
1, p0, fd[1]);
}
exit(a && b);
}
}
while (num > 0) {
pid = wait(&status);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
num--;
}
The printf only prints the child process that finishes ls but not cat

Most likely, the parent is holding open the other side of the pipe. The ls has an open file descriptor on the write side of the pipe into cat, but so does the parent. cat will not exit until all the write side file descriptors are closed. Probably, you just need to reverse your code and close the pipes before you call waitpid instead of after.

Related

Piping implementation stuck on second command

int main() {
char *cmd1[2] = { "ls", NULL };
char *cmd2[3] = { "grep", "a", NULL };
char *cmd3[3] = { "wc", "-l", NULL };
char *cmd4[5] = { "cat", NULL };
char *cmd5[5] = { "cat", NULL };
int pipe_count = 2;
int pid1, pid2, pid3, pid4, pid5;
int pfd1[2];
int pfd2[2];
pipe(pfd1);
pipe(pfd2);
if ((pid1 = fork()) == 0) {
close(pfd2[0]);
close(pfd2[1]);
close(pfd1[0]);
dup2(pfd1[1], 1);
if (execvp(cmd1[0], cmd1) == -1) {
exit(-1);
}
} else if (pid1 > 0) {
waitpid(pid1, NULL, 0);
}
if ((pid2 = fork()) == 0) {
if (pipe_count >= 2) {
close(pfd1[1]);
close(pfd2[0]);
dup2(pfd1[0], 0);
dup2(pfd2[1], 1);
} else {
close(pfd1[1]);
close(pfd2[0]);
close(pfd2[1]);
dup2(pfd1[0], 0);
}
if (execvp(cmd2[0], cmd2) == -1) {
exit(-1);
}
if (pipe_count == 1) {
printf("\n");
return 0;
}
} else if (pid2 > 0) {
waitpid(pid2, NULL, 0);
}
if (pipe_count >= 2) {
if ((pid3 = fork()) == 0) {
if (pipe_count >= 3) {
close(pfd1[0]);
close(pfd2[1]);
dup2(pfd2[0], 0);
dup2(pfd1[1], 1);
} else {
close(pfd1[0]);
close(pfd1[1]);
close(pfd2[1]);
dup2(pfd2[0], 0);
}
if (execvp(cmd3[0], cmd3) == -1) {
exit(-1);
}
if (pipe_count == 2) {
printf("\n");
}
} else if (pid3 > 0) {
waitpid(pid3, NULL, 0);
}
}
if (pipe_count >= 3) {
if ((pid4 = fork()) == 0) {
close(pfd1[1]);
close(pfd2[0]);
dup2(pfd1[0], 0);
if (pipe_count == 4)
dup2(pfd2[1], 1);
else
close(pfd2[1]);
if (execvp(cmd4[0], cmd4) == -1) {
exit(-1);
}
} else if (pid4 > 0) {
waitpid(pid4, NULL, 0);
}
}
if (pipe_count == 4) {
if ((pid5 = fork()) == 0) {
close(pfd1[0]);
close(pfd2[1]);
dup2(pfd2[0],0);
close(pfd1[1]);
if (execvp(cmd5[0], cmd5) == -1) {
exit(-1);
}
} else if (pid5 > 0) {
waitpid(pid5, NULL, 0);
}
}
return 0;
}
I'm trying to build a shell with piping command. When I input ls | grep a | wc -l for example, I realize that the program is stuck on grep a when I use ps f on the terminal. The shell is not responsive.
When I kill the child process for grep a, I'm again stuck on wc -l and have to kill it on the terminal again.
After killing the processes, no output is printed (My desired output is 2).
Any help would be appreciated.
As already diagnosed in the comments, there are many problems with the original code, including:
The most likely problem is that your parent process isn't closing the pipes before waiting for the child processes to die, so the child processes don't get EOF and don't terminate. (This was one of the problems, but far from the only problem.)
If you have N processes to run, you need N-1 pipes. You have only two pipes here; you've got a lot of work to do before you can make it work with just two pipes. The case of N=2 still has special cases: the first and last processes need to be treated a bit different from the way you treat processes 2..N-1.
You also need to run the processes in a pipeline concurrently. The controlling process should not wait for any of the children until the whole pipeline has been launched. This is because, for example, process P1 may generate so much data that it fills the pipe buffer connecting it to process P2, at which point it will block waiting for P2 to read some data. But if P2 hasn't been launched yet, P1 will never be unblocked, so the pipeline will make no progress. You need to rethink the waiting code as well as the piping code. You end up closing a lot of file descriptors.
You aren't closing enough file descriptors. Rule of thumb: If you dup2() one end of a pipe to standard input or standard output, close both of the original file descriptors from pipe() as soon as possible. In particular, that means before using any of the exec*() family of functions. The rule also applies with either dup() or fcntl() with F_DUPFD.
Note that there is no need to test the return value from the exec*() family of functions. If they succeed, they do not return; if they return, they failed. I think it is good practice, in most cases, to generate an error message before exiting after an exec*() call fails.
Putting those observations together leads to code like this:
/* SO 7412-0402 */
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stderr.h>
int main(void)
{
char *cmd1[2] = { "ls", NULL };
char *cmd2[3] = { "grep", "a", NULL };
char *cmd3[3] = { "wc", "-l", NULL };
char *cmd4[5] = { "cat", NULL };
char *cmd5[5] = { "cat", NULL };
int pid1, pid2, pid3, pid4, pid5;
int pfd1[2];
int pfd2[2];
int pfd3[2];
int pfd4[2];
err_setarg0("pipe61");
err_setlogopts(ERR_PID | ERR_MILLI);
err_remark("Parent process\n");
if (pipe(pfd1) != 0 ||
pipe(pfd2) != 0 ||
pipe(pfd3) != 0 ||
pipe(pfd4) != 0)
err_syserr("failed to create a pipe: ");
if ((pid1 = fork()) < 0)
err_syserr("failed to fork(): ");
if (pid1 == 0)
{
err_remark("Child process 1\n");
dup2(pfd1[1], 1);
close(pfd1[0]); close(pfd1[1]);
close(pfd2[0]); close(pfd2[1]);
close(pfd3[0]); close(pfd3[1]);
close(pfd4[0]); close(pfd4[1]);
execvp(cmd1[0], cmd1);
err_syserr("failed to execute '%s': ", cmd1[0]);
}
if ((pid2 = fork()) < 0)
err_syserr("failed to fork(): ");
else if (pid2 == 0)
{
err_remark("Child process 2\n");
dup2(pfd1[0], 0);
dup2(pfd2[1], 1);
close(pfd1[0]); close(pfd1[1]);
close(pfd2[0]); close(pfd2[1]);
close(pfd3[0]); close(pfd3[1]);
close(pfd4[0]); close(pfd4[1]);
execvp(cmd2[0], cmd2);
err_syserr("failed to execute '%s': ", cmd2[0]);
}
if ((pid3 = fork()) < 0)
err_syserr("failed to fork(): ");
else if (pid3 == 0)
{
err_remark("Child process 3\n");
dup2(pfd2[0], 0);
dup2(pfd3[1], 1);
close(pfd1[0]); close(pfd1[1]);
close(pfd2[0]); close(pfd2[1]);
close(pfd3[0]); close(pfd3[1]);
close(pfd4[0]); close(pfd4[1]);
execvp(cmd3[0], cmd3);
err_syserr("failed to execute '%s': ", cmd3[0]);
}
if ((pid4 = fork()) < 0)
err_syserr("failed to fork(): ");
else if (pid4 == 0)
{
err_remark("Child process 4\n");
dup2(pfd3[0], 0);
dup2(pfd4[1], 1);
close(pfd1[0]); close(pfd1[1]);
close(pfd2[0]); close(pfd2[1]);
close(pfd3[0]); close(pfd3[1]);
close(pfd4[0]); close(pfd4[1]);
execvp(cmd4[0], cmd4);
err_syserr("failed to execute '%s': ", cmd4[0]);
}
if ((pid5 = fork()) < 0)
err_syserr("failed to fork(): ");
else if (pid5 == 0)
{
err_remark("Child process 5\n");
dup2(pfd4[0], 0);
close(pfd1[0]); close(pfd1[1]);
close(pfd2[0]); close(pfd2[1]);
close(pfd3[0]); close(pfd3[1]);
close(pfd4[0]); close(pfd4[1]);
execvp(cmd5[0], cmd5);
err_syserr("failed to execute '%s': ", cmd5[0]);
}
close(pfd1[0]); close(pfd1[1]);
close(pfd2[0]); close(pfd2[1]);
close(pfd3[0]); close(pfd3[1]);
close(pfd4[0]); close(pfd4[1]);
int status;
int corpse;
while ((corpse = wait(&status)) > 0)
printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
return 0;
}
Notice that the blocks for pid2, pid3 and pid4 are almost the same; the block for pid1 only duplicates a pipe descriptor to stdout, while the block for pid5 only duplicates a pipe descriptor to stdin.
The code for the error reporting routines is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory. The err(3) functions on Linux and BSD have similar functionality but different function names.
Here is the output from a sample run (of the program pipe61 compiled from source code pipe61.c shown above.
pipe61: 2022-10-19 23:52:03.833 - pid=50391: Parent process
pipe61: 2022-10-19 23:52:03.834 - pid=50392: Child process 1
pipe61: 2022-10-19 23:52:03.834 - pid=50393: Child process 2
pipe61: 2022-10-19 23:52:03.834 - pid=50394: Child process 3
pipe61: 2022-10-19 23:52:03.834 - pid=50395: Child process 4
pipe61: 2022-10-19 23:52:03.834 - pid=50396: Child process 5
50391: child 50392 exited with status 0x0000
50391: child 50393 exited with status 0x0000
16
50391: child 50394 exited with status 0x0000
50391: child 50395 exited with status 0x0000
50391: child 50396 exited with status 0x0000
Clearly, this code is not easily configurable to deal with 6 or more stages in the pipeline except by cut'n'paste programming, nor is it trivial to remove any stages from the pipeline (variable renaming). For 'real' code, you'd need to use an array-driven approach to avoid unnecessary duplication of code. You'd have the pipe descriptors stored in an array; you'd have the PIDs stored in an array. You'd probably have an array of pointers to the lists of command arguments — three-star programming. And you'd probably use a function to launch the Nth child process.

Creating a new child process when old one is terminated in C

I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.

minishell created in c not working as expected, pipes related

im making an UNIX minishell in c, in my OS signature. I only have to improve the shell itself, we have a premade parser for implement yacc and a scanner for implement lex among other files.
The file to modify is msh.c, the main executable file.
Well, the problem begins when I try to implement the pipe secuences. This is what I made:
int executePipeLine (char*** argvv, int bg, char** filev, int n){
int i;
int in = 0;
pid_t pid;
int fd[2];
for (i = 0 ; i < n-1 ; i++){
pipe(fd);
pid_t pid = fork();
if (pid == 0){ //child
if (in != STDIN_FILENO){
dup2(in, STDIN_FILENO);
close(in);
}
if (fd[1] != STDOUT_FILENO){
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
}
execvp(argvv[i][0], argvv[0]);
}
else { //parent
close(fd[1]);
in = fd[0];
}
}
if(in != STDIN_FILENO){
dup2(in, STDIN_FILENO);
close(in);
}
pid_t lastpid = fork();
if(lastpid == 0){ //child
execvp(argvv[i][0], argvv[0]);
}
if(lastpid == -1){
perror("no se pudo crear el hijo\n");
exit(-1);
}
else { //parent
/* not bg*/
if(!bg ) {
int status;
while (wait(&status) != lastpid); /* wait the child. */
}
else {
/*bg mode*/
printf("pid del proceso last: %d\n", lastpid);
}
return 0;
}
}//end executePipeLine
This seems to work fine. In the main , where we have an extern function called obtain_order(); that returns the number of commands + 1 and save it to ret. If ret is 1 we continue with the prompt, if is 0 means EOF (Control + D keybinding) to end the shell, and if is >1 execute the commands.
Here you have it:
int main(void)
{
char ***argvv;
int command_counter;
int num_commands;
int args_counter;
char *filev[3];
int bg;
int ret;
int reset = 0;
setbuf(stdout, NULL); /* Unbuffered */
setbuf(stdin, NULL);
while (1)
{
fprintf(stderr, "%s", "msh> "); /* Prompt */
ret = obtain_order(&argvv, filev, &bg);
printf("ret: %d\n", ret);
if (ret == 0) break; /* EOF */
if (ret == -1) continue; /* Syntax error */
num_commands = ret - 1; /* Line */
if (num_commands == 0) continue; /* Empty line */
if(num_commands > 1){
executePipeLine(argvv, bg, filev, num_commands);
}
else if (num_commands == 1){
executeCommand(argvv, bg, filev);
}
} //fin while
return 0;
} //end main
All works fine with a simple command. The problem is when I try to execute a pipe line. It show a good result, but i dont know we, after that ret always is 0 in the next iteration, so every time I try to execute a pipe line, it works but close the shell process, and have to execute it again instead of continue with the promt.
You know what is the problem here?
I hope you understand me, my english is not perfec. Thanks
In the parent process (i.e. your mini-shell) you are duping the standard input:
...
else { //parent
close(fd[1]);
in = fd[0];
}
...
if(in != STDIN_FILENO){
dup2(in, STDIN_FILENO);
close(in);
}
When your pipeline terminates, children are dead, pipes are no longer readable => stdin is considered as closed. When you later call obtain_order in your main loop, it returns 0 (EOF) and your program exits.

C program to pipe multiple commands

I have written the below method to fork and execute commands separated by multiple pipes( test with : ls -lrt | grep "check" | wc -l . However it is not resulting in any output, could any one please spot my mistake. Thanks.
void execCmd (pInfo *info)
{
int i, j, k, m;
struct comType *comm, *comm1, *comm2;
if(info->noOfPipes > 2)
{
// DOES NOT WORK
printf("Start\n");
comm=&(info->cArr[0]);
comm2=&(info->cArr[(info->ppNum)-1]);
int fds[2];
pipe(fds);
pid_t pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
printf("1st child execution here\n");
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm->cmd,comm->parms);
}
for (k=1;k<=((info->ppNum)-1);k++)
{
printf("For loop executionn number %d",k);
comm1=&(info->cArr[k]);
printf ("comm 1 : %s\n",comm1->cmd);
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//2nd to n-1 child process
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
dup2(fds[1], STDOUT_FILENO);
close(fds[1]);
execvp(comm1->cmd,comm1->parms);
}
wait(NULL);
}
pid = fork();
if(pid == -1)
{
perror("fork failed");
exit(1);
}
if(pid == 0)
{
//nth child process
printf("Last child execution\n");
close(fds[1]);
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
execvp(comm2->cmd,comm2->parms);
}
close(fds[0]);
close(fds[1]);
wait(NULL);
wait(NULL);
}
}
This following code should give you an idea how to implement the pipelining:
#define STDIN 0
#define STDOUT 1
void exec_cmd(struct comType cmd) {
execvp(cmd->cmd, cmd->params);
}
void pipeCmds(struct comType* cmds) {
int fd[cmds_length * 2] = {0};
pid_t pid = 0;
for (int i = 0; i < cmds_length; i++) {
if (pid = fork() == 0) {
//child: make this cmd's output the other cmd's input
pipe(fd + (2*i) );
close(STDOUT);
dup(fd[i]);
if(i > 0) {
close(STDIN);
dup(fd[i-1]);
}
exec_cmd(cmds[i]);
close(fd[i]);
}
}
}
Note that the main idea is that each command is executed in a separate process (via fork) and the output goes to the next command's input rather than to the default stdout(with file descriptor 1), and the same for the input - stdin (file descriptor 0).

C Programming 2 pipes

I want to set up 2 pipes in my program. I have 1 pipe working fine, but I don't know where to place the second pipe.
The pseudo code of my setup is shown below,
Here is it with curly braces sorry about that
//the first pipe:
pipe(pipe1)
//the second pipe:
pipe(pipe2)
pid = fork()
if(pid == 0) {
dup2(pipe1[1], 1)
close(pipe1[0])
execvp(beforepipe)
}
if(pid > 0) { //everything below is in here
pid2 = fork()
if(pid2 == 0){
//pipe1
dup2(pipe1[0],0)
dup2(out,1)
close(pipe1[1])
execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)
}
if(pid2 > 0){
close(pipe[0])
close(pipe[1])
wait() //this is an infinite for loop
pid3 = fork()
if(pid3 == 0){
dup2(pipe2[0],0)
dup2(out,1)
close(pipe2[1])
execvp(afterpipe2)
}
if(pid3 > 0) {
close(pipe2[0])
close(pipe2[1])
wait()
}
}
The position of the second pipe is in the wrong place or the code is altogether wrong.
Any suggestions?
Your main problem is that you are not closing anywhere near enough file descriptors. Given a file input1 in the current directory containing your string "eschew obfuscation\", this code works for me (but note how many file descriptors have to be closed!).
Rule of thumb: if a pipe is dup2()d or dup()d to standard input or output, close both file pipe file descriptors.
Example code (with debug tracing in place):
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* command pipeline: cat input1 | tr a-z A-Z | tr \\ q */
int main(void)
{
int pipe1[2];
int pipe2[2];
pid_t pid1;
char *cmd1[] = { "cat", "input1", 0 };
char *cmd2[] = { "tr", "a-z", "A-Z", 0 };
char *cmd3[] = { "tr", "\\", "q", 0 };
if (pipe(pipe1) != 0 || pipe(pipe2) != 0)
{
perror("pipe failed");
return 1;
}
pid1 = fork();
if (pid1 < 0)
{
perror("fork 1 failed");
return 1;
}
if (pid1 == 0)
{
/* Child 1 - cat */
dup2(pipe1[1], 1);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd1[0], cmd1);
perror("failed to execute cmd1");
return 1;
}
printf("pid 1 = %d\n", pid1);
fflush(stdout);
pid_t pid2 = fork();
if (pid2 < 0)
{
perror("fork 2 failed");
return 1;
}
if (pid2 == 0)
{
/* Child 2 - tr a-z A-Z */
dup2(pipe1[0], 0);
dup2(pipe2[1], 1);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd2[0], cmd2);
perror("failed to execute cmd2");
return 1;
}
printf("pid 2 = %d\n", pid2);
fflush(stdout);
pid_t pid3 = fork();
if (pid3 < 0)
{
perror("fork 3 failed");
return 1;
}
if (pid3 == 0)
{
/* Child 3 - tr \\ q */
dup2(pipe2[0], 0);
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
execvp(cmd3[0], cmd3);
perror("failed to execute cmd3");
return 1;
}
printf("pid 3 = %d\n", pid3);
fflush(stdout);
/* Parent - wait for the kids to all die */
close(pipe1[0]);
close(pipe1[1]);
close(pipe2[0]);
close(pipe2[1]);
pid_t corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d died status 0x%.4X\n", corpse, status);
return 0;
}
execvp(afterpipe)
//pipe2 does not work might need to be placed in different area
dup2(pipe1[1],1)
close(pipe1[0])
execvp(beforepipe1)
I think the execvp() didnot return. So the code below the execvp() is irrelevent.

Resources