I'm a bit new to pipes and concurrency, and have been frustrated with this problem for hours. I am struggling to understand why this write operation is constantly failing on my pipe. I am trying to have the child process write data through a pipe that will be received by the parent process. My current code is this:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 4096
int main() {
pid_t status;
int fd[2]; //The array of file descriptors
if (pipe(fd) == -1) {
printf("Error piping");
}
status = fork(); //Begin the fork process
switch (status) {
case -1:
perror("Error forking");
break;
case 0:
//Child process
close(fd[0]); //Only send data
char some_string[15] = "hi there";
if (write(fd[1], some_string, MAXSIZE) == -1) {
printf("Error writing to the pipe");
}
close(fd[1]); //Close write end
exit(1);
default:
close(fd[1]); //Only receive data
char readed[500] = "";
while(read(fd[0], readed, MAXSIZE) != 0) {
printf("read this %s\n", readed);
}
printf("Done reading");
close(fd[0]);
break;
}
return 1;
}
However, I constantly get the message "Error writing to pipe", meaning that the write operation has failed in the child process. Another interesting thing is that if I change some_string to a string literal instead, this code works fine with the exception that it never terminates and instead, the read operation in the parent process reads from STDIN! I don't understand why this could be happening, is it possible that we have a zombie child when parent executes so the pipe is "dead"? Or perhaps that the parent process terminates and we have an orphaned child? How can I avoid this and how does this explain the weird behaviour from the string literal instead? Any insights?
You told write() to read the data from out-of-range of the array and allowed read() to write the data read to out-of-range of the array. That is very bad.
Write only valid data and limit the length to read not to cause out-of-range access.
Try this:
#include <unistd.h>
#include <sys/types.h> /* add this to use pid_t */
#include <sys/wait.h> /* add this to use wait() */
#include <stdio.h>
#include <stdlib.h>
/* remove unused MAXSIZE */
int main() {
pid_t status;
int fd[2]; //The array of file descriptors
int st; /* variable for receiving the status */
if (pipe(fd) == -1) {
printf("Error piping");
return 1; /* return 1 when the execution failed */
}
status = fork(); //Begin the fork process
switch (status) {
case -1:
perror("Error forking");
return 1; /* return 1 when the execution failed */
break;
case 0:
//Child process
close(fd[0]); //Only send data
char some_string[15] = "hi there";
if (write(fd[1], some_string, sizeof(some_string)) == -1) {
printf("Error writing to the pipe");
}
close(fd[1]); //Close write end
exit(0); /* return 0 if the execution finished successfully */
default:
close(fd[1]); //Only receive data
char readed[500] = "";
while(read(fd[0], readed, sizeof(readed) - 1) != 0) { /* -1 for reserving space for terminating null-character */
printf("read this %s\n", readed);
}
printf("Done reading");
close(fd[0]);
wait(&st); /* wait for the child process to exit and release the data of the process */
break;
}
return 0; /* return 0 if the execution finished successfully */
}
Related
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
int main(void){
//Variables, p[2] for each end of the pipe. nbytes to read pipe return value SUCCESS or FAILURE. pid_t to hold pid of fork process.
// buffer to hold response from the child process.
int p[2], nbytes;
pid_t childpid;
char string[] = "Hello, World!\n";
char buffer[80];
//Declaration of pipe
pipe(p);
//Error handling.
if(((childpid = fork()) == -1) || (pipe(p) == -1))
{
perror("fork");
exit(1);
}
//Child process sends message to paprent.
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(p[0]);
/* Send "string" through the output side of pipe */
write(p[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(p[1]);
/* Read in a string from the pipe */
nbytes = read(p[0], buffer, sizeof(buffer));
printf("Received string: %s", buffer);
}
return(0);
}
Output > Received string: #�=zJ
The point of the exercise is to have a child process send a message through a pipe to the parent process and the parent returns the result. This exact code worked the first time I ran it, but then when I tried to run it a second time it started to return seemingly random characters each time. I tried to copy my buffer to another variable but then it was empty. Is the pipe actually not function the way I think it is? What am I doing wrong?
You first create a pipe with pipe(p); and then you create another with ... || (pipe(p) == -1)) Is that deliberate?
2nd Pipe was causing an issue.
You have:
pipe(p);
//Error handling.
if(((childpid = fork()) == -1) || (pipe(p) == -1))
{
perror("fork");
exit(1);
}
This creates two pipes — one in the line pipe(p); and the second in the condition if(((childpid = fork()) == -1) || (pipe(p) == -1)). This is wasteful at best. Moreover, the second pipe is after the fork(), so the parent and child processes don't access the same pipe any more — you overwrote the one created before the fork() which they do share. Test the result of pipe() before calling fork() and remove the extra condition in the if test:
if (pipe(p) != 0)
{
perror("pipe");
exit(1);
}
if ((childpid = fork()) < 0)
{
perror("fork");
exit(1);
}
Get used to testing for errors and writing appropriate code to handle them. It will be a major part of your life as a C programmer.
Later on in the code, you have:
{
/* Parent process closes up output side of pipe */
close(p[1]);
/* Read in a string from the pipe */
nbytes = read(p[0], buffer, sizeof(buffer));
printf("Received string: %s", buffer);
}
You need to heed the value of nbytes. Since it is an int, you could use:
printf("Received %d bytes: [%.*s]\n", nbytes, nbytes, buffer);
This limits the output to what was read, and reports 0 if that's what it gets. I suppose you should also check for -1 in nbytes before using it in the printf() statement:
if (nbytes < 0)
{
fprintf(stderr, "failed to read from pipe descriptor %d\n", p[0]);
// Or perror("read");
// Should you exit here with a non-zero status?
}
else
printf("Received %d bytes: [%.*s]\n", nbytes, nbytes, buffer);
Note: errors are reported on stderr; perror() does that automatically.
The problem is that you create two pipes when you really only need to check the first for errors:
// Declaration of pipe
if(pipe(p) == -1) { // check for error here
perror("pipe");
exit(1);
}
// Error handling.
if((childpid = fork()) == -1) { // and don't create another pipe here
perror("fork");
exit(1);
}
You should also check the return values from write and read. They may not write or read the full string in one go.
I am working on a program where the main program forks itself and the child process calls exec. I have set it up so that the parent process has 2 pipes StdOutPipe and StdInPipe, and the child process calls dup so that stdout writes to the StdOutPipe and stdin reads from StdInPipe. Then the parent process calls wait, after which i would like to read the entirety of the StdOutPipe into a buffer. I know you can do so by reading one character at a time, but is there a faster way to do so?
For performance reasons, one typically reads a chunk at a time, not a character at a time.
Loop,
Attempt to enlarge the buffer so it can fit CHUNK_SIZE more bytes.
If an error occurred,
Fail.
Attempt to read CHUNK_SIZE bytes from the pipe into the unused part of the buffer.
If an error occurred,
Fail.
If EOF was reached,
Break.
Increased the total number of bytes read by the number of bytes read.
A pipe is basically a byte stream which means:
There's no concept of messages or message boundaries with pipes
The process reading from a
pipe can read blocks of data of any size, regardless of the size of blocks written by
the writing process
A read from a pipe is usually blocked until atleast a byte is written to the pipe.
That said, here's how i would implement your issue.
Create two pipes, stdinpipe and stdoutpipe
Do a fork
Parent process should close the write end of the pipes and sit in a
loop, waiting until data is written to pipe
Child process should close the read end of the pipes and duplicate
STDOUT to stdoutpipe and STDIN to stdinpipe
Child process can then do an exec.
Sample code:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define STDPIPE_BUFFER_SIZE 4096
#define ARGV_SIZE 3
int main()
{
// Stdoutpipe and stdint pipe
int stdoutpipe[2], stdinpipe[2], stdin_char_count, stdout_char_count, stdout_read, stdin_read;
pid_t pid;
char stdinbuffer[STDPIPE_BUFFER_SIZE], stdoutbuffer[STDPIPE_BUFFER_SIZE];
char *argv[ARGV_SIZE]; // arguments to exec
if (pipe(stdinpipe) == -1 || pipe(stdoutpipe) == -1)
exit(1); // error occurred
// Fork and exec
switch (pid = fork())
{
case -1:
exit(1); // error
case 0:
// child close the read end of both pipes
if (close(stdinpipe[0]) == -1 || close(stdoutpipe[0]) == -1)
exit(1);
// have the pipes as the new STDIN and STDOUT
if (dup2(stdinpipe[1], STDIN_FILENO) == -1 || dup2(stdoutpipe[1], STDOUT_FILENO) == -1)
exit(1);
argv[0] = "/usr/bin/ssh"; // replace with your own program [ssh -V in my case]
argv[1] = "-V";
argv[2] = NULL;
execve(argv[0], argv, NULL);
exit(1); // if we get here something horribly bad happened
default:
// parent process
stdin_char_count = 0;
stdout_char_count = 0;
// parent close write end of both pipes
if (close(stdinpipe[1]) == -1 || close(stdoutpipe[1]) == -1)
exit(1);
for (;;)
{
stdin_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
stdout_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
if (stdin_read == 0 && stdout_read == 0)
{
stdinbuffer[stdin_char_count] = '\0';
stdoutbuffer[stdout_char_count] = '\0';
break;
}
if (stdin_read == -1 && stdout_read == -1)
exit(1); // we cant recover from this
stdin_char_count += stdin_read;
stdout_char_count += stdout_read;
}
printf("%s\n", stdoutbuffer);
wait(NULL);
}
}
source: https://man7.org/linux/man-pages/man2/pipe.2.html
You can convert the pipe into an ordinary stream and then use whatever function you find convenient to read the data. Here, getdelim() can be used to read all text up to a NUL byte which need not be sent over the pipe. Error checking is partially omitted for brevity.
Also be aware that if you want to continue interacting directly with the pipe even after opening the stream, you'll probably want to disable buffering on the stream.
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int fds[2];
if(pipe(fds) == -1) {
perror("Failed to create pipe");
exit(EXIT_FAILURE);
}
const pid_t pid = fork();
if(pid == -1) {
perror("Failed to fork");
exit(EXIT_FAILURE);
}
if(!pid) {
close(fds[0]);
const char *const msg = "Hello, world!";
if(write(fds[1], msg, strlen(msg)) == -1) {
perror("Failed to write");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
close(fds[1]);
FILE *const stream = fdopen(fds[0], "r");
if(!stream) {
perror("Failed to create stream");
exit(EXIT_FAILURE);
}
char *text = NULL;
assert(wait(NULL) != -1);
getdelim(&text, &(size_t){0}, '\0', stream);
fclose(stream);
assert(text);
puts(text);
free(text);
}
I have written a program where the parent process creates two child processes.
The parent process writes to either the first or the second child and the child reads the message.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main(){
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a,child_b;
if(pipe(p1) == -1){
printf("error in creating pipe\n");
exit(-1);
}
if(pipe(p2) == -1){
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO,msgbuf,MSGSIZE);
printf("%d receives message: %s\n",getpid(),msgbuf);
close(p1[0]);
close(p1[1]);
} else {
child_b = fork();
if (child_b == 0) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO,msgbuf,MSGSIZE);
printf("%d receives message: %s\n",getpid(),msgbuf);
close(p2[0]);
close(p2[1]);
} else {
/* Parent Code */
// Write something to child A
while(1){
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s",&choice,msgbuf);
switch(choice){
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
// Write something to child B
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
case -1:
usleep(250);
printf("parent waiting");
wait(NULL);
exit(-1);
break;
}
}
}
}
return 0;
}
My issue is that I want the parent to keep writing to the child process. With the above code, once it writes to child or child 2 it wont write again or at least the child process wont read it again. I don't know if it is possible to do this.
I tried putting the while loop at the beginning of the program but this causes another child process to be created every time.
Here my solution, followed by some explanation:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <assert.h>
#define MSGSIZE 64
void read_process(int fh) {
assert(-1 < fh);
char msgbuf[MSGSIZE];
ssize_t retval = 0;
while (-1 < retval) {
retval = read(fh, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(fh);
}
}
void write_process(int fh_child_1, int fh_child_2) {
assert(-1 < fh_child_1);
assert(-1 < fh_child_2);
char msgbuf[MSGSIZE];
int choice = -1;
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %64s", &choice, msgbuf);
switch (choice) {
case 1:
write(fh_child_1, msgbuf, MSGSIZE);
break;
// Write something to child B
case 2:
write(fh_child_2, msgbuf, MSGSIZE);
break;
case -1:
printf("parent waiting");
wait(NULL);
exit(-1);
break;
}
}
}
int main() {
/* 0 will be for reading, 1 for writing */
int p1[2];
int p2[2];
pid_t pid;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
/* Don't create 2nd pipe yet, we don't require it here and save us to
* tear it down in child 1 */
pid = fork();
if (pid == 0) {
close(p1[1]); /* not needed here */
p1[1] = -1;
read_process(p1[0]);
exit(EXIT_SUCCESS);
} else {
/* Nobody is going to read from pipe 1 here again */
close(p1[0]);
p1[0] = -1; /* Mark fh as invalid */
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
pid = fork();
if (pid == 0) {
close(p1[1]);
p1[1] = -1;
close(p2[1]);
p2[1] = -1;
/* Ensure we did not forget an fh */
assert(-1 == p1[0]);
assert(-1 == p1[1]);
assert(-1 == p2[1]);
read_process(p2[0]);
exit(EXIT_SUCCESS);
} else {
/* Parent Code */
close(p2[0]);
p2[0] = -1;
assert(-1 == p1[0]);
assert(-1 == p2[0]);
write_process(p1[1], p2[1]);
exit(EXIT_SUCCESS);
}
}
return 0;
}
As noted before, your main problem was that your children processes don't loop but read just once.
There are a few notes, I will first talk about the general ones, and then the more system programming specific ones afterwards.
Your main problem, the missing loops, was hidden below your code being a bit spaghetti.
C provides means for structuring your code, like functions.
Functions are not only there for re-using code, but can also be used to summarize your code: Instead of pasting the code for your child processes directly where you require it, shift the code to a dedicated function and just call the function. This aids greatly in understanding the basic structure of the code:
close(p1[1]); /* not needed here */
p1[1] = -1;
read_process(p1[0]);
exit(EXIT_SUCCESS);
is pretty obvious what is the basic idea, isn't it? And if you want the gory details of the read process, inspect the read_process function.
Be careful about your resources.
Allocate as few as possible, only when you need them. Free them as soon as possible and mark them as freed - see the pipe file handles.
Lastly, if you fork, the process is basically copied. You create a second process, and it is given copies/ clones of all (well, most) of the parent processes resources.
The file handles in your case, are cloned.
E.g. closing p1[0] in your child does not affect p1[0] in your parent, because they are not the same.
That also means, that immediately after forking, you should consider all the resources available and get rid of every resource you wont require immediately, like
pid = fork();
if(0 == pid) {
close(p1[1]); /* not needed here */
p1[1] = -1;
read_process(p1[0]);
exit(EXIT_SUCCESS);
}
Your first child does not require p1[1], thus close it and mark it as closed and invalid.
There is probably much more to say, but these are the points that come to my mind immediately.
Some of it might not seem clumsy, but as you get more and more experienced, and your code bases grow, you will appreciate these things, at least I do more and more every day.
As for the code, there are certainly many bugs still hiding in there, you get the basic idea though I hope ;)
Sorry for the length of this post... I've encountered about a zillion problems in this. Up front I'll say I'm a student and my professor is a worthless resource. So, all I want to to do is have producer fork, then the parent producer will count some stuff in a file and send two ints to consumer, which was launched by the child process. I've tested everything, the fork and the file stuff works and I have printf statements all over the place so I know what is being done and where the code is at.
When I added the
if (pipe(pipefd) == -1) {
perror("pipe");
}
it caused my parent to just terminate. It reaches "parent pipe open" but then it dies. I checked with $ ps to see if it was just hung, but it's not there; it just dies. If I take that snippet out, it runs to the end but I presume if that code isn't there, then it's not actually aware that pipefd is a pipe... right?
I did search on this site and found another example of this and followed what he did as well as the answer and mine just refuses to work. I'm pretty sure it's a trivially easy thing to fix but I've run out of ideas of what to try :(
I don't really want to post all my code because it'll be a huge wall of text but I don't want to accidentally cut something out that turns out to be important either.
producer.c
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork, execl */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
#include <sys/wait.h> /* wait */
#define SLEEP_TIME 8
int main (int argc, char *argv[]){
//PID
pid_t local_pid;
local_pid = fork();
//Logic to determine if the process running is the parent or the child
if (local_pid == -1) {
/* Error:
* When fork() returns -1, an error happened
* (for example, number of processes reached the limit).
*/
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
} else if (local_pid == 0) {
//Child specific code
int child;
char *temp[] = {NULL};
printf("Child PID found\n");
child = execv("./consumer", temp);
_exit(0);
} else {
//Parent specific code
printf("Parent running\n");
//open file
FILE * randStrings;
randStrings = fopen("randStrings.txt", "r");
int file_length;
int num_of_e = 0;
int c; //using this as a char
//until eof
while (feof(randStrings) == 0) {
c = fgetc(randStrings);
//calculate length of file
file_length++;
//count e chars
if (c == 'e') {
num_of_e++;
}
}
//close file
fclose(randStrings);
//send bundle to child
int a[2];
a[0] = num_of_e;
a[1] = file_length;
printf("num of e = %i\n", a[0]);
printf("len = %i\n", a[1]);
//set up parent pipe
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
printf("x\n");
}
printf("parent pipe open\n");
close(pipefd[0]); //close the read end
write(pipefd[1], &a[0], sizeof(int));
write(pipefd[1], &a[1], sizeof(int));
close(pipefd[1]);
printf("parent pipe closed\n");
//wait for child to finish running
wait(NULL);
printf("parent out\n");
//terminate
}
}
and consumer.c
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork, execl */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
#define SLEEP_TIME 5
int main (int argc, char *argv[]){
sleep(SLEEP_TIME);
printf("Child program launched\n");
//receive bundle
int pipefd[2];
int buf[2];
if (pipe(pipefd) == -1) {
perror("pipe");
printf("child x\n");
}
close(pipefd[1]); //child closes write end
buf[0] = 0;
buf[1] = 0;
/*int i = 0; // i dont like this
while (read(pipefd[0], &buf[i], sizeof(int)) > 0) {
i++;
}*/
printf("child reading pipe\n");
read(pipefd[0], &buf[0], sizeof(int));
read(pipefd[0], &buf[1], sizeof(int));
close(pipefd[0]);
//buf should have the stuff in it
int num_of_e = buf[0];
int file_length = buf[1];
printf("child num of e = %i\n", num_of_e);
printf("child len = %i\n", file_length);
//open file
FILE * resultStrings;
resultStrings = fopen("resultStrings.txt", "w");
for (int i = 0; i < num_of_e; i++) {
//write num_of_e e chars
fputc('e', resultStrings);
}
//or if no e chars, write - chars
if (num_of_e == 0) {
for (int i = 0; i < file_length; i++) {
//write file_length '-' chars
fputc('-', resultStrings);
}
}
//close file
fclose(resultStrings);
printf("child out\n");
}
if you're still here after all that, you deserve a thank you just due to the length of this.
You're doing it wrong. The whole mechanism works because a child process inherits the parent's open file descriptors.
It should go like this:
Open the pipe with pipe(pipefd)
fork()
Parent (producer):
closes the read side (pipefd[0])
writes to the write side (pipefd[1])
Child (consumer):
closes the write side (pipefd[1])
reads from the read side (pipefd[0]) or calls exec
You are opening distinct pipes in both the parent and child process (after you've forked.) It needs to happen before you fork.
Now since you're execing, the new process needs to be aware of read-only pipe. There are a couple ways you could do this:
Pass it the file descriptor number (pipefd[0]) on the command line
dup2(1, fd) it to be the stdin of the newly exec'd process
I am trying to create a child that calls sort. The parent sends data to the child through a pipe. My code compiles and runs, but there is no output. What am I doing wrong? Am I not closing the pipes correctly, writing the pipes or outputting the data correctly?
[eddit] On my system I need to call /bin/sort NOT /usr/bin/sort!
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>
int main(void){
int pipes[2];
pid_t pid;
FILE *stream;
if(pipe(pipes) == -1)
printf("could not create pipe\n");
switch(fork()){
case -1:
fprintf(stderr, "error forking\n");
break;
case 0:
dup2(pipes[0], STDIN_FILENO);
pid = getpid();
printf("in child, pid=%d\n");
if(close(pipes[1]) == -1)
fprintf(stderr,"err closing write end pid=%d\n", pid);
execl("/usr/bin/sort", "sort", (char*) NULL);
break;
default:
stream = fdopen(pipes[1], "w");
pid = getpid();
printf("in parent, pid=%d\n", pid);
if (stream == NULL)
fprintf(stderr, "could not create file streami\n");
if(close(pipes[0]) == -1)
printf("err closing read end pid=%d\n");
fputs("bob\n",stream);
fputs("cat\n",stream);
fputs("ace\n",stream);
fputs("dog\n",stream);
if(fclose(stream) == EOF)
fprintf(stderr, "error while closing stream\n");
break;
}
return 0;
}
[edit] Here is my working code. Thank you everyone
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void){
int pipes[2];
pid_t pid;
FILE *stream;
int stat;
if(pipe(pipes) == -1)
printf("could not create pipe\n");
switch(fork()){
case -1:
fprintf(stderr, "error forking\n");
break;
case 0:
dup2(pipes[0], STDIN_FILENO);
pid = getpid();
printf("in child, pid=%d\n", pid);
if(close(pipes[1]) == -1)
fprintf(stderr,"err closing write end pid=%d\n", pid);
if(close(pipes[0]) == -1)
fprintf(stderr,"err closing write end pid=%d\n", pid);
execl("/bin/sort", "sort", (char*) NULL);
exit(EXIT_FAILURE);
break;
default:
stream = fdopen(pipes[1], "w");
pid = getpid();
printf("in parent, pid=%d\n", pid);
if (stream == NULL)
fprintf(stderr, "could not create file streami\n");
if(close(pipes[0]) == -1)
printf("err closing read end pid=%d\n");
fputs("bob\n",stream);
fputs("cat\n",stream);
fputs("ace\n",stream);
fputs("dog\n",stream);
if(fclose(stream) == EOF)
fprintf(stderr, "error while closing stream\n");
break;
}
wait(&stat);
return 0;
}
You most certainly do not have enough close() calls in the code, which will lock the processes up.
Pseudo code:
Create pipe
Fork
In parent:
Close read end of pipe
Write data to be sorted down write end of pipe
Close write end of pipe
Wait for child to die
In child
Close write end of pipe
Duplicate read end of pipe to stdin
Close read end of pipe
Exec the sort program
Exit with an error if the exec returns
Note that the pseudo code ends up closing all four ends of the pipe - the two in the parent and the two in the child. If you don't do that, you will run into deadlock.
The only thing you're really missing is calling wait() or waitpid() at the end of the parent's code, so that it doesn't exit until the child has finished.
No arguments to sort command. Simply running an execl will not work.
A simple program to test would be:
int main(void){
execl("/bin/sort","/bin/sort","filename", (char*) NULL);
}
I will try to create a simple program for you to analyze the situation.
Here you go, try this code:
int main(void){
int pipefd[2];
pid_t pid = 0;
int status;
char data[100]={0};
int fildes[2] ;
int nbytes;
char buf[100]={0};
status = pipe(fildes);
if (status == -1 ) {
// handle eerrror.
}
switch (fork()) {
case -1: /* Handle error */
break;
case 0: /* Child - reads from pipe */
close(fildes[1]); /* Write end is unused */
nbytes = read(fildes[0], buf, 100); /* Get data from pipe */
fprintf(stderr,"Inside child val recieved is %s\n", buf);
/* At this point, a further read would see end of file ... */
execl("/bin/sort", "/bin/sort",buf, (char*) NULL);
close(fildes[0]); /* Finished with pipe */
exit(0);
default: /* Parent - writes to pipe */
close(fildes[0]); /* Read end is unused */
write(fildes[1], "file", strlen("file")); /* Write data on pipe */
close(fildes[1]); /* Child will see EOF */
exit(0);
}
}
Here "file" is a file which need to be sorted.
Hope you can customize it as per your need.
Enjoy..!!!