Problem on piping with shell command in C - c

Here i try to implement linux shell script with piping in c, and i try to do it by passing the output of 1st child process to the 2nd child, and then do "grep a", then it should return sth like this
a 1
a 4
,and it should end the program.
But what i encounter is that, the output of 2nd child process is correct,output of "grep a" did come out, but the child process get stuck there and does not terminate itself, can anyone explain to me why this is happening? My parent process is keep waiting for the 2nd child process to end. But it just stuck there foreverfor some reason.
/* pipe4.c */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>
int main(int agrc, char* agrv[])
{
int pipefds[2];
pid_t pid;
pid_t pid2;
int status;
if(pipe(pipefds) == -1){
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if(pid == -1){
perror("fork");
exit(EXIT_FAILURE);
}
if(pid == 0){
//replace stdout with the write end of the pipe
dup2(pipefds[1],STDOUT_FILENO);
//close read to pipe, in child
close(pipefds[0]);
execlp("cat","cat","try.txt",NULL);
}else{
waitpid(pid, &status, 0);
printf("first child done\n");
pid2 = fork();
if(pid2 == 0){
printf("second child start\n");
dup2(pipefds[0],STDIN_FILENO);
close(pipefds[1]);
execlp("grep","grep","a",NULL);
}
else{
waitpid(pid2, &status, 0);
printf("second child end\n");
close(pipefds[0]);
close(pipefds[1]);
exit(EXIT_SUCCESS);
printf("end\n");
}
}
}

The grep is waiting for all processes to close the write side of the pipe. The parent is waiting for grep to finish before it closes the write side of the pipe. That's a deadlock. The parent needs to close the pipe ends before it calls waitpid
Note that the boiler plate for dup2 is:
dup2(pipefds[1],STDOUT_FILENO);
close(pipefds[0]);
close(pipefds[1]);
as you need to close both ends of the pipe. I believe this is not causing an issue in your current setup, but it's not worth thinking too hard about. Just close both ends of the pipe.

Related

3 child processes require only 2 wait()

I am trying to implement a code that does ls| grep "pipes"| wc -l. For this I have created 3 child processes and used 2 pipes. Please find the code used:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
//pid_t p;
int pfds1[2],pfds2[2],s;
pipe(pfds1);
pipe(pfds2);
if(!fork()) //first child ls
{
//printf("ls ppid is:%d\n", getppid());
dup2(pfds1[1],1);
close(pfds1[0]);
close(pfds2[0]);
close(pfds2[1]);
close(pfds1[1]);
if(execlp("ls", "ls", NULL)==-1)
{
perror("Error in exec line 24\n");
exit(1);
}
}
else{
if(!fork())
{
//printf("grep ppid is:%d\n", getppid());
dup2(pfds1[0],0);
dup2(pfds2[1],1);
close(pfds1[0]);
close(pfds2[0]);
close(pfds2[1]);
close(pfds1[1]);
if(execlp("grep","grep","pipes",NULL)==-1)
{
perror("Error in exec line 41\n");
exit(1);
}
}
else{
if(!fork())
{ //printf("wc ppid is:%d\n", getppid());
dup2(pfds2[0],0);
close(pfds1[0]);
close(pfds2[0]);
close(pfds2[1]);
close(pfds1[1]);
if(execlp("wc","wc","-l",NULL)==-1)
{
perror("Error in exec line 56\n");
exit(1);
}
}
else{
close(pfds1[0]);
close(pfds2[0]);
close(pfds1[1]);
close(pfds1[1]);
wait(&s);
wait(&s);
wait(&s);
//printf("parent pid is:%d\n", getpid());
//printf("grandparent pid is:%d\n", getppid());
exit(0);
}
}
}
}
The code works as intended when only 2 wait(&s) are used instead of 3, even though there are three children processes. The current code gets stuck and doesn't finish executing. Could someone pls elaborate on why this is happening?
Thanks
Before all, there's a typo in your code that makes one end of the pipe in the last process to remain open and this makes the block to happen. See below.
The problem is that when you fork your two file descriptors (from which you are closing one, the unused one, in the child, before calling exec) convert in four (two in the child, and also two in the parent, and you don't close one of the file descriptors in the parent process)
if you don't close the descriptors you don't use (either in the parent or in the child process) there will be cases in which both descriptors of the pipe will still be open, and while that happens, the reading process is blocked, waiting for some input (or EOF) to come. when you create a pipe (by using the pipe(2) system call, as soon as you fork(), close the file descriptor of the pipe you are not going to use, because you can block because everything is finished, but you still wait for input to come (being the parent or the child process, depending on how you organized the information to flow)
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void)
{
//pid_t p;
int pfds1[2],pfds2[2], s;
pipe(pfds1);
pipe(pfds2);
if(!fork()) { //first child ls
//printf("ls ppid is:%d\n", getppid());
dup2(pfds1[1],1);
here, you have installed the writing end of the pipe as the standard output for ls, but you don't read that.
close(pfds1[0]);
close(pfds2[0]);
close(pfds2[1]);
close(pfds1[1]);
This is ok. All file descriptors will be closed on exit, so no need to close them explicitly.
if(execlp("ls", "ls", NULL)==-1) {
perror("Error in exec line 24\n");
exit(1);
}
} else { // parent
if(!fork()) {
//printf("grep ppid is:%d\n", getppid());
dup2(pfds1[0],0);
dup2(pfds2[1],1);
Here you connect the standard input to the reading side of pipe1 and the standard output of pipe2 to the standard input. grep will wait for input on that pipe.
close(pfds1[0]);
close(pfds2[0]);
close(pfds2[1]);
close(pfds1[1]);
as said before, all pipes will be closed when grep finishes... so no need to explicitly close them here.
if(execlp("grep","grep","pipes",NULL)==-1) {
perror("Error in exec line 41\n");
exit(1);
}
} else { // parent
if(!fork()) {
//printf("wc ppid is:%d\n", getppid());
dup2(pfds2[0],0);
you connect also the input edge of pipe2 to standard input, so wc -l will wait for your input on pipe2.
close(pfds1[0]);
close(pfds2[0]);
close(pfds2[1]);
close(pfds1[1]);
as always, no problem if you don't close because this process will close all of them when it finishes.
if(execlp("wc","wc","-l",NULL)==-1) {
perror("Error in exec line 56\n");
exit(1);
}
} else{ // parent
close(pfds1[0]);
close(pfds2[0]);
close(pfds1[1]);
close(pfds1[1]); /* mistake!!!! */
You have a typo above, you close twice the descriptor pdfs1[1] and pdfs2[1] remains open, so the last process remains waiting for more input on the pipe, and never ends.
wait(&s);
wait(&s);
wait(&s);
//printf("parent pid is:%d\n", getpid());
//printf("grandparent pid is:%d\n", getppid());
exit(0);
}
}
}
}
Edit
The pipe requires that all the descriptors belonging to the write side to be closed, in order to notify the readers that end of file has occured and so, unlock the processes read()ing on them. In the fork, the descriptors of the pipe are implicitly dup()ed, and you again dup() them, when you redirect the input or output, by doing an explicit loop. The children processes just need to close the descriptors they are not going to use (you do well, when you do the dup() to redirect, and then close all the pipe descriptors)
In your case you use the pipes just to connect the children, and no communication is made from the parent... but its pipe descriptors also count to consider is EOF will be signalled to a reader. For a reader to be unlocked from read with EOF, you need to close all the dupped writing descriptors. This includes the ones of the parent, and the ones of the other children.

Creating pipes in C for inter process communication between multiple processes

There are already multiple answers to this question but none of them have been able to help me solve my problem. I am trying to understand IPC using an anonymous pipe in C.
From my understanding of pipes, they are a one way communication channel with one read end and one write end.
Assuming we have two c files one named parent.c and the other child.c. What I am trying to achieve is to be able to create 5 or more child processes. After this the parent and the child should communicate with the child processes through standard input and standard output, but since I want to be able to print what the parent receives from the child I'll instead tie the pipes to standard error output using dup2.
In summary
1. Run a parent program which spins up 5 or more child processes and runs them.
2. The child process waits for an input from the parent using scanf.
3. The parent sends a message to the child process.
4. The child process receives the message and sends a reply to the parent and exits.
5. The parent process prints the received message and prints it then exits.
parent.c
// Parentc
#include <stdio.h>
#include <stdlib.h>
#include <uinstd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, const char *argv[]){
// File descriptors for the pipes
int read_pipe[2]; // From child to parent
int write_pipe[2]; // From parent to child
pid_t process_id;
int exit_status;
// Try to fork 5 child processes
for(int i = 0; i < 5; i++){
if(pipe(write_pipe) == -1 || pipe(read_pipe) == -1){
perror("Pipe");
exit(1);
}
// Spin a child process
process_id = fork();
if(process_id == -1){
perror("Fork");
exit(1);
} else if(processId == 0) {
// The child process
// I don't know what to do here, The idea is to close the
// unneeded end of the pipes and wait for input from the parent
// process
// Start the ./child
execl("./child", "");
} else {
// The parent process
char recieved_data[1024];
// Send data to child since stderr is duplicated in the pipe
// It sends the pid of the child
fprintf(stderr, "Test data to %d ", process_id);
// Wait to recieve data from child
// Don't know how to do that
// Print the recieved data
printf("Parent recieved: \"%s\"\n", recieved_data);
wait(&exit_status); // Will wait till all children exit before exiting
}
}
return 0;
}
The child.c is a simple program as shown below
child.c
#include <stdio.h>
int main(int argc, const char *argv[]){
char data_buffer[1024];
// Wait for input from parent
scanf("%s", data_buffer);
// Send data back to parent
printf("Child process: %s", data_buffer);
return 0;
}
Expected output
$ ./parent
parent recived: "Child process: Test data to 12345"
parent recived: "Child process: Test data to 12346"
parent recived: "Child process: Test data to 12347"
parent recived: "Child process: Test data to 12348"
parent recived: "Child process: Test data to 12349"
Where 12345, 12346....12349 is the process id of the child process
Here you have a code i did, and i will use to explain to you:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char buff[1024];
int aux, i, count;
int fds[2], fdss[2];
pipe(fds); //Here we initialize the file descriptors
pipe(fdss);
mode_t fd_mode = S_IRWXU;
for (i = 0; i < 3; i++) {
aux = fork();
if (aux == 0)
break;
}
switch (i) {
case 0:
printf("Write something:\n");
scanf("%s[^\n]", buff);
i = 0;
count = 0;
while(buff[i] != '\0') {
count++;
i++;
}
dup2(fds[1], 1);
close(fds[1]);
close(fds[0]);
close(fdss[0]);
close(fdss[1]);
write (1, buff, sizeof(buff));
break;
case 1:
dup2(fds[0], 0);
dup2(fdss[1], 1);
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
//
if (execl("/bin/grep", "grep", "example", NULL) == -1) {
printf("Error\n");
exit (1);
}
break;
case 2:
aux = open("result.txt", O_RDWR | O_CREAT , S_IRWXU);
dup2(fdss[0], 0);
dup2(aux, 1);
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
close(aux);
if (execl("/usr/bin/wc", "wc", "-l", NULL) == -1) {
printf("Error \n");
exit (1);
}
}
close(fds[0]);
close(fds[1]);
close(fdss[0]);
close(fdss[1]);
for (i = 0; i < 3; i++) wait(NULL);
return 0;
}
Ok, let's start:
We create and initialize pipes with pipe()
Then we write our code and before execl() we change the file descriptors, in order to pass the text we will write in the console, through processes and finally write in a file called result.txt the result of the "grep example" command applied to the text we have written.
The function dup2(new_descriptor, old_descriptor) is copying the new descriptor into the old descriptor and closes the old descriptor. For example:
Before dup2(fds[1], 1) we have:
0 STDIN
1 STDOUT
2 STDERR
After dup2(fds[1], 1) we have:
0 STDIN
1 fds[1]
2 STDERR
NOTE: If you don't want to use 1, yo can simply write STDOUT_FILENO
So now we are able to write through processes and in my example to a file too

How does a parent process read a FIFO after the child process finished the writing that FIFO?

I have a very simple basic program that has two process first one is parent and second one is child.
Child process should write some stuff to the FIFO. After all writing jobs finished(after the child is terminated).
Then parent process should read all the FIFO file and print to the stdout.
So I think, I need a wait(NULL); for parent. So the parent will wait until the child is terminated. But child is also blocked because of the writing and blocked for reading this writes. So both process wait each other and I think,there occur an deadlock.
My program is this:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
int writeSomeStuffToFifo ();
void printAllFifo ();
char * myfifo = "myfifo";
int main(int argc, char **argv) {
int pid=0;
int childPid=-1;
int status;
pid=fork();
if ((pid = fork()) < 0){
perror("fork() error");
}
else if (pid == 0) {
writeSomeStuffToFifo ();
exit(1);
}
else do {
if ((pid = waitpid(pid, &status, WNOHANG)) == -1)
perror("wait() error");
else if (pid == 0) {
//child running
printf("child running\n");
}
else {
if (WIFEXITED(status)){
printf("child is terminated\n");
printAllFifo();
}
else{
printf("child did not exit successfully\n");
}
}
} while (pid == 0);
return 0;
}
int writeSomeStuffToFifo (){ //child process will run this function
int fd;
mkfifo(myfifo, 0666);
fd = open(myfifo, O_WRONLY);
write(fd,"foo1\n",strlen("foo1\n"));
close(fd);
fd = open(myfifo, O_WRONLY);
write(fd,"foo2\n",strlen("foo2\n"));
close(fd);
fd = open(myfifo, O_WRONLY);
write(fd,"foo3\n",strlen("foo3\n"));
close(fd);
}
void printAllFifo (){ //parent process will run this function
int fd=open(myfifo, O_RDONLY);
char* readBuffer=(char*)malloc((strlen("foo1\n")+strlen("foo2\n")+strlen("foo3\n"))*sizeof(char));
read(fd, readBuffer, strlen("foo1\n")+strlen("foo2\n")+strlen("foo3\n"));
printf("%s\n",readBuffer );
close(fd);
}
mkfifo() creates a pipe of limited size. You should not wait in the parent process until the child has finished in order to read, you should read constantly in the parent process while checking if the child has terminated already.
You can use ulimit -p in order to read the default size of pipes in your linux system. The number is multiplications of 512, so a value of 8 means 4096 bytes.
Using pipe() is more suited to the task than mkfifo() because you do not actually need a named pipe. this will provide you with 2 fds, one for read and one for write. In the parent code you close the write fd, in the child code you close the read fd, then you can start reading from the pipe in the parent code until it returns a value <= 0. This would mean that the child process has terminated (and the pipe was closed for writing). then you only need to call waitpid() from the parent code to collect the terminated child process.

Unable to use pipe as input for grep in C

On Ubuntu 16 I am trying to write a program exercising pipes, forking, and execing:
the program will accept a file name via a command-line argument;
a child process will open the named file and exec cat to transfer the content to a second child process; and
the second child will exec grep to select the lines that contain numbers for forwarding to a third child process
the third child process prints the received lines.
Here's my code:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <string.h>
#include <sys/types.h>
#include<sys/wait.h>
#include<fcntl.h>
#define BLOCK_SIZE 4096
int main(int argc, char** argv)
{
int PID;
int pipe1[2];
int pipe2[2];
int pipe3[2];
char fileName[256];
int lengthfileName = strlen(argv[1]);
char content[BLOCK_SIZE];
char modifiedContent[BLOCK_SIZE];
int file;
if(argc < 2)
{
printf("Usage prog file\n");
exit(1);
}
if(pipe(pipe1) < 0)
{
printf("Error at pipe\n");
exit(1);
}
if(pipe(pipe2) < 0)
{
printf("Error at pipe\n");
exit(1);
}
if(pipe(pipe3) < 0)
{
printf("Error at pipe\n");
exit(1);
}
if((PID = fork()) < 0)
{
printf("Error at process\n");
exit(1);
}
if(PID == 0) //first child
{
close(pipe1[1]);
read(pipe1[0],fileName,lengthfileName);
close(pipe1[0]);
close(pipe2[0]);
dup2(pipe2[1],1);
close(pipe2[1]);
execlp("/bin/cat","cat",fileName,NULL);
exit(0);
}
else // parent
{
close(pipe1[0]);
write(pipe1[1],argv[1],lengthfileName);
close(pipe1[1]);
int status;
if((PID = fork()) < 0)
{
printf("Error at process\n");
exit(1);
}
if(PID == 0) // child 2
{
close(pipe2[1]);
//read(pipe2[0],content,BLOCK_SIZE);
//dup2(pipe2[0],0);// ***********************MARKED LINE HERE *****************************************
close(pipe2[0]);
close(pipe3[0]);
dup2(pipe3[1],1);
close(pipe3[1]);
execlp("grep","grep","[0-9]",NULL);
exit(0);
}
if((PID = fork()) < 0)
{
printf("Error at process\n");
exit(1);
}
if(PID == 0) //cod fiu 2
{
close(pipe3[1]);
read(pipe3[0],modifiedContent,BLOCK_SIZE);
close(pipe3[0]);
printf("GOT FROM PIPE:%s",modifiedContent);
exit(0);
}
waitpid(PID, &status, 0);
}
return 0;
}
My problem is inside the child process 2 code, where I try to use the pipeline as input for grep. As presented the input is taken from the terminal; if I uncomment the marked lines then the program hangs, and I have to manually kill it to make it stop.
What's wrong with how I'm using pipe2 to feed data to grep in child process 2? Or is the problem somewhere else?
It's a bit silly that you transfer the file name to the first child via a pipe, but rely on that child inheriting its length from its parent. If you're going to inherit the name's length, then you might as well inherit the whole file name, dispensing with the first pipe.
You could conceivably send the (fixed-size) length value over the pipe first to avoid inheriting it, but such a scheme is pointless -- not only do forked child processes inherit data from their parents, you cannot avoid relying on that in your program. In particular, the children must inherit the open pipe ends and the arrays of pipe file descriptors from the parent for the single-parent approach to work at all.
Note also that you are (maybe) lucking into null termination of the file name received over the pipe. The first child neither reads it from the pipe nor sets it explicitly.
But the main problem appears to be that you have stray open pipe ends. You create all three pipes in the parent, before forking any children. At each fork, the child will therefore inherit the open file descriptors for all pipe ends that the parent has not yet closed. The child processes should close all of the open pipe ends they do not use, but they only close some of them. Programs such as grep (and cat) don't exit until they see the end of the file, and they won't see that on a pipe while any process holds the write end open.
Specifically, the parent process never closes the write end of pipe2, and in fact the third child inherits that open descriptor and also does not close it. The first child closes its copy of that FD when it exits, but with two other handles on the pipe end open, that end remains open. Therefore, when the second child is taking its input from that pipe, it never sees end-of-file, and never exits. Making the parent close both ends of pipe2 between forking the second child and forking the third child should solve that problem.

forking multiple processes and making the parent wait for all of them (in C)

I'm creating various processes (3 to be precise) and making them do different things.
So far so good. I'm trying to wait in the parent until all children are completed. I've played around with many options (such as the one listed below) but either the parent waits but I have to press enter to return to the shell (meaning that some child completes after the parent?) or the parent never returns to the shell. Any ideas? pointers to where to look for more help? Thanks
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define READ_END 0
#define WRITE_END 1
int main (int argc, char **argv)
{
pid_t pid;
int fd[2];
int fd2[2];
pipe(fd);
pipe(fd2);
for (int i=0; i<3; i++) {
pid=fork();
if (pid==0 && i==0) {
//never uses fd2, so close both descriptors
close(fd2[READ_END]);
close(fd2[WRITE_END]);
printf("i'm the child used for ls \n");
close(fd[READ_END]); /*close read end since I don't need it */
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[WRITE_END]);
execlp("ls", "ls", "-hal", NULL);
break; /*exit for loop to end child's code */
}
else if (pid==0 && i==1) {
printf("i'm in the second child, which will be used to run grep\n");
close(fd[WRITE_END]);
dup2(fd[READ_END], STDIN_FILENO);
close(fd[READ_END]);
close(fd2[READ_END]);
dup2(fd2[WRITE_END], STDOUT_FILENO);
close(fd2[WRITE_END]);
execlp("grep", "grep","p",NULL);
break;
}
else if (pid==0 && i==2) {
//never uses fd so close both descriptors
close(fd[READ_END]);
close(fd[WRITE_END]);
printf("i'm in the original process which will be replaced with wc\n");
close(fd2[WRITE_END]);
dup2(fd2[READ_END], STDIN_FILENO);
close(fd2[READ_END]);
printf("going to exec wc\n");
execlp("wc","wc","-w",NULL);
break;
}
else {
//do parenty things
}
}
wait(NULL);
while (1){
wait(NULL);
if(errno== ECHILD) {
printf("all children ended\n");
break;
}
}
close(fd[READ_END]);
close(fd[WRITE_END]);
close(fd2[READ_END]);
close(fd2[WRITE_END]);
return 0;
}
grep and wc never exit.
Why? They never receive an EOF on stdin.
Why? Because, even though ls has exited and closed the write end of pipe(fd), the main process still has the write end of pipe(fd) open, thus the read end of pipe(fd) is still waiting for more data. Similar thing goes for fd2: even if grep exited, wc wouldn't get an EOF on stdin.
Solution: close all the pipe fds in the main process before you wait.

Resources