I wrote the following code in order to use pipes in c unix:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
int main ()
{
int fds[2];
pid_t pid;
/* Create a pipe. File descriptors for the two ends of the pipe are
placed in fds. */
pipe (fds);
/* Fork a child process. */
pid = fork ();
if (pid == (pid_t) 0) {
//char abc[10]; - **Uncommenting this cause the program not to work.**
/* This is the child process. Close our copy of the write end of
the file descriptor. */
close (fds[1]);
// Read params
FILE * stream;
stream = fdopen (fds[0], "r");
char* args[4]={"avg3.out","4","3","5"};
/* Replace the child process with the “avg3” program. */
execv("avg3.out", args);
} else {
/* This is the parent process. */
FILE* stream;
/* Close our copy of the read end of the file descriptor. */
close (fds[0]);
/* Convert the write file descriptor to a FILE object, and write
to it. */
dup2(fds[0], STDOUT_FILENO);
stream = fdopen (fds[1], "w");
fprintf (stream, "5 4 3");
fflush (stream);
close (fds[1]);
/* Wait for the child process to finish. */
waitpid (pid, NULL, 0);
}
return 0;
}
avg3.out is a file I compiled before. It simply calculate the average of the 3 params sent to it.
The output was 4, but when I tried to actually read from the stream, I added a declaration for char buffer[10] The code stopped working. That is, no output provided. I tried to rename it, to move the decleration to the start of the if statement. but nothing worked.
So, why does the program stop working when adding just an array declaration?
The parameter-array to go with calls to exec*() needs to be (char*)NULL-terminated.
This line
char* args[4]={"avg3.out","4","3","5"};
should be
char* args[] = {"avg3.out", "4", "3", "5", NULL};
As it isn't in your code, exec() might get lost searching for it.
By bad luck the stack might have been clean (0 filled) for the version of your code not declaring a and execv() found a NULL right after the pointer pointing to "5". Having a created on the stack then changed the content of the stack which made execv() getting lost searching for the NULL.
Additionally its worth mentioning that the OP's code misses error checking on most of the relevant system call.
Having done so together with a detailed examation of the errors' causes, probably by using calls to perror() might have led to solving this issue by providing relevant information.
In particular placing it after the call to execv() it soon would have been obvious what's wrong:
execv("avg3.out", args);
perror("execv() failed");
Related
I would like to run an external command from a C program. Let's say, as minimal working example, that I want to run the 'cat' command. I use use fork() and execl() to spawn the new process, and I communicate with it via pipes.
Now that's where my problem is. In a terminal I would tell 'cat' that I am done with my input by pressing CTRL-D. Here I am trying to do so by closing the file descriptor -- see the line with close(outpipefd[1]) in the code below -- but this does not seem to work. My code stalls as 'cat' is waiting for more input.
My code is as follows... What am I doing wrong? Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
int main(void)
{
pid_t pid=0;
int inpipefd[2];
int outpipefd[2];
/*
We create the pipes for communicating with the child process
*/
pipe(inpipefd);
pipe(outpipefd);
if((pid=fork())==0)
{
/*
Child
*/
dup2(outpipefd[0],STDIN_FILENO);
dup2(inpipefd[1],STDOUT_FILENO);
dup2(inpipefd[1],STDERR_FILENO);
/*
We spawn the process
*/
execl("/bin/cat","cat",(char *)(NULL));
/*
Nothing below this line should be executed by child process.
If so, it means that the execl function wasn't successfull, so lets exit!
*/
exit(1);
}
/*
Parent.
Close unused pipe ends.
*/
close(outpipefd[0]);
close(inpipefd[1]);
/*
Now we can write to outpipefd[1] and read from inpipefd[0]
*/
char *greeting="Hello world!\n";
write(outpipefd[1],greeting,strlen(greeting));
/*
Here I believe that closing the pipe should be equivalent to
pressing CTRL-D in a terminal, therefore terminating the cat command...
This is unfortunately not the case!
*/
close(outpipefd[1]);
while(1)
{
char buf[256];
for(int c=0;c<256;c++)
buf[c]=0;
if(read(inpipefd[0], buf, 256)<=0)
break;
printf("OUTPUT: %s\n", buf);
}
/*
Send SIGKILL signal to the child process
*/
int status;
kill(pid, SIGKILL);
waitpid(pid, &status, 0);
return 0;
}
The child still has both ends of both pipes opened, because you never closed any of your FDs in it. Until every FD referring to the write end of a pipe is closed, it won't return EOF.
You have also to close the unused pipe ends in the child, or there will be still things open that block the other end. close what you don't use in parent and child, and you will get the EOFs.
My program creates child process and sets pipes to communicate with it. The problem occurs when i try to read data from the pipe. Since child process has ended (i use wait to ensure that) EOF should be on the end of the data stream thus ending the read (As in the man page for pipe). But instead read just freezes and waits for more data to come.
What am i missing here?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void setfd(int *in, int *out) {
dup2(out[1], 1);
dup2(in[0], 0);
}
int main(int argc, char *argv[]) {
int status;
int pipe2ch[2], pipe2pr[2];
char *newargv[] = {NULL, NULL};
newargv[0] = argv[1];
pipe(pipe2ch);
pipe(pipe2pr);
setfd(pipe2pr, pipe2ch);
int a;
if (!(a = fork())) {
setfd(pipe2ch, pipe2pr);
execve(newargv[0], newargv, NULL);
exit(1);
} else {
printf("hello!\n");
fflush(stdout);
char str;
wait(&status);
while (read(pipe2pr[0], &str, 1) > 0) {
fprintf(stderr, "%c", str);
}
exit(0);
}
}
Since child process has ended (i use wait to ensure that) EOF should be on the end of the data stream thus ending the read (As in the man page for pipe).
I'm not sure what you've read to suggest that. Or maybe it's your wording that I don't understand. EOF is not a character on the stream.
But instead read just freezes and waits for more data to come. What am i missing here?
Several things. The most important one is probably that when a process forks, the child's copies of the parent's open file descriptors refer to the same entries in the kernel's underlying table of open files as the parent's do, each of which remains open until all handles on it are closed. The child closes all its file descriptors when it exits, but both ends of both pipes remain open in the parent, so end-of-file will not be signaled to readers. Each process must close the pipe ends it doesn't use or is finished using.
Additionally, you should read() first, then wait(), for if the child process writes enough data to the pipe then it may block, and if the parent does not read until after the child exits then you'll have a deadlock.
Furthermore, I don't see any reason to dupe either pipe end onto the parent's standard streams (resulting in closing the original ones). Just manipulate the pipes via their file descriptors, as you already half do. If you want a stream interface to those, then use fdopen() to get one.
I am writing C program which constantly generates two string values named stateName and timer (with the rate of five times per second). I need to concatenate and pass them to another process called ProcessNo3_TEST which is responsible for tokenizing and also displaying them.
The problem is I don't know how to pass them continuously via execl. I had a couple of attempts but none of them were successful. Here is my code which works fine for a single pair of values (e.g. UP2 and 98):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define READ 0
#define WRITE 1
int FIFO[2];
char fileDescriptor[10];
char* stringMaker( char *s1,char *s2 );
int main()
{
char lengthInChar[15],msg[200];
int msgLength,i;
char *stateName, *timer;
if (pipe(FIFO) == -1)
{
printf("cannot create pipe\n");
exit(1);
}
sprintf(fileDescriptor, "%d", FIFO[READ]);
stateName = "UP2"; // for instance
timer = "98"; // for instance
msgLength = strlen(stateName) + strlen(timer) +3;
strcpy(msg, stringMaker(stateName, timer) );
write(FIFO[WRITE], msg, msgLength);
switch (fork())
{
case 0:
sprintf(lengthInChar, "%d", msgLength);
execl("ProcessNo3_TEST", "ProcessNo3_TEST", lengthInChar, fileDescriptor, NULL);
exit(1);
case -1:
perror("fork() failed-->");
exit(2);
default:
break;
}
sleep(10);
exit(0);
}
char* stringMaker( char *s1,char *s2 )
{
char *s3;
strcpy(s3,s1);
strcat(s3,"-");
strcat(s3,s2);
strcat(s3,"-");
strcat(s3,"\0");
return s3;
}
Can anyone help on this please?
(I am running CygWin on Windows by the way)
----------UPDATE-------------
As advised in comments below, I found a good example of fdopen() which solved my problem. (Link)
Although one can arrange to pass one pipe end's file descriptor number (in string form) as a program argument, normally one would instead redirect the child process's standard streams to read from (in this case) or write to the pipe. This is usually achieved via dup2(), which you would apply in the child process, after forking but before execl().
Parent and child processes then communicate via the pipe. In this case, the parent writes to the writing end and the child reads from the reading end. Either or both can wrap their file descriptor in a stream by passing it to fdopen(). Then you can use stdio functions with it. Note, too, that after the fork, each process should close the FD for the pipe end it does not intend to use.
If are set on using execl() (often people prefer not to, but sometimes it has it's benefits) than you should use named pipes instead of unanonymous. Anononymous pipe end is lost after execl(). But if you have a named pipe, you can pass it's name as an argument to the execl(), open it in child process and use there.
I want to learn how Linux pipes work! I wrote a small and easy program that use a pipe to communicate a string between parent and child process. However, the program results in a dead lock that I have not understood what is its cause.
Here is the code :
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define SIZE 100
int
main(int argc, char *argv[])
{
int pfd[2];
int read_pipe=0, write_pipe=0;
pid_t cpid;
char buf[SIZE];
/* PIPE ***************************************
* pipe() creates a pair of file descriptors, *
* pointing to a pipe inode, and places them *
* in the array pointed to by filedes. *
* filedes[0] is for reading, *
* filedes[1] is for writing *
**********************************************/
if (pipe(pfd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
read_pipe=pfd[0];
write_pipe=pfd[1];
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
char * hello = "I am a child process\n";
sleep(1);
// wait until there is some data in the pipe
while (read(read_pipe, buf, SIZE) > 0);
printf("Parent process has written : %s\n", buf);
write(write_pipe, hello, strlen(hello));
close(write_pipe);
close(read_pipe);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
char * hello = "I am a parent process\n";
write(write_pipe, hello, strlen(hello));
while (read(read_pipe, buf, SIZE) > 0);
printf("Child process has written : %s\n", buf);
close(write_pipe);
close(read_pipe);
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
In this link you'll find the proper mannipulation of PIPEs between parent and child. Your problem here is that the communication is not being correctly set-up.
The PIPE should be used to communicate in only one direction, so one process has to close the read descriptor and the other has to close the write descriptor. Otherwise what will happen is that the call to 'read'(both on the father and the son), since it can detect that there is another process with an open write descriptor on the PIPE, will block when it finds that the PIPE is empty (not return 0), until someone writes something in it. So, both your father and your son are getting blocked on their respective read.
There are two solutions to this:
.You create two PIPEs, one for the communication in each direction, and perform the initialization as explained in the link above. Here you have to remember to close the write descriptor when you are done sending the message, so the other process' read will return, or condition the loop to the count of bytes read (not to the return of read), so you won't perform another call when you read the whole message. For example:
int bread = 0;
while(bread < desired_count)
{
bread += read(read_pipe, buf + bread, SIZE - bread);
}
.You create one PIPE as you did, and modify the flags on the read descriptor, using fcntl to also have O_NONBLOCK, so the calls to read won't block when there's no information in the PIPE. Here you need to check on the return value of the read to know you received something, and go adding up until you get the full length of the message. Also you will have find a way to synchronize the two processes so they won't read messages that are not meant for them. I don't recommend you to use this option, but you can try it if you want using condition variables.
Maybe you can tell if you see any of yout printf() outputs?
Anyway, if you want to establish a two way communication between your paent and child, yout should use two pipes, one for writing data form parent to child an the other for writing from child to parent. Furthermore, your read loops may be dangerous: if the data comes in two or more chunks the second read() overwrites the first portion (I've never seen tha happen with local pipes, but for example with sockets). And of course, yout is not automatically null terminated after read(), so just printing int with "%s" may also cause problems.
I hope that gives you some ideas to try.
This question already has answers here:
Execute program from within a C program
(6 answers)
Closed 8 years ago.
How do I run another program from within my C program, I need to be able to write data into STDIN(while execution of program i have to provide input through stdin more than once) of the programed launched (and read line by line from it's STDOUT)
I need the solution to work under Linux.
while going through net i found below code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
void error(char *s);
char *data = "Some input data\n";
main()
{
int in[2], out[2], n, pid;
char buf[255];
/* In a pipe, xx[0] is for reading, xx[1] is for writing */
if (pipe(in) < 0) error("pipe in");
if (pipe(out) < 0) error("pipe out");
if ((pid=fork()) == 0) {
/* This is the child process */
/* Close stdin, stdout, stderr */
close(0);
close(1);
close(2);
/* make our pipes, our new stdin,stdout and stderr */
dup2(in[0],0);
dup2(out[1],1);
dup2(out[1],2);
/* Close the other ends of the pipes that the parent will use, because if
* we leave these open in the child, the child/parent will not get an EOF
* when the parent/child closes their end of the pipe.
*/
close(in[1]);
close(out[0]);
/* Over-write the child process with the hexdump binary */
execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL);
error("Could not exec hexdump");
}
printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid);
/* This is the parent process */
/* Close the pipe ends that the child uses to read from / write to so
* the when we close the others, an EOF will be transmitted properly.
*/
close(in[0]);
close(out[1]);
printf("<- %s", data);
/* Write some data to the childs input */
write(in[1], data, strlen(data));
/* Because of the small amount of data, the child may block unless we
* close it's input stream. This sends an EOF to the child on it's
* stdin.
*/
close(in[1]);
/* Read back any output */
n = read(out[0], buf, 250);
buf[n] = 0;
printf("-> %s",buf);
exit(0);
}
void error(char *s)
{
perror(s);
exit(1);
}
but this code is working fine if my C program(which needs to be executed usng exec) is reading input only once from stdin and returns output
once .but if my Cprogram(which needs to be executed usng exec) is taking input more than once(dont know exactly how many times it will read input from stdin)
and display output put mork than once(while execution display output line by line on stdout)
then this code is crashing. can any body suggest how to solve this problem?
Actually my C program(which needs to be executed usng exec) is displaying some output line by line and depending upon output i have to provide input on stdin
and number of this read/write is not constant.
Please help me resolve this issue.
You can use the select api to get notified when you can read/write a file descriptor.
So you would basically put your read and write calls into a loop, and run select to find out when the external program consumed some bytes or wrote something to stdout.