piping two times using fork in C linux - c

I am trying to rewrite a c program that do something like ls|wc|wc , I already did it for ls|wc , it worked fine, but I can't figure out why my program stops at the child in the indicated line. please help!
int main (void)
{
pid_t pid_fils, pid_pfils;
int fd[2], fd2[2];
if(pipe(fd)==-1 || pipe(fd2)==-1)
{
printf("pipe failed!");
return 1;
}
printf("program started\n");
pid_fils=fork();
if(pid_fils==0)
{
pid_pfils=fork();
if(pid_pfils==0)
{
//action3
printf("I am the grandson\n");
close(fd[0]);//close read side
dup2(fd[1],1);//connect write with stdout
close(fd[1]);//close write side
execlp("ls","ls",(char*)0);
//execvp("ls",argv3);
return 0;/*actions grandson*/
}
else
{
//action2
printf("I am the son\n");
wait();
printf("son, wait ok\n");
>close(fd[1]); //close read side
>dup2(fd[0],0); //connect write with stdin
>close(fd[0]); //close read side
///////pipe2////
> close(fd2[0]); //close read side
>dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
printf("ok!\n");
>close(fd2[1]); //close write side
execlp("wc","wc",(char*)0);
printf("error exec returned!\n");
return 0;
}
}
else
{
///action1
printf("I am the parent\n");
wait();
printf("parent,wait ok\n");
close(fd2[1]); //close write side,
dup2(fd2[0],0); //connect read with stdin
close(fd2[0]); //close read side
execlp("wc","wc",(char*)0);
return 0;/*the parent*/
}
return 1;
}

Make sure you close all unused descriptors. In your case, the easiest solution is to move the creation of pipe(fd) into the first if block (in the first sub-process). The problem is that as long as any process could possibly write to the pipe, the reader won't get EOF and so won't terminate.
if(pipe(fd2)==-1)
{
printf("pipe failed!");
return 1;
}
printf("program started\n");
pid_fils=fork();
if(pid_fils==0)
{
if(pipe(fd)==-1)
{
printf("pipe failed!");
return 1;
}
pid_pfils=fork();
I should also mention that you may want to reconsider the wait calls. Not sure what you are intending to do with them but you don't want the "ls" process to block on output because the reader hasn't been started yet.

dup2(fd2[1],1);
Above line will first close the file at descriptor 1 and then duplicate the decriptor from fd2[1] into 1.
1 is stdout. Meaning that call closed stdout.
printf prints to stdout, meaning printf prints to 1 which is now assigned to the pipe fd2
So your ok went into the pipe and not on the screen.
try
//action2
printf("I am the son\n");
wait();
printf("son, wait ok\n");
close(fd[1]); //close read side
dup2(fd[0],0); //connect write with stdin
close(fd[0]); //close read side
///////pipe2////
int my_terminal_out = dup(1);
close(fd2[0]); //close read side
dup2(fd2[1],1); //connect write with stdout/*it stops here -can't display "ok!"*/
fprintf(my_terminal_out, "ok!\n");
close(fd2[1]); //close write side
Not tested. Also you should test the rest of your code for similar missteps.
+What DrC said.

Related

execlp() failing to retrieve correct input

I've been trying to write a really simple program in which the parent process passes 100 lines to a child process through a pipe. The child should then use the generated lines and execute the command line program more over those lines.
However, when I try to run the program, it just freezes. I was careful to close all descriptors not being used by both processes but I don't really understand what may be causing it.
Code:
int main(void){
int fd[2];
if (pipe(fd) == -1){
perror("Error creating pipe");
return 1;
}
dup2(fd[1], STDOUT_FILENO);
int i;
for (i = 1; i <= 100; i++){
printf("Line %d\n", i);
}
close(fd[1]);
pid_t pid = fork();
if(pid == 0) {
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execlp("more", "more",(char*) NULL);
fprintf(stderr, "Failed to execute 'more'\n");
exit(1);
}
wait(NULL);
return 0;
}
I was careful to close all descriptors not being used by both processes
Not really.
dup2(fd[1], STDOUT_FILENO);
Here you make stdout a copy of fd[1].
close(fd[1]);
Here you close fd[1], but stdout is still open.
Then you fork. At this point both processes have access to the write end of the pipe via stdout.
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
In the child process you copy fd[0] to stdin and close fd[0].
Then, when you exec more, it still has access to both ends of the pipe (via stdin / stdout).
At the same time your parent process has access to both ends of the pipe (via fd[0] / stdout).
In effect you've closed nothing.
There's a second issue: Your parent process writes to stdout, which is bound to the write end of the pipe, without anyone reading it. Depending on how much you write, whether stdout is line buffered or block buffered, how big the stdout buffer is, and how much your pipe itself can store, this itself can deadlock. If the pipe runs full and there's no one around to read from it, printf will just block.
To fix this, don't dup2 in the parent process and don't write to the pipe before the child process has started.
int main(void){
int fd[2];
if (pipe(fd) == -1){
perror("Error creating pipe");
return 1;
}
pid_t pid = fork();
if (pid == -1) {
perror("Error spawning process");
return 2;
}
if (pid == 0) {
close(fd[1]); /* close write end of the pipe in the child */
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execlp("more", "more", (char*)NULL);
fprintf(stderr, "Failed to execute 'more'\n");
exit(1);
}
close(fd[0]); /* close read end of the pipe in the parent */
FILE *fp = fdopen(fd[1], "w");
if (!fp) {
perror("Error opening file handle");
return 3;
}
for (int i = 1; i <= 100; i++){
fprintf(fp, "Line %d\n", i);
}
fclose(fp); /* flush and close write end of the pipe in the parent */
wait(NULL);
return 0;
}

Forking multiple child processes and open()/dup2()

So I'm trying to read a line with multiple commands and creating a child process for each command to handle it. I'm having some trouble once I try to uncomment the if(fd2) statement for stdout redirection. Instead of the desired output appearing once, it appears multiple times. I'm not exactly sure what is causing this, I'm closing all of the file descriptors and having the child exit.
The commands I'm dealing with may have both stdout and stdin redirection, and I'm successful in setting up the redirection for stdin, but I cant seem to find my bug. I don't get a perror() warning on display. It's not so much as a problem with dup2(), but rather with open(), if I just uncomment that part I get the error.
int concCmd(Cmd cmdM[], int iCmdCnt, Token tokenM[], int iTokenCnt){
long pid, wpid;
int i, status=0, fd = 0, fd2=0;
fflush(0);
for(i=0; i<iCmdCnt; i++){ //create a process for every command
pid=fork();
switch(pid){
case -1:
perror("Fork\n");
return 1;
case 0:
if(cmdM[i].iStdinRedirectIdx != 0){ //does command need stdin redirection
if((fd = open(tokenM[cmdM[i].iStdinRedirectIdx], O_RDONLY)) <0){
perror("open stdin");
return 1;
}
if((dup2(fd,STDIN_FILENO))<0){
perror("dup2");
return 1;
}
close(fd); //close in parent process
}
if(cmdM[i].iStdoutRedirectIdx != 0){ //command needs stdout redirection
// if((fd2 = open(tokenM[cmdM[i].iStdoutRedirectIdx], O_WRONLY|O_CREAT|O_EXCL)) < 0){
// perror("open stdout");
// return 1;
// }
// if((dup2(fd, STDOUT_FILENO))<0){
// perror("dup2");
// return 1;
// }
close(fd2);
}
//EXECVP HERE!!!
//execvp (cmdM[i].szCmdNm, tokenM[
exit(0);
default:
wpid = wait(&status);
close(fd);
close(fd2);
fprintf(stderr, "%ld %ld\n", (long)getpid(), wpid);
}
}
return 0;
}
I went ahead an added a fflush(0) before I started forking, to clear out the buffer, as suggested in another question, which should reasonably clear the buffer for when I call open for stdout, but I still get the same errors.
I was going to make a comment, because what I want to say is very simple, but I need to reference some code, so maybe posting an answer is easier.
// if((fd2 = open(tokenM[cmdM[i].iStdoutRedirectIdx], O_WRONLY|O_CREAT|O_EXCL)) < 0){
// perror("open stdout");
// return 1;
// }
// if((dup2(fd, STDOUT_FILENO))<0){
// perror("dup2");
// return 1;
// }
In your code, the part about fd2 which you comment in your question has a typo.
dup2(fd, STDOUT_FILENO) should be dup2(fd2, STDOUT_FILENO)
I don't know whether it is really a typo in your source code, or you just made a mistake when you posting your question.

C: execve: I have to implement pipes for a shell, however I cant seem to get the final result out of the second pipe

This is a homework assignment that has me stumped. I make two pipes, then two child processes to handle both sides of the pipe. The first child handles the first command and writes it to the first pipe, the second child handles the second command and writes it to the second pipe. However, when all is said and done, I read the contents from the second pipe and put it into a buffer and simply printf(buffer). Its at this step that my code is failing. I cannot read from the buffer. I have tested all my method calls such as getWordsBeforePipe() and I know they work. Do you guys see anything I am missing?
// Create the first pipe
pipeStatus = pipe(pfd1);
if (pipeStatus == -1) {
perror("pipe");
exit(1);
}
// create the first child
pid = fork();
if (pid == -1) {
printf("Bad first fork()...\n");
exit(1);
}
// Here we will run the first command inside of the first child.
if (pid == 0) {
printf("Im in the first child...\n");
getWordsBeforePipe(pipeLoc); // get the words before the pipe
close(pfd1[0]); // close read end because we arent reading anything
dup2(pfd1[1], 1); // copy to write-end of pfd instead of stdout
close(pfd1[1]); // close the write end
firstCommand = execve(pathFirst, beforePipeWords, environ);
perror("execve"); // we only get here if execve died
_exit(1);
}
// create the second pipe
pipeStatus = pipe(pfd2);
if (pipeStatus == -1) {
perror("pipe");
exit(1);
}
// create the second child
pid = fork();
if (pid == -1) {
printf("Bad second fork()...\n");
exit(1);
}
// Here we will run the second command and put its
// output into the second pipe
// first command business
if (pid == 0) {
printf("Im in the second child...\n");
getWordsAfterPipe(pipeLoc);
close(pfd1[1]); // close first child write end
dup2(pfd1[0], 0); // read from the pfd read end instead of stdin
close(pfd1[0]); // close the read end
// second command business
close(pfd2[0]); // close read end because we arent reading anything
dup2(pfd2[1], 1); // copy to write end of pfd instead of stdout
close(pfd2[1]);
secondCommand = execve(pathSecond, afterPipeWords, environ);
perror("execve"); // we only get here if execve died
_exit(1);
}
close(pfd1[0]);
close(pfd2[0]);
close(pfd2[1]);
// read from the second pipe and output the final value
readSuccess = read(pfd2[0], buffer, 256);
if (readSuccess < 0) {
printf("Failure reading the buffer...\n"); // I keep getting this error
exit(1);
}
if (readSuccess == 0) {
printf("Empty buffer...\n");
exit(1);
}
buffer[readSuccess] = '\0';
printf("%s", buffer);
The parent process is doing this:
close(pfd2[0]);
Followed by this:
readSuccess = read(pfd2[0], buffer, 256);
You can't read from a file descriptor after it's been closed.
You properly closed both ends of the pfd1 pair, since the two children read/write from them. The second child writes to pfd2[1], so the parent should be closing that instead of pfd2[0].
Check that the command specified by pathFirst writes to stdout, and that the command specified by pathSecond both reads from stdin and writes to stdout.

Killing all descendants of a process

I'm trying to create a shell wherein i need to implement pipelining..
The pipes are working fine untill all commands are correct else it either blocks or goes into infinite loop(when last cmd is wrong)..here's my pipelines function....
Code explanation:- I'm using two pipes for alternate pipes declared in command.Initially pipe1(fd1) in declared and when second pipe is found another pipe(fd2) is declared. When the third pipe is found pipe1(fd1 ) is redeclared and when fourth pipe is found pipe(fd2) is redeclared and this goes as long as new pipes are found.
num received by function is number of commands (actually number-1) separated by pipes.
Inside the loop then I have divided commands on five conditions
1>>(odd numbered cmd as i%2==0)starting command(i==0 and i%2==0)
2>>ending command(for I%2==0 and i==num)
3>>mid in pipe(i%2==0 and i!=num)
4>>(even numbered cmd as i%2!=0) mid in pipe(i%2!=0 and i!=num)
5>>ending even numbered cmd(i%2!=0 and i==num)
Heres my code :
void call_piping(int num){
int i,fd1[2],fd2[2],status;
pid_t pid;
//pipe(fd1);
//pipe(fd2);
for(i=0;i<=num;i++){
//printf("HH\n");
if(i%2==0){
if(pipe(fd1)==-1){
printf("Error creating pipe fd1\n");
return;
}
}
else{
if(pipe(fd2)==-1){
printf("Error creating pipe fd2\n");
return;
}
}
/*else{
close(fd1[1]);
}*/
if(i==0){
pid=fork();
if(pid==0){
close(fd1[0]);
close(1);
dup2(fd1[1],1);
if((execvp(argv[i][0],argv[i]))==-1){
printf("%s: Invalid command or Command not found\n",argv[i][0]);
close(fd1[1]);
return;
}
}
else{
waitpid(pid,&status,0);
close(fd1[1]);
//printf("Hello1");
}
}
else if(i%2==0 && i==num){
pid=fork();
if(pid==0){
close(0);
//close(1);
dup2(fd2[0],0);
if((execvp(argv[i][0],argv[i]))==-1){
printf("%s: Invalid command or Command not found\n",argv[i][0]);
close(fd2[0]);
return;
}
}
else{
waitpid(pid,&status,0);
//printf("Hello");
close(fd2[0]);
}
}
else if(i%2==0 && i!=num){
pid=fork();
if(pid==0){
close(0);
close(1);
dup2(fd2[0],0);
dup2(fd1[1],1);
if((execvp(argv[i][0],argv[i]))==-1){
printf("%s: Invalid command or Command not found\n",argv[i][0]);
close(fd1[1]);
//printf("Hell");
close(fd2[0]);
return;
}
}
else{
waitpid(pid,&status,0);
close(fd1[1]);
//printf("Hell");
close(fd2[0]);
}
}
else if(i%2!=0 && i==num){
pid=fork();
if(pid==0){
close(0);
dup2(fd1[0],0);
if((execvp(argv[i][0],argv[i]))==-1){
printf("%s: Invalid command or Command not found\n",argv[i][0]);
close(fd1[0]);
return;
}
}
else{
waitpid(pid,&status,0);
//printf("Hel");
close(fd1[0]);
}
}
else if(i%2!=0 && i!=num){
pid=fork();
if(pid==0){
close(0);
close(1);
dup2(fd1[0],0);
dup2(fd2[1],1);
if((execvp(argv[i][0],argv[i]))==-1){
printf("%s: Invalid command or Command not found\n",argv[i][0]);
close(fd2[1]);
close(fd1[0]);
return;
}
}
else{
waitpid(pid,&status,0);
//printf("He");
close(fd2[1]);
close(fd1[0]);
}
}
}
}
so basically it is error handling i'm having problem with...one solution that i thought was to all descendants processes created but dont know how to do that....
That is an extremely complex rat's nest of if statements. I've certainly not understood all the code; I've not even attempted to read it all. However, I don't think you're closing enough file descriptors quick enough.
For example, at the end, you have:
else{
waitpid(pid,&status,0);
//printf("He");
close(fd2[1]);
close(fd1[0]);
}
Diagnostic printing should always have a newline at the end; otherwise, you won't see the output in a timely manner. The two close() calls should be before the waitpid(); processes that wait for EOF on the pipe won't get EOF if the parent process still has it open for writing.
Early on in the code, you have:
if(pid==0){
close(fd1[0]);
close(1);
dup2(fd1[1],1);
if((execvp(argv[i][0],argv[i]))==-1){
printf("%s: Invalid command or Command not found\n",argv[i][0]);
close(fd1[1]);
return;
}
}
As a rule of thumb, if you use dup2() to associate a pipe file descriptor with either standard input or standard output, you should close both of the pipe file descriptors in that process. You also do not need to do close(1) before doing dup(fd[1], 1) — dup2() closes the target file descriptor anyway.
You should report errors on standard error, not standard output. The name should be self-explanatory.
You don't need to test the return value from execvp(); the function won't return unless it failed, so the test is redundant. It is also usually a good idea to exit from a failed exec*() call rather than return. If the exec*() fails and the code returns, you'll have two processes competing for standard input; this never leads to happiness.
The second fragment might be written like this (where, amongst other changes, I've added some spaces for improved readability; spaces are cheap!):
if (pid == 0)
{
dup2(fd1[1], 1);
close(fd1[0]);
close(fd1[1]);
execvp(argv[i][0], argv[i]);
fprintf(stderr, "%s: Invalid command or Command not found\n", argv[i][0]);
exit(1);
}

How to use dup2/close correctly to connect these three processes?

I'm trying to properly connect three processes in order to allow inter-process communication between them. I have one process, scanner, which takes the parent's STDIN and then processes the words within the stream. If a word length is odd, it sends it to one process, if it is even, it sends it to another. These processes should take in these words via STDIN (I assume) and then output some info back to the scanner process via STDOUT. The STDOUT of even/odd should be redirected to scanner, which will then read (using read) and then output/process the words. It's an academic exercise, not a practical one. Here's what a picture of it would look like:
Here's what my code currently looks like. The problem is I'm not exactly sure what to dup and what to close. Once I figure that out I should be good to go! Any advice would be appreciated.
File descriptors:
int scannertoeven[2]; int scannertoodd[2];
int eventoscanner[2]; int oddtoscanner[2];
//Pipe stuff here (ommitted)
Code:
//Create the child processes
if ((scanner_pid = fork()) == 0) {
//We need the scanner pid so even and odd can send signals to it
char pidofparent[sizeof(getpid())];
sprintf(pidofparent, "%i", getpid());
//Even stuff
if ((even_pid = fork()) == 0) {
close(scannertoodd[0]); close(scannertoodd[1]);
close(oddtoscanner[0]); close(oddtoscanner[1]);
//Not sure which ones to close
close(scannertoeven[0]); close(scannertoeven[1]);
close(eventoscanner[0]); close(eventoscanner[1]);
//Correct?
close(STDIN_FILENO);
dup2(scannertoeven[0], STDIN_FILENO);
close(STDOUT_FILENO);
dup2(eventoscanner[1], STDOUT_FILENO);
if(execl("./evenodd", "even", pidofparent, NULL ) == -1) {
printf("execl Error!");
exit(1);
}
//Odd Stuff
} else if ((odd_pid = fork()) == 0){
close(scannertoeven[0]); close(scannertoeven[1]);
close(eventoscanner[0]); close(eventoscanner[1]);
//Not sure which ones to close
close(scannertoodd[0]); close(scannertoodd[1]);
close(oddtoscanner[0]); close(oddtoscanner[1]);
//Correct?
close(STDIN_FILENO);
dup2(scannertoodd[0], STDIN_FILENO);
close(STDOUT_FILENO);
dup2(oddtoscanner[1], STDOUT_FILENO);
if(execl("./evenodd", "odd", pidofparent, NULL ) == -1) {
printf("execl Error!");
exit(1);
}
//Actual Scanner
} else {
// Not sure which ones to close- this is very wrong
close(scannertoeven[0]); close(scannertoeven[1]);
close(eventoscanner[0]); close(eventoscanner[1]);
close(scannertoodd[0]); close(scannertoodd[1]);
close(oddtoscanner[0]); close(oddtoscanner[1]);
//Not sure what to dup either
dup2(scannertoodd[1], STDOUT_FILENO);
dup2(scannertoeven[1], STDOUT_FILENO);
if(execl("./scanner", "scanner", stoeven, stoodd, eventos, oddtos, NULL ) == -1) {
printf("execl Error!");
exit(1);
}
//Wait twice here, or three times in main?
waitpid(odd_pid, &status2, 0);
waitpid(even_pid, &status3, 0);
}
//Main
} else {
//Close Pipes
close(scannertoodd[0]); close(scannertoeven[0]); close(eventoscanner[0]); close(oddtoscanner[0]);
close(scannertoodd[1]); close(scannertoeven[1]); close(eventoscanner[1]); close(oddtoscanner[1]);
//Wait for children to finish
waitpid(scanner_pid, &status1, 0);
printf("Done\n");
}
Not sure about the logic. But the way you use dup2 is not right.
The following code in the "Even" process:
close(STDIN_FILENO);
dup2(scannertoeven[0], STDIN_FILENO);
close(STDOUT_FILENO);
dup2(eventoscanner[1], STDOUT_FILENO);
should be:
dup2(scannertoeven[0], STDIN_FILENO);
// You should close scannertoeven[0], not STDIN. After this dup2, the even
// process will receive input from scannertoeven[0]
close(scannertoeven[0]);
// Note the the scannertoeven[0] is not "really" closed, just that the file
// is "attached" to STDIN
dup2(eventoscanner[1], STDOUT_FILENO);
// Same as above. After this dup2, all the even process's output will go
// to eventoscanner[1]
close(eventoscanner[1]);
The same as the "Odd" process.
Here is an example of dup2, for your reference.

Resources