headache with named pipes and forks - c

I need to write program that have construction like this:
Parent makes fifo, then fork()
child 1 reads message from stdin and writes it to named pipe (FIFO)
then in parent process I need to create pipe (unnamed) and another fork()
child number 2 reades from FIFO, counts length of message and send number to parent via pipe(unnamed).
I created a simple program with one fork where child can communicate with parent:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO "/tmp/my_fifo"
int main()
{
pid_t fork_result;
int pipe_fd;
int res;
char writer[3];
char reader[3];
res = mkfifo(FIFO,0777);
if (res == 0)
{
printf("FIFO created!\n");
fork_result = fork();
if (fork_result == -1)
{
fprintf(stderr, "fork error");
exit(EXIT_FAILURE);
}
if (fork_result == 0)
{
printf("CHILD 1\n");
pipe_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
scanf("%s", writer);
res = write(pipe_fd,writer,3);
if (res == -1)
{
fprintf(stderr,"error writing fifo\n");
exit(EXIT_FAILURE);
}
(void)close(pipe_fd);
exit(EXIT_SUCCESS);
}
else
{
printf("PARENT\n");
pipe_fd = open(FIFO, O_RDONLY);
res = read(pipe_fd, reader, 3);
printf("reader: 0: %c\n",reader[0]);
printf("reader: 1: %c\n",reader[1]);
printf("reader: 2: %c\n",reader[2]);
(void)close(res);
}
}
else
{
printf("deleting fifo... run program again!\n");
unlink(FIFO);
}
exit(EXIT_SUCCESS);
}
and it is working very well. So I created code that have architecture described above:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO "/tmp/my_fifo"
int main()
{
pid_t fork_result;
pid_t fork_result2;
int pipe_fd;
int res;
char writer[3];
char reader[3];
res = mkfifo(FIFO,0777);
if (res == 0)
{
printf("FIFO created!\n");
fork_result = fork();
if (fork_result == -1)
{
fprintf(stderr, "fork error");
exit(EXIT_FAILURE);
}
if (fork_result == 0)
{
printf("CHILD 1\n");
pipe_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
scanf("%s", writer);
res = write(pipe_fd,writer,3);
if (res == -1)
{
fprintf(stderr,"error writing to fifo\n");
exit(EXIT_FAILURE);
}
(void)close(pipe_fd);
exit(EXIT_SUCCESS);
}
else
{
printf("PARENt 1\n");
//don't forget pipe!
fork_result = fork();
pipe_fd = open(FIFO, O_RDONLY);
if (fork_result == 0)
{
printf("CHILD 2\n");
res = read(pipe_fd, reader, 3);
printf("Odczytano: 0: %c\n",reader[0]);
printf("Odczytano: 1: %c\n",reader[1]);
printf("Odczytano: 2: %c\n",reader[2]);
(void)close(res);
}
}
}
else
{
printf("deleting fifo\n");
unlink(FIFO);
}
exit(EXIT_SUCCESS);
}
Running sequence is like this:
PARENT 1
CHILD 1
CHILD 2
so in Parent 1 I'm opening FIFO to read, in child 1 I'm writing to FIFO and child 2 should read it. I mean in code because when I run it I can't even write anything to FIFO. In blocks in scanf("%s", writer); which worked in first program.
Am I using open() correctly? Do I need to use getpid() somewhere? Why it's blocking when I try to write to fifo.

The problem is that CHILD1 is opening the fifo with O_NONBLOCK, which will fail (with EWOULDBLOCK or EAGAIN) if no other process has the fifo open for reading. Now in the first program, the parent continues running after the fork and opens the fifo for reading before the child gets going and opens the write end, so it works. But in the second case, the parent does an extra fork first, which slows it down just enough that CHILD1 gets to its open command before PARENT or CHILD2 has opened the fifo for reading, so the CHILD1 open fails.
Get rid of the O_NONBLOCK and it works just fine (though you do open the fifo for reading in both PARENT and CHILD2, which is probably not what you want).
You have another issue if you want to read from the keyboard. If you run this from the shell, PARENT will exit immediately (more or less), so the shell will go back to reading commands from the keyboard, which means that CHILD1 and the shell will be fighting over the input. If on the other hand, you do what you originally describe and have PARENT wait reading from a pipe from CHILD2, it should do what you want.

Isn't it because you use twice the same variable fork_result? As you created another variable fork_result2, which you don't use, it is probably unintended.
I don't know if this will solve your problem, but at least using fork_result2 at the second fork would make it easier to understand...

Related

why does my program get stuck in wait(NULL)?

I'm a c beginner and wrote a multiprocess program. I want to let my child process invoke strace and then pipe to the parent process so that parent process could print it.
But my parent progress seem to be getting stuck in wait(NULL); . I tried commenting code wait(NULL); and I got the output from my child process. I can't figure out why parent process keeping waiting. Hasn't the child process returned yet?
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
int pipefd[2];
pid_t pid;
char *exec_argv[] = { "/bin/strace", "-T", "tree", "/bin", NULL};
char *exec_envp[] = { "PATH=/bin", NULL };
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
} else if (pid == 0) { // child
close(pipefd[0]); /* close unused read end */
close(STDOUT_FILENO);
if (dup2(pipefd[1], STDERR_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
// invoke strace
execve(exec_argv[0], exec_argv, exec_envp);
perror(exec_argv[0]);
exit(EXIT_FAILURE);
} else { // parent
close(pipefd[1]); /* close unused write end */
if (dup2(pipefd[0], STDIN_FILENO) == -1) {
perror("dup2");
exit(EXIT_FAILURE);
}
printf("I'm parent!!!\n");
wait(NULL);
char *line = NULL;
size_t len;
while (getline(&line, &len, stdin) != -1) {
printf("%s", line);
}
free(line);
}
return 0;
}
You didn't close pipefd[0] in the parent.
You didn't close pipefd[1] in the child.
Another problem is that your code is susceptible to deadlocks. If the child writes enough to the pipe to fill it, it will block until it has space to accept more. And since the the pipe is not emptied until the child exits, the child will never unblock.
This is easy to fix: Read until EOF, then call wait to reap the child. In other words, move the wait so it's after the loop.

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.

How to Create IPC (Interprocess Communication) C programme to create with two child process

I want to create a IPC c program to create one parent and two child's processes. My code is:
#include <stdio.h>
void main()
{
int pid, status;
pid = fork();
if(pid == -1) {
printf(“fork failed\n”);
exit(1);
}
if(pid == 0) { /* Child */
if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
printf(“exec failed\n”);
exit(1);
}
}
else { /* Parent */
wait(&status);
printf(“Well done kid!\n”);
exit(0);
}
}
I want to show you an other code snippet to create one parent and two child process. This is what I am looking for. Now I want to write shell script for IPC, first take look of this code.
Note: there is an other code with same logic but different process names UP, uc1, uc2 e.g in this way we have two parent VP and UC and there childs vp1 vp2 and uc1 uc2.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_BUF 1024
int main(){
int mypipe_c1[2];
int ret_c1;
char buf_c1[6];
ret_c1 =pipe(mypipe_c1);
int mypipe_c2[2];
int ret_c2;
char buf_c2[6];
ret_c2 =pipe(mypipe_c2);
if(ret_c1 == -1)
{
perror("pipe");
exit(1);
}
pid_t vc1;
pid_t vc2;
vc1 = fork ();
if (vc1 == 0)
{
read(mypipe_c1[0], buf_c1 , 37);
printf("PIPE1 :%s\n", buf_c1);
printf (" vc1 : I'm the child! My pid is (%d)\n", getpid ());
close(ret_c1);
int fd;
char * fifo1 = "/tmp/fifo1";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(fifo1, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("FIFO1: %s\n", buf);
close(fd);
exit(0);
}
if(vc1 < 0)
{
perror ("Ouch! Unable to fork() child process!\n");
exit (1);
}
vc2 = fork ();
if (vc2 == 0)
{
printf ("vc2 : I'm the child! My pid is (%d)\n", getpid ());
read(mypipe_c2[0], buf_c2 , 37);
printf("PIPE2 %s\n", buf_c2);
int fd;
char * fifo2 = "/tmp/fifo2";
/* create the FIFO (named pipe) */
mkfifo(fifo2, 0666);
/* write "Hi" to the FIFO */
fd = open(fifo2, O_WRONLY);
write(fd, " assignment VU 2 ", sizeof(" assignment VU 2 "));
close(fd);
/* remove the FIFO */
unlink(fifo2);
exit(0);
}
else if (vc2 < 0)
{
perror ("Ouch! Unable to fork() child process!\n");
exit (1);
}
printf ("I'm the parent! My pid is (%d)!\n",getpid());
write(mypipe_c1[1], "I am going to close you carry on UC1 \n", 37);
write(mypipe_c2[1], "I am going to close you carry on UC2 \n", 37);
exit(0);
}
Now I want shell script such that VP and UP should be started when users types … script.sh start VP or UP. vc1, vc2, uc1,uc2 should be stoppable only using script.sh stop vc1 or vc2 or uc1 or uc2
script.sh connect command should create two fifo and connect processes as shown in figure.
So you are asking for methods for IPC, with the sample code you provided, I think the best one is the use of pipes.
From the pipe() man page:
A pipe is a unidirectional data channel that can be used for interprocess communication
Basically, it is handled like a pair of file descriptors. First, you must init the pipe, and then create the childs using the fork() call, so both parents and childs share the resource. Then, using write and read methods, you can send data between them.
In this example I create a child which reads some data from the parent process:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int pid;
char buffer[255];
int fd[2]; // channel 0 for reading and 1 for writing
pipe(fd);
pid = fork();
if(pid == 0) {
close(fd[1]); // close fd[1] since child will only read
read(fd[0], &buffer, sizeof(buffer));
close(fd[0]);
exit(0);
} else { // parent
close(fd[0]) // close fd[0] since parent will only write
// init buffer contents
write(fd[1], &buffer, sizeof(buffer));
close(fd[1]);
}
return 0;
}
As you can see pipe creates a pair of file descriptors, one for writing (number 1) and one for reading (number 0).
In my sample code, the child process closes the writing one, since it will only read, and the parent closes the reading one, since it will only write data.
Note that pipes are unidirectional, so if you want that both the childs and the parent write and read data from it, you should create two pipes (so 4 file descriptors) for each of the childs. An example of how to handle that situation:
int pipeA[2], pipeB[2];
pid = fork();
if (pid == 0) { // child will write to pipeB and read from pipeA
close(pipeA[1]); // closing pipeA writing fd
close(pipeB[0]); // closing pipeB reading fd
write(pipeB[1],&buffer, sizeof(buffer));
read(pipeA[0], &buffer2, sizeof(buffer2));
close(pipeA[0]);
close(pipeB[1]);
exit(1);
} else { // parent will write to pipeA and read from pipeB
close(pipeA[0]); // closing pipeA reading fd
close(pipeB[1]); // closing pipeB writing fd
read(pipeB[0], &buffer, sizeof(buffer));
write(pipeA[1], &buffer2, sizeof(buffer2));
close(pipeA[1]);
close(pipeB[0]);
}
If you want more info about pipes you can check the man page here.
Also, other simple ways of IPC would be the use of Unix Sockets, although I think that for the example you presented pipes will be enough.
You'r code create one parent and one child, not two child, so you need to add another fork into child block :
#include <stdio.h>
void main()
{
int pid,status;
pid = fork();
if(pid == -1) {
printf(“fork failed\n”);
exit(1);
}
if(pid == 0) { /* Child */
fork();// another child
if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
printf(“exec failed\n”);
exit(1);
}
}
else { /* Parent */
wait(&status);
printf(“Well done kid!\n”);
exit(0);
}
}

Passing data from a parent to a child and back with Unix C

I am very new to C and am trying to learn how to use pipes to transfer data from a parent process to a child process and vice versa in a Unix environment. In the code below, I receive a command line argument and build a char array based on the argument's value. I then use pipes to pass the char array to a child which will execute a program called vc. This program returns a number result based on the char array. My question is how can I use a second pipe to get the result back to the parent? Also, once the parent has it, how can I print it to the screen since the parent is set to send output to the child? Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
int
pfildes[2],
pid,
argNumber;
char
buffer[256],
charString[1024];
//Check for arguments
if(argc != 2) {
printf("No command line arguements given.\n");
argNumber=10; //default
}
else
argNumber=atoi(argv[1]);
//***********************************
//Build charString based on argNumber
//***********************************
//create pipes
if(pipe(pfildes) == -1) {
//error occured when creating pipe
perror("demo");
exit(1);
}
//create child process
if((pid=fork()) < 0) {
//error occured when forking child
perror("demo");
exit(1);
}
else if(pid > 0) {
//parent process
close(pfildes[0]);
dup2(pfildes[1],1);
printf("%s", charString);
close(pfildes[1]);
perror("demo");
_exit(1);
}
else {
//child process
close(pfildes[1]);
dup2(pfildes[0],0);
execlp("/usr/bin/vc","vc", NULL);
close(pfildes[0]);
perror("demo");
exit(1);
}
while(wait(NULL) >0);
return 0;
}
You can use socketpair() instead of pipe() to generate a bidirectional communication channel between the parent and child process:
//...
if (socketpair(PF_UNIX, SOCK_STREAM, 0, pfildes) == -1) {
//error occured when socket pair
perror("demo: socketpair");
exit(1);
}
//..
In the child process, you can dup() one of the pair into both input and output before calling exec():
//...
else {
//child process
close(pfildes[1]);
dup2(pfildes[0],0);
dup2(pfildes[0],1);
dup2(pfildes[0],2);
close(pfildes[0]);
execlp("/usr/bin/vc","vc", NULL);
perror("demo: child exec");
exit(1);
}
//...
In the parent process, you can create a FILE * from a file descriptor using fdopen(), so you don't need to dup() over your existing stdout file descriptor:
//...
else if(pid > 0) {
//parent process
close(pfildes[0]);
FILE *to_child = fdopen(dup(pfildes[1]), "w");
FILE *from_child = fdopen(dup(pfildes[1]), "r");
close(pfildes[1]);
fprintf(to_child, "%s", charString);
while (fgets(buf, sizeof(buf), from_child) != NULL) {
//...do something with output
}
//...
} else { //...

process termination doesn't affect waitpid()

I need to simulate the following bash commands using C under Linux (with fork, exec, kill, signal, wait, waitpid, dup2, open, sleep, pipe etc).
[0] echo 'tail-f $1' > /tmp/rtail
[1]/tmp/rtail ~/.bash_history >> /tmp/1.txt &
PID of process [1] should be saved.
[2] Expect termination of the command started on step [1]. After termination print on the screen: "Program 1 terminated."
So far I have this code:
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc, char *argv[]) {
pid_t pID = fork();
if (pID == 0) // child
{
int file = open("/tmp/rtail", O_CREAT | O_WRONLY);
//Now we redirect standard output to the file using dup2
dup2(file, 1);
puts("tail -f $1");
close(file);
system("chmod 777 /tmp/rtail");
exit(0);
} else if (pID < 0) // failed to fork
{
printf("Failed to fork");
exit(1);
// Throw exception
} else // parent
{
pid_t pID2 = fork();
if (pID2 == 0) {
char tmp1[20];
sprintf(tmp1, "echo %i > /tmp/pidprog1", getpid());
system(tmp1);
int file = open("/tmp/1.txt", O_APPEND | O_WRONLY);
//Now we redirect standard output to the file using dup2
dup2(file, 1);
FILE* proc = popen("sh /tmp/rtail ~/.bash_history", "r");
char tmp[20];
while (fgets(tmp, 40, proc) != NULL) {
printf(tmp);
}
fclose(proc);
exit(0);
}
else if (pID2 < 0) // failed to fork
{
printf("Failed to fork");
exit(1);
// Throw exception
} else {
FILE* fl = fopen("/tmp/pidprog1", "r");
char buff[10];
fgets(buff, 10, fl);
int pidc = atoi(buff);
fclose(fl);
int status;
waitpid(pidc, &status, 0);
printf("Program 1 terminated\n");
}
}
// Code executed by both parent and child.
return 0;
}
The problem is that when I manually kill the process using PID saved into /tmp/pidprog1, parent process doesn't stop waiting and doesn't print "Program 1 terminated" line.
The parent is very likely reading a garbage value into pidc. You are doing nothing to ensure that the grandchild has actually written the pid before the parent tries to read it. You need to use wait to ensure that valid pids are in the file. (Or, just keep track of the pids from the return value of fork.)
You are not doing enough error checking: what happens if any open fails? (eg, when you try
to open /tmp/1.txt for appending but it doesn't already exist?)
Why are you using fgets to read 40 characters into a buffer of size 20?
Why are you dup'ing and using fputs instead of just writing to the fd?
Why are you printing error messages to stdout instead of stderr ( use perror ).

Resources