C Read stdout from multiple exec called from fork - c

In the code below a process creates one child (fork()) and then the child replaces itself by calling exec(). The stdout of the exec is written in a pipe instead of the shell. Then the parent process reads from the pipe what the exec has written with while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
Can someone tell me how to do the exact same thing as described above but with N number of children processes (who replace themselves with exec as above).
int pipefd[2];
pipe(pipefd);
if (fork() == 0)
{
close(pipefd[0]); // close reading end in the child
dup2(pipefd[1], 1); // send stdout to the pipe
dup2(pipefd[1], 2); // send stderr to the pipe
close(pipefd[1]); // this descriptor is no longer needed
exec(...);
}
else
{
// parent
char buffer[1024];
close(pipefd[1]); // close the write end of the pipe in the parent
while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
{
}
}

I found the answer. I made an array of pipes so that a process does not overwrite the output of another process.
Here is my code. Do you find any mistake?
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#define N 10
int main(int argc, char *argv[]) {
ssize_t readlen;
int pipefd[N][2];
int i;
for (i = 0; i < N; i++) {
pipe(pipefd[i]);
}
int pid = getpid();
for (i = 0; i < N; i++) {
if (fork() == 0) //The parent process will keep looping
{
close(pipefd[i][0]); // close reading end in the child
dup2(pipefd[i][1], 1); // send stdout to the pipe
dup2(pipefd[i][1], 2); // send stderr to the pipe
close(pipefd[i][1]); // this descriptor is no longer needed
char b[50];
sprintf( b, "%d", i);
execl("/bin/echo", "echo", b,NULL);
}
}
if (pid == getpid()) {
// parent
char buffer[1024];
for (i = 0; i < N; i++) {
close(pipefd[i][1]); // close the write end of the pipe in the parent
while ((readlen=read(pipefd[i][0], buffer, sizeof(buffer))) != 0)
{
buffer[readlen] = '\0';
}
printf("%s\n",buffer);
}
}
}

Maybe this code would do the job:
const int N = 10; //Number of child processes
int pipefd[2];
pipe(pipefd);
int i;
for (i = 0; i < N; i++) {
if (fork() == 0) //The parent process will keep looping
{
close(pipefd[0]); // close reading end in the child
dup2(pipefd[1], 1); // send stdout to the pipe
dup2(pipefd[1], 2); // send stderr to the pipe
close(pipefd[1]); // this descriptor is no longer needed
exec(...);
}
}
// parent
char buffer[1024];
close(pipefd[1]); // close the write end of the pipe in the parent
while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
{
}
WARNING: the output will be mixed. If you want all processes to dump data without being mixed, then you should manage to synchronize processes (by means of public locks, for example).

I think you can create named chanel in any place of the file system (like a local socket) and read all received data to parent process. So child processes must write their getted data to this channel. It will be unix-like architecture.

Related

Is printf equivalent to dprintf(STDOUT_FILENO)?

I am learning something about PIPE in Linux, but I met something I can't figure out. I was reading rozmichelle's blog http://www.rozmichelle.com/pipes-forks-dups/#pipelines. The code below is to sort three words that parent process passes on to child process by PIPE.
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2]; // an array that will hold two file descriptors
pipe(fds); // populates fds with two file descriptors
pid_t pid = fork(); // create child process that is a clone of the parent
if (pid == 0) { // if pid == 0, then this is the child process
dup2(fds[0], STDIN_FILENO); // fds[0] (the read end of pipe) donates its data to file descriptor 0
close(fds[0]); // file descriptor no longer needed in child since stdin is a copy
close(fds[1]); // file descriptor unused in child
char *argv[] = {(char *)"sort", NULL}; // create argument vector
if (execvp(argv[0], argv) < 0) exit(0); // run sort command (exit if something went wrong)
}
// if we reach here, we are in parent process
close(fds[0]); // file descriptor unused in parent
const char *words[] = {"pear", "peach", "apple"};
// write input to the writable file descriptor so it can be read in from child:
size_t numwords = sizeof(words)/sizeof(words[0]);
for (size_t i = 0; i < numwords; i++) {
dprintf(fds[1], "%s\n", words[i]);
}
// send EOF so child can continue (child blocks until all input has been processed):
close(fds[1]);
int status;
pid_t wpid = waitpid(pid, &status, 0); // wait for child to finish before exiting
return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
In the code above, the parent process uses dprintf, but I wonder if we can redirect parent process' standard out to PIPE's in. So I tried to write the code below.
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int fds[2];
pipe(fds);
pid_t pid = fork();
if (pid == 0) {
dup2(fds[0], STDIN_FILENO);
close(fds[0]);
close(fds[1]);
char *argv[] = {(char *)"sort", NULL};
if (execvp(argv[0], argv) < 0) exit(0);
}
// if we reach here, we are in parent process
close(fds[0]);
const char *words[] = {"pear", "peach", "apple"};
// write input to the writable file descriptor so it can be read in from child:
size_t numwords = sizeof(words)/sizeof(words[0]);
dup2(fds[1],STDOUT_FILENO);//redirect stdout
close(fds[1]); //fds[1] is not used anymore
for (size_t i = 0; i < numwords; i++) {
printf("%s\n", words[i]);
}
close(STDOUT_FILENO);
int status;
pid_t wpid = waitpid(pid, &status, 0);
return wpid == pid && WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
After redrecting, I used printf, which in my understanding will output to STDOUT. However, this code print nothing, while the first code print as below:
apple
peach
pear
I can't figure out why this happen, is there something I understand mistakely?
According to man pages, dprintf is a POSIX extension, not a standard library function, so it is not equivalent in terms of portability.
As far as their implementation in GLIBC is concerned, both printf and dprintf call __vfprintf_internal, but note that dprintf does also this (done != EOF && _IO_do_flush (&tmpfil.file) == EOF) which suggests flushing the buffer after the write.
printf, on the other hand, does not.
I'd try fiddling with buffering, i.e. setbuf, fflush or similar on the stdout and see if that helps.

Piping output between N processes in C

I'm trying to write a C program to simulate the piping of two or more processes together, like ls | sort | wc so running my code as ./driver ls sort wc should show the same result. I think I'm really close, but I can't seem to find the bug in my code below. Any help would be appreciated, I'm really stumped here.
I think I understand what is supposed to happen, but Im crossing my wires somehow in making it happen. The parent should fork child processes who in turn reroute their STDOUT to the write end of a pipe(a). Any child who is created beyond the first child should consider the read end of this pipe(a) as its STDIN, as well as redirect it's own output to a pipe(b) of it's own.
Say a third process is piped. It should consider the read end of the pipe(b) as STDIN, and again pipe its output to the write end of a new pipe(c) before executing the requested command.
The last case is the when the final process is passed to the pipe. In this example, a fourth process would consider the read end of the pipe(c) but should not need to redirect the STDOUT, just send it to STDOUT as normal.
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define FORK_CHILD 0
static void error_and_exit(void) {
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
static int fork_or_die(void) {
int pid = fork();
if (pid == -1) {
error_and_exit();
}
return pid;
}
int main(const int argc, const char * argv[])
{
int processes = argc - 1;
int apipe[argc - 1][2];
int pid;
int result = -1;
for (int i = 0; i < processes; i++) {
result = pipe(apipe[i]);
if (result == -1) {
error_and_exit();
}
}
for (int i = 0; i < processes; i++) {
pid = fork_or_die();
// Child process executes process
if (pid == FORK_CHILD) {
// If we are not the first program in the pipe
if (i > 1) {
// Use the output from the previous program in the pipe as our input
// Check the read end of the pipe and STDIN are different descriptors
if (apipe[i - 1][0] != STDIN_FILENO) {
// Send the read end of the pipe to STDIN
if (dup2(apipe[i - 1][0], STDIN_FILENO) == -1) {
error_and_exit();
}
}
}
// Before we execute a process, bind the write end of the pipe to STDOUT
// Don't do this to the last process in the pipe, just send output to STDOUT as normal
if (i < processes - 1) {
// Check the write end of the pipe and STDOUT are different descriptors
if (apipe[i][1] != STDOUT_FILENO) {
// Send the write end of the pipe to STDOUT
if (dup2(apipe[i][1], STDOUT_FILENO) == -1) {
error_and_exit();
}
}
}
// Child executes requested process
if (execlp(argv[i + 1], argv[i + 1], (char *)NULL) == -1) {
error_and_exit();
}
wait(NULL);
}
// Parent does nothing until loop exits (waits for children)
}
return 0;
}
I've spotted three issues with your code:
As You have decided to index children starting from 0, not one but two processes will skip this part of code. The simplest fix that comes to my mind right now is to change the 1 to 0 or > to >=.
// If we are not the first program in the pipe
if (i > 1) {
You are calling wait in code that is not executed by parent. Moving the call outside the if (pid == FORK_CHILD) branch won't help as parent will wait for one child to finish before another one is started. Child process's write operation may wait for next child to consume some data and make place in buffer. Simplest solution that comes to my mind right now is to move wait calls to another loop.
You keep all pipe's descriptor open in parent and child processes. You should close it before wait loop in parent and before execlp in forked processes. The programs like grep, sort won't finish unless they receive EOF in their incoming streams. The pipe won't send EOF as long as at least one write descriptor is still open.
The code with minimal changes applied:
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#define FORK_CHILD 0
static void error_and_exit(void) {
fprintf(stderr, "Error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
static int fork_or_die(void) {
int pid = fork();
if (pid == -1) {
error_and_exit();
}
return pid;
}
int main(const int argc, const char * argv[])
{
int processes = argc - 1;
int apipe[argc - 1][2];
int pid;
int result = -1;
for (int i = 0; i < processes; i++) {
result = pipe(apipe[i]);
if (result == -1) {
error_and_exit();
}
}
for (int i = 0; i < processes; i++) {
pid = fork_or_die();
// Child process executes process
if (pid == FORK_CHILD) {
// If we are not the first program in the pipe
if (i > 0) {
// Use the output from the previous program in the pipe as our input
// Check the read end of the pipe and STDIN are different descriptors
if (apipe[i - 1][0] != STDIN_FILENO) {
// Send the read end of the pipe to STDIN
if (dup2(apipe[i - 1][0], STDIN_FILENO) == -1) {
error_and_exit();
}
}
}
// Before we execute a process, bind the write end of the pipe to STDOUT
// Don't do this to the last process in the pipe, just send output to STDOUT as normal
if (i < processes - 1) {
// Check the write end of the pipe and STDOUT are different descriptors
if (apipe[i][1] != STDOUT_FILENO) {
// Send the write end of the pipe to STDOUT
if (dup2(apipe[i][1], STDOUT_FILENO) == -1) {
error_and_exit();
}
}
}
for (int j = 0; j < processes; j++) {
if(close(apipe[j][0]) == -1)
error_and_exit();
if(close(apipe[j][1]) == -1)
error_and_exit();
}
// Child executes requested process
if (execlp(argv[i + 1], argv[i + 1], (char *)NULL) == -1) {
error_and_exit();
}
}
}
// Parent does nothing until loop exits (waits for children)
for (int i = 0; i < processes; i++) {
if(close(apipe[i][0]) == -1)
error_and_exit();
if(close(apipe[i][1]) == -1)
error_and_exit();
}
for (int i = 0; i < processes; i++) {
wait(NULL);
}
return 0;
}

Why does program hang on child to parent communication?

I am trying to understand why my program hangs. The Parent sends input froma
file it reads to the child program, and the child program will send the result of its computation back to it's parent. However, I have trouble sending the message back through a second pipe. The parent seems to hang when reading from the pipe.
From the other posts, I have read it seems to indicate that the parent should wait for the child to finish by using wait or waitpid (which in my case both of them does not resolve my issue).
I have notice by adding print statement that neither the PARENT or the CHILD finishes.. Could someone please explain to me why this is happening?
Why does this not work?
int main(int argc,char** argv) {
char buffer[1];
int i;
int fd1[2]; int fd2[2];
pipe(fd1); pipe(fd2);
pid_t pid;
// FIRST PROCESS.
// -------------------
pid = fork();
if(pid == 0) {
int cnt;
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
for (i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
while(read(STDIN_FILENO, buffer, sizeof(buffer)) > 0) {
fprintf(stderr, "( %s )", buffer);
cnt = cnt + *buffer - 48;
}
write(STDOUT_FILENO, &cnt, sizeof(cnt));
exit(0);
}
// PARENT.
// ------------------------
int file = open(argv[1], O_RDONLY);
// READ THE FILE.
while(read(file, buffer, 1) > 0) {
if (48 <= *buffer && *buffer <= 57) {
// PIPE TO CHILD.
write(fd1[1], buffer, 1);
}
}
// WAIT FOR CHILD TO FINISH SENDING BACK.
// int status = 0;
// waitpid(pid, &status, 0);
// THIS BLOCK DOESN'T RESOLVE ANYTHING. IT HANGS AT WAIT OR WAITPID.
// **** THIS IS THE PART WHERE IT DOESN'T WORK.
while(read(fd2[0], buffer, 1) > 0) {
fprintf(stderr, "RESULT : %s", buffer);
}
// CLOSING PIPES
for (i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
close(file);
exit(0);
}
You aren't closing enough file descriptors in the parent soon enough.
Rule of thumb: If you
dup2()
one end of a pipe to standard input or standard output, close both of the
original file descriptors returned by
pipe()
as soon as possible.
In particular, you should close them before using any of the
exec*()
family of functions.
The rule also applies if you duplicate the descriptors with either
dup()
or
fcntl()
with F_DUPFD
Now, your child process is following the RoT perfectly. But the corollary for parent processes is that they need to close the unused ends of the pipe, and they must close the write end of a pipe that they use to signal EOF to the reading end of that pipe. This is where your code fails.
Arguably, before reading the file, the parent process should close the read end of the pipe it uses to write to the child, and it should close the write end of the pipe it uses to read from the child.
Then, after reading the whole of the file, it should close the write end of the pipe to the child, before going into the 'read from child' loop. That loop never terminates because the parent still has the write end of the pipe open, so there's a process that could (but won't) write to the pipe.
Also, since the child writes the bytes of an integer onto a pipe, the parent should read the bytes of an integer. Using char buffer[1]; with a %s format is pointless; you need a null terminator for the string, and a single char buffer can't hold both a null byte and any data.
Along with various other improvements ('0' instead of 48, for example), you might end up with:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
int fd1[2];
int fd2[2];
char buffer[1];
pipe(fd1);
pipe(fd2);
pid_t pid = fork();
if (pid == 0) {
int cnt = 0;
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
for (int i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
while (read(STDIN_FILENO, buffer, sizeof(buffer)) > 0) {
fprintf(stderr, "(%c)", buffer[0]); // Changed
cnt = cnt + buffer[0] - '0';
}
putc('\n', stderr); // Aesthetics
write(STDOUT_FILENO, &cnt, sizeof(cnt));
exit(0);
}
int file = open(argv[1], O_RDONLY);
if (file < 0) {
fprintf(stderr, "failed to open file '%s' for reading\n", argv[1]);
exit(EXIT_FAILURE);
}
close(fd1[0]); // Added
close(fd2[1]); // Added
while (read(file, buffer, sizeof(buffer)) > 0) {
if ('0' <= buffer[0] && buffer[0] <= '9') {
write(fd1[1], buffer, sizeof(buffer));
}
}
close(file); // Moved
close(fd1[1]); // Added
// Rewritten
int result;
while (read(fd2[0], &result, sizeof(result)) == sizeof(result)) {
fprintf(stderr, "RESULT : %d\n", result);
}
close(fd2[0]); // Added
// Close loop removed
return 0;
}
If that is stored in file pipe71.c and compiled, I get the following outputs when it is run:
$ ./pipe71 pipe71.c
(2)(0)(1)(2)(2)(2)(1)(1)(2)(0)(0)(2)(1)(0)(2)(2)(1)(0)(2)(1)(2)(0)(0)(0)(0)(0)(1)(0)(1)(1)(0)(2)(1)(0)(0)(0)(0)(9)(1)(1)(1)(1)(2)(0)(2)(0)(0)
RESULT : 49
$ ./pipe71 pipe71
(0)(0)(8)(0)(0)(2)(2)(0)(8)(1)(1)(5)(1)(1)(1)(1)(5)(1)(1)(1)(8)(5)(1)(9)(8)(5)(1)(1)(0)(4)(4)(4)(6)(0)(2)(8)(0)(0)(0)(2)(7)(1)(3)(8)(3)(0)(4)(3)(0)(4)(9)(0)(0)(0)(0)(7)(1)(9)(8)(1)(3)(0)
RESULT : 178
$

Unable to read from a pipe after something is written to it by a child process

I create a function exec_in_child which takes the command arguments, pipe file descriptors (fds), read_flag and write_flag as input. When write_flag is set to 1, the child process should duplicate stdout to fds[1], and then execute the command. When read_flag is set to 1, the child should duplicate the stdin to fds[0] and the execute the command.
Do I have to close one end of the pipe when I'm reading/writing to
the other end?
The code below doesn't work. I'm trying to execute /bin/ls inside a child process, write the stdout to the pipe, and then read
it off in the parent process and print it. I'm not able to read in
the parent process.
Can I read and write to the pipe inside the same process without closing other? This situation arises when I want to child to read
from pipe, execute, and then write to the pipe.
#include <stdio.h> /* printf */
#include <stdlib.h>
#include <string.h> /* strlen, strcpy */
int exec_in_child(char *arguments[], const int temp[], int , int);
int main()
{
ssize_t bytes_read;
char *curr_dir = (char *)malloc(500);
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
char *arguments[] = {"/bin/pwd",0};
exec_in_child(arguments, pipefd, 0, 1);
bytes_read = read(pipefd[0], curr_dir, strlen(curr_dir));
printf("%s = %d\n", "bytes read from pipe" ,(int)bytes_read);
printf("%s: %s\n","character read from the pipe",curr_dir);
return 0;
}
int exec_in_child(char * arguments[], const int fds[], int read_flag, int write_flag) {
pid_t pid;
pid = fork();
if (pid < 0) {
perror("Error: Fork Failed");
}
else if (pid == 0){ /*inside the child process */
if (read_flag == 1) {
dup2(fds[0], 0);
perror("Dup2 stdin");
}
if (write_flag == 1) {
dup2(fds[1], 1);
perror("Dup2 stdout");
}
execv(arguments[0], arguments);
perror("Error in child");
exit(1);
} /* if (pid == 0) */
else {
while(pid != wait(0));
} /* if(pid < 0) */
return 0;
}
I get this result:
hmwk1-skk2142(test) > ./a.out
Dup2 stdout: Success
bytes read from pipe = 0
character read from the pipe:
To answer your questions:
1) You do not need to close either end of the pipe in order to use the other end. However, you generally want to close any end(s) of the pipe you're not using. The biggest reason to do this is that the pipe will only close when all open write file descriptors are closed.
2) Your code isn't working because you're using strlen() improperly. This function calculates the length of a string by searching for the null (0) character. When you malloc() the storage for curr_dir you have no guarantee of what resides there (though it will usually be zeroed, as in this case).
Thus, your call strlen(curr_dir) returns zero, and the read() system call thinks you want to read up to zero bytes of data. Change your read call to the following:
bytes_read = read(pipefd[0], curr_dir, 500);
and your code will work perfectly.
3) You can read and write to any pipe you've got a valid file descriptor to. A single process can absolutely read and write the same pipe.

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