How to pipe stdin to a child and execl cat in C - c

In the code below, I am simply trying to send a file via stdin to a child process which will exec the cat OS command. The code compiles fine. Here is how I call it from the command line:
$ ./uniquify < words.txt
However, when I run it I get a seg fault error. I am really having a hard time understanding how the flow if information is supposed to work through pipes to children. I am trying to make the code as simple as possible, so I can understand it, but it is not yet making sense. Any help would be appreciated.
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define NUM_CHILDREN 2
int main(int argc, char *argv[])
{
pid_t catPid;
int writeFds[NUM_CHILDREN];
int catFds[2];
int c = 0;
FILE *writeToChildren[NUM_CHILDREN];
//create a pipe
(void) pipe(catFds);
if ((catPid = fork()) < 0) {
perror("cat fork failed");
exit(1);
}
//this is the child case
if (catPid == 0) {
//close the write end of the pipe
close(catFds[1]);
//close stdin?
close(0);
//duplicate the read side of the pipe
dup(catFds[0]);
//exec cat
execl("/bin/cat", "cat", (char *) 0);
perror("***** exec of cat failed");
exit(20);
}
else { //this is the parent case
//close the read end of the pipe
close(catFds[0]);
int p[2];
//create a pipe
pipe(p);
writeToChildren[c] = fdopen(p[1], "w");
} //only the the parent continues from here
//close file descriptor so the cat child can exit
close(catFds[1]);
char words[NUM_CHILDREN][50];
//read through the input file two words at a time
while (fscanf(stdin, "%s %s", words[0], words[1]) != EOF) {
//loop twice passing one of the words to each rev child
for (c = 0; c < NUM_CHILDREN; c++) {
fprintf(writeToChildren[c], "%s\n", words[c]);
}
}
//close all FILEs and fds by sending and EOF
for (c = 0; c < NUM_CHILDREN; c++) {
fclose(writeToChildren[c]);
close(writeFds[c]);
}
int status = 0;
//wait on all children
for (c = 0; c < (NUM_CHILDREN + 1); c++) {
wait(&status);
}
return 0;
}

Since your question seems to be about understanding how pipes and forks work, I hope below programs can help you. Please notice that this is for illustration only. It wouldn't qualify for commercial implementation, but I wanted to keep it short!
You can compile the two programs as follows:
cc pipechild.c -o pipechild
cc pipeparent.c -o pipeparent
Then execute with ./pipeparent
pipeparent.c source
/* pipeparent.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define MESSAGE "HELLO!\n"
#define INBUFSIZE 80
#define RD 0 // Read end of pipe
#define WR 1 // Write end of pipe
int main(void)
{
int ptocpipe[2]; // Parent-to-child pipe
int ctoppipe[2]; // Chile-to-parent pipe
pid_t childpid; // Process ID of child
char inbuf[80]; // Input from child
int rd; // read() return
int rdup; // dup():ed stdin for child
int wdup; // dup():ed stdout for child
char *eol; // End of line
// Create pipe for writing to child
if (pipe(ptocpipe) < 0) {
fprintf(stderr, "pipe(ptocpipe) failed!\n");
return 2;
}
// Create pipe for writing back to parent
if (pipe(ctoppipe) < 0) {
fprintf(stderr, "pipe(ctoppipe) failed!\n");
return 2;
}
// Verify that one of the pipes are working by filling it first
// in one end and then reading it from the other. The OS will
// buffer the contents for us. Note, this is not at all necessary,
// it's just to illustrate how it works!
write(ptocpipe[WR], MESSAGE, strlen(MESSAGE));
read(ptocpipe[RD], inbuf, INBUFSIZE);
if (strlen(inbuf) != strlen(MESSAGE)) {
fprintf(stderr, "Failed to flush the toilet!\n");
return 6;
} else {
printf("Wrote to myself: %s", inbuf);
}
// Next, we want to launch some interactive program which
// replies with exactly one line to each line we send to it,
// until it gets tired and returns EOF to us.
// First, we must clone ourselves by using fork(). Then the
// child process must be replaced by the interactive program.
// Problem is: How do we cheat the program to read its stdin
// from us, and send its stdout back to us?
switch (childpid = fork()) {
case -1: // Error
fprintf(stderr, "Parent: fork() failed!\n");
return 3;
case 0: // Child process
// Close the ends we don't need. If not, we might
// write back to ourselves!
close(ptocpipe[WR]);
close(ctoppipe[RD]);
// Close stdin
close(0);
// Create a "new stdin", which WILL be 0 (zero)
if ((rdup = dup(ptocpipe[RD])) < 0) {
fprintf(stderr, "Failed dup(stdin)\n");
return 4;
}
// Close stdout
close(1);
// Create a "new stdout", which WILL be 1 (one)
if ((wdup = dup(ctoppipe[WR])) < 0) {
fprintf(stderr, "Failed dup(stdout)\n");
return 5;
}
// For debugging, verify stdin and stdout
fprintf(stderr, "rdup: %d, wdup %d\n", rdup, wdup);
// Overload current process by the interactive
// child process which we want to execute.
execlp("./pipechild", "pipechild", (char *) NULL);
// Getting here means we failed to launch the child
fprintf(stderr, "Parent: execl() failed!\n");
return 4;
}
// This code is executed by the parent only!
// Close the ends we don't need, to avoid writing back to ourself
close(ptocpipe[RD]);
close(ctoppipe[WR]);
// Write one line to the child and expect a reply, or EOF.
do {
write(ptocpipe[WR], MESSAGE, strlen(MESSAGE));
if ((rd = read(ctoppipe[RD], inbuf, INBUFSIZE)) > 0) {
// Chop off ending EOL
if ((eol = rindex(inbuf, '\n')) != NULL)
*eol = '\0';
printf("Parent: Read \"%s\" from child.\n", inbuf);
}
} while (rd > 0);
fprintf(stderr, "Parent: Child done!\n");
return 0;
}
pipechild.c source
/* pipechild.c
* Note - This is only for illustration purpose!
* To be stable, we should catch/ignore signals,
* and use select() to read.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#define MAXCOUNT 5 // Maximum input lines toread
#define INBUFSIZE 80 // Buffer size
int main(void)
{
char buff[INBUFSIZE];
int remains = MAXCOUNT;
pid_t mypid;
char *eol;
mypid = getpid(); // Process-ID
fprintf(stderr, "Child %d: Started!\n", mypid);
// For each line read, write one tostdout.
while (fgets(buff, INBUFSIZE, stdin) && remains--) {
// Chop off ending EOL
if ((eol = rindex(buff, '\n')) != NULL)
*eol = '\0';
// Debug to console
fprintf(stderr, "Child %d: I got %s. %d remains.\n",
mypid, buff, 1 + remains);
// Reply to parent
sprintf(buff, "Child %d: %d remains\n", mypid, 1 + remains);
write(1, buff, strlen(buff));
}
fprintf(stderr, "Child %d: I'm done!\n", mypid);
return 0;
}

Related

Redirect stdin from exec to reading pipe

Basically I'm programming my own xargs implementation for practicing. The main difference with the original xargs is that what I do is to buffer the first 4 lines I get from stdin in the parent process and write it in the pipe I created, so it processes 4 lines at a time instead of each line. Then, in the child process I redirect stdin to the reading pipe so when I call exec it should receive the arguments. After that, when child ends, the parent should do this again until all stdin was read.
So let's say I do cat directories.txt | ./my_xargs ls where directories is a file that has:
/var/
/opt/
/dev/
I should get the result of running ls /var/ /opt/ /dev/. But instead I'm getting as if I've run just ls without parameters.
I tried several things:
Writing a file and redirecting that file descriptor to stdin. Didn't work.
I already checked the pipe is written correctly debugging and also printing the result of reading the pipe instead of calling exec.
closing stdin and opening a new file and write what I read in the child to that file. When I debug I can even see that that file descriptor is 0.
removing the line close(pd[0]); didn't work either.
#ifndef NARGS
#define NARGS 4
#endif
#define LINE_SIZE 1024
#define PATH_MAX 1024
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
typedef enum { false, true } bool;
int
main(int argc, char *argv[])
{
bool eof = false;
int pd[2];
size_t len = 0;
while (!eof) {
if (pipe(pd) == -1) {
fprintf(stderr, "Error creating pipe\n");
}
pid_t pid;
pid = fork();
if (pid == -1) {
fprintf(stderr, "Fork error\n");
}
if (pid == 0) { // child
close(pd[1]); // child doesn't write
dup2(pd[0], 0); // changing reading pipe por stdin
close(pd[0]);
execvp(argv[1], argv + 1);
perror("Exec failed.\n");
} else {
close(pd[0]); // parent doesn't read
char total_params[PATH_MAX] = "";
char* newLine = NULL;
int i = 0;
while (i < NARGS && !eof) {
// Reading stdin
eof = getline(&newLine, &len, stdin) < 1;
// Removing '\n'
if ( i+1 < NARGS) {
newLine[strcspn(newLine, "\n")] = ' ';
} else {
newLine[strcspn(newLine, "\n")] = '\0';
}
strcat(total_params, newLine);
i++;
}
free(newLine);
write(pd[1], &total_params, strlen(total_params));
close(pd[1]);
wait(NULL);
}
}
return 0;
}

How can i print every string in C pipes

How can i print every string in C pipes i am stuck.
output like this
Received string: spike
Received string: spike
Received string: spike
but i want like this
Received string: spike
Received string: tom
Received string: jerry
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[3][10] = {
"spike",
"tom",
"jerry"};
char readbuffer[80];
pipe(fd);
if ((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if (childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string) + 1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
for (int i = 0; i < 3; i++)
{
printf("Received string: %s \n", readbuffer);
}
}
return (0);
}
You've made several mistakes.
First of all, the child doesn't write the correct thing into the pipe.
Then you read() a 80 byte buffer, which will contain all 3 strings (asuming you've fixed issue 1). But since you write one byte more than the string is long, you'll have a zero byte in the middle of your readbuffer. Any attempt to print that will simply stop at that zero byte.
It'll be important to add error handling. You can never ever assume that a read or write will be successful.
I've modified your code a little, such that it works better (but not right yet):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
/* added newlines to separate the entries when printing */
char string[3][10] = {
"spike\n",
"tom\n",
"jerry\n"
};
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
/* Send "string" through the output side of pipe */
/* Added a loop here, so all 3 entries are written */
for (int i = 0; i < 3; ++i) {
write(fd[1], string[i], (strlen(string[i])));
}
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Read in a string from the pipe */
/* no loop needed here for now
But you'd need to read until you reach EOF.
I leave that as an exercise
*/
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
readbuffer[nbytes] = '\0';
printf("Received string: %s \n", readbuffer);
}
return(0);
}

Communication between parent and child results in system lockup

I am trying to create some communication between two programs by forking in the child program within the parent program.
When I execute the child program separately, it works. The purpose of it is that if someone types 1, 2, or 3 followed by enter, that program prints that number as a word. But if one presses 0 and enter, the program exits.
Now I am trying to make the parent program execute the child program in a way where all it does is exit the program while showing the progress of action.
When I execute my program, I see:
Child to start
Parent running OK
Which suggest the child program is running, otherwise I would see:
Exec failed
So instead of me seeing any actual useful output, the system decides to gradually slow down to the point where at first the mouse cursor doesn't move smoothly when I move the mouse, then It got to the point where it wouldn't respond to the keyboard, so I literally had to hold the power button to reset my computer.
How do I fix this so that it can work with any program (that I use as a child) that can exit when I press 0 and enter from within it?
This is my code for the parent:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
//Setup child read and write file handle named parr and parw respectively
//and parent read and write file handle named to parr and parw respectively
#define kidr wrp[0]
#define kidw rdp[1]
#define parw wrp[1]
#define parr rdp[0]
int main(){
int cmd=0;
//setup and start pipes
int wrp[2],rdp[2];
if (pipe(wrp) == -1 || pipe(rdp) == -1){printf("ERROR: cant run pipes.\n");return -1;}
//Start fork
pid_t f=fork();
if (f > 0){
int wstat; //wait state data
char buff[100]; //our data buffer
close(kidr); //we are parent so close child handles
close(kidw);
struct timeval tv;
fd_set readfds;
tv.tv_sec = 1;
tv.tv_usec = 0;
printf("Parent running OK\n");
while(1){
//process other async events here
pid_t wpid=waitpid(-1,&wstat,WNOHANG);
if (wpid==-1){printf("Wait PID error\n");break;}
if (wpid > 0){printf("Children closed OK\n");break;}
//Process data only when child data is readable via pipe
FD_ZERO(&readfds);FD_SET(parr, &readfds);
select(parr+1, &readfds, NULL, NULL, &tv);
if(FD_ISSET(parr, &readfds)){
memset(buff,0,99);
int rd=read(parr, buff, 50);
//doesnt seem to reach this point...
if (rd > 0){
printf("Got: %s\n", buff);
}else{
if (cmd==0){
printf("sending data...\n");
char*dat="0\n"; //parent sends 0 and the enter button.
cmd++; //so this doesn't get called again
write(parw,dat,strlen(dat));
}
}
}
}
//close everything and exit
close(parr);
close(parw);
return 0;
}
if (f==0){
printf("Child to start\n");
//Child mode.
//Close parents
close(parr);close(parw);
//make stdio as child handles
dup2(kidr,STDIN_FILENO);dup2(kidw,STDOUT_FILENO);
//close old child handles
close(kidw);close(kidr);
execlp("/path/to/forkt","forkt",NULL);
//We shouldn't get here unless 'ls' command isnt found
printf("Exec failed\n");
_exit(-1);
}
if (f==-1){
//If fork() doesnt work...
printf("Fork error\n");
}
return 0;
}
This is my code for the child and I compiled it so its named forkt.
#include <stdio.h>
#include <stdlib.h>
int main(){
printf("The child has started\n\n");
char c[100];
while (1){
printf("Enter number or 0 to exit: \n>");
scanf("%s",c);
if (c[0]=='1'){printf("one\n");}
if (c[0]=='2'){printf("two\n");}
if (c[0]=='3'){printf("three\n");}
if (c[0]=='0'){return 0;}
}
}
Update
I took a suggestion of running my parent code through the gdb debugger.
I compiled my code using the gcc -g switch then executed it with gdb a.out
Then in gdb, I set a break point to first line of code then used the "run" command then i kept using the "step" command until I found the crashing point which is here:
pid_t f=fork();
if (f > 0){ // <- right here
This suggests that somehow the child is creating the lockup(?) even though the child runs fine if it is run by itself without a parent?
AFAICS, the parent won't write anything to the child until the child sends something back, but the child won't send anything until it gets something from the parent. That's a deadlock. There's also a problem with buffering. The pipes are not 'interactive devices' so the output streams are not flushed until the buffer is full, the stream is closed, or you call fflush().
Here's some alternative but very similar code to yours:
forkt.c
#include <stdio.h>
int main(void)
{
printf("The child has started\n\n");
fflush(stdout);
char c[100];
while (1)
{
printf("Enter number or 0 to exit:\n>");
fflush(stdout);
if (scanf("%s", c) != 1)
return 0;
fprintf(stderr, "Child received: [%s]\n", c);
if (c[0] == '1')
{
printf("one\n");
}
if (c[0] == '2')
{
printf("two\n");
}
if (c[0] == '3')
{
printf("three\n");
}
if (c[0] == '0')
{
return 0;
}
fflush(stdout);
}
}
This is mostly noticeable for a collection of calls fflush(stdout).
parent.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#define kidr wrp[0]
#define kidw rdp[1]
#define parr rdp[0]
#define parw wrp[1]
int main(void)
{
int cmd = 0;
int wrp[2], rdp[2];
fprintf(stderr, "Parent process: PID %d\n", getpid());
if (pipe(wrp) == -1 || pipe(rdp) == -1)
{
fprintf(stderr, "ERROR: cant run pipes.\n");
exit(1);
}
pid_t f = fork();
if (f == -1)
{
fprintf(stderr, "Fork error\n");
exit(1);
}
if (f > 0)
{
int wstat;
char buff[100];
close(kidr);
close(kidw);
fprintf(stderr, "Parent running OK - child %d\n", f);
while (1)
{
pid_t wpid = waitpid(-1, &wstat, WNOHANG);
if (wpid == -1)
{
fprintf(stderr, "Wait PID error\n");
break;
}
if (wpid > 0)
{
fprintf(stderr, "Child %d exited\n", wpid);
break;
}
for (cmd = 3; cmd >= 0; cmd--)
{
char buffer[30];
int nb = snprintf(buffer, sizeof(buffer), "%d\n", cmd);
int wr = write(parw, buffer, strlen(buffer));
if (wr != nb)
{
fprintf(stderr, "Parent failed to write: %d\n", wr);
exit(1);
}
fprintf(stderr, "Parent sent: %s", buffer);
memset(buff, 0, 99);
int rd = read(parr, buff, 50);
if (rd > 0)
{
fprintf(stderr, "Got: [[%.*s]]\n", rd, buff);
}
else
{
fprintf(stderr, "Parent read failed\n");
exit(1);
}
}
}
close(parr);
close(parw);
return 0;
}
if (f == 0)
{
fprintf(stderr, "Child %d to start\n", getpid());
close(parr);
close(parw);
dup2(kidr, STDIN_FILENO);
dup2(kidw, STDOUT_FILENO);
close(kidw);
close(kidr);
execlp("forkt", "forkt", NULL);
fprintf(stderr, "Exec failed\n");
_exit(-1);
}
return 0;
}
The surgery here is more extensive.
When I ran the code, one time I got the output:
Parent process: PID 94693
Parent running OK - child 94694
Parent sent: 3
Child 94694 to start
Got: [[The child has started
]]
Parent sent: 2
Child received: [3]
Got: [[Enter number or 0 to exit:
>]]
Parent sent: 1
Child received: [2]
Got: [[three
Enter number or 0 to exit:
>]]
Parent sent: 0
Child received: [1]
Got: [[two
Enter number or 0 to exit:
>]]
Child received: [0]
Parent sent: 3
Got: [[one
Enter number or 0 to exit:
>]]
Parent sent: 2
Parent read failed
Note that the prompts from the child are mixed up with the output.

Child reading from std input and writes to std output

I have a program where the child runs a program but the parent process passes the child a number and the child writes back to the parent a response. However whenever I run the code, it does not give me anything back, so I must be passing or receiving to the child wrong, but I'm not sure how. Any help is appreciated. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main() {
int pid;
int n;
char buf[101];
int pfdA[2];
int pfdB[2];
// CREATES FIRST PIPE
if (pipe(pfdA) == -1) {
perror("pipe failed");
exit(-1);
}
// CREATES SECOND PIPE
if (pipe(pfdB) == -1) {
perror("pipe failed");
exit(-1);
}
// FORK()
if ((pid == fork()) < 0) {
perror("fork failed");
exit(-2);
}
if (pid == 0 ) {
// duplicate file descriptor 0 to point to FIRST pipe
dup(pfdA[0]);
// CLOSES ends of FIRST pipe you don't need anymore
close(pfdA[0]);
close(pfdA[1]);
// duplicates file descriptor 1 to point to SECOND pipe
dup(pfdA[1]);
// CLOSES ends of SECOND pipe you don't need anymore
close(pfdB[0]);
close(pfdB[1]);
execlp("./A5_CHILD", "./A5_CHILD", (char *) 0);
perror("execlp");
exit(-3);
}
else {
while( 1 ) {
char NUM[100];
close(pfdA[0]);
close(pfdB[1]);
int r=0;
printf("Enter a Number: ");
fflush(stdout);
scanf("%s", NUM);
// SENDS NUM to Child process
write(pfdA[1], NUM, strlen(NUM));
// READS FROM CHILD THE RESPONSE into the variable buf and
// store the return value from read() into the variable r
r= read(pfdB[0], buf, 100);
if( r > 0 ) {
buf[r] = '\0';
printf("%s\n", buf);
fflush(stdout);
}
else {
printf("[PARENT] Reading from child: read() returned %d\n", r);
break;
}
}
}
return(0);
}
Unless you explicitly close(0), dup(pfdA[0]) almost certainly does not return 0. Try dup2 to specify which descriptor you want as the new one. That is (error checking omitted for brevity):
dup2( pfdA[0], STDIN_FILENO );
close( pfdA[0])
Similarly for stdout.

New to IPC, can't get my pipe to work

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

Resources