Pipe to sort and back to main - c

So i am trying to understand how pipes work in UNIX and i am trying to pipe a text into sort, sort them and pipe them back to main to doo. But when the execution reaches:
Note: The program takes the text file as an argument.
execlp("sort", "sort",(char *)0);
The program stops and stays still there like its waiting from the pipe something. I know that there must be something with my understanding of UNIX piping.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid;
FILE *fdin;
long fsize;
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid = fork()) == -1){
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid != 0){
char buf[1024];
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
fread(buf, sizeof(buf), 1, fdin);
fclose(fdin);
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
}
else if (childpid == 0){
char buf[1024];
close(pipe1[1]);
close(pipe2[0]);
//dup2(pipe2[1], STDOUT_FILENO);
//dup2(pipe1[0], STDIN_FILENO);
read(pipe1[0], buf, sizeof(buf));
close(pipe1[0]);
printf("%s\n\n", buf);
dup2(pipe2[1], STDOUT_FILENO);
close(pipe2[1]);
execlp("sort", "sort",(char *)0);
printf("%s\n", buf);
exit(0);
}
// wait child
wait(NULL);
// parent read pipe 2 and print
if (childpid != 0){
// DOOOO
//read(pipe2[0], buf, 1024);
//printf("%s\n", buf);
}
return 0;
}
Dead Locked
Updated
UPDATE: 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
//char *message = "This is a message!!!";
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid[2];
FILE *fdin;
char buf[1024];
//long fsize;
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid[0] = fork()) == -1)
{
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid[0] != 0){
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
fread(buf, sizeof(buf), 1, fdin);
fclose(fdin);
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
}
else if (childpid[0] == 0){
buf[0] = '\0';
int pipe3[2];
pipe(pipe3);
close(pipe1[1]);
close(pipe2[0]);
//dup2(pipe2[1], STDOUT_FILENO);
dup2(pipe1[0], STDIN_FILENO);
//dup2(pipe3[1],STDOUT_FILENO);
read(pipe1[0], buf, sizeof(buf));
close(pipe1[0]);
write(pipe3[1], buf, sizeof(buf));
printf("-PIPED BUFF-\n%s\n\n", buf);
if ((childpid[1] = fork()) == -1){
perror("fork second child");
exit(1);
}
// Child of child (sort call)
if (childpid[1] != 0){
close(pipe2[1]);
close(pipe3[0]);
printf("I AM YOUR FATHER LOOK\n");
}else{
printf("a\n");
buf[0] = '\0';
printf("b\n");
close(pipe3[1]);
printf("c\n\n");
dup2(pipe3[0], STDIN_FILENO);
read(pipe3[0], buf, sizeof(buf));
close(pipe3[0]);
printf("-SORT BUFF-\n%s\n\n", buf);
//dup2(pipe2[1], STDOUT_FILENO);
close(pipe2[1]);
execlp("sort","sort",(char *)0);
printf("-SORTED BUFF-\n%s\n\n", buf);
exit(0);
}
// wait second child exec
wait(NULL);
//printf("%s\n", buf);
exit(0);
}
// wait child exec
//wait(NULL);
int status;
pid_t pid;
int n = 2;
while (n > 0){
pid = wait(&status);
printf("-SORTED BUFF-\n%s\n\n", buf);
--n;
}
// parent read pipe 2 and print
if (childpid[0] != 0){
printf("asd\n");
buf[0] = '\0';
dup2(pipe2[0], STDIN_FILENO);
read(pipe2[0], buf, sizeof(buf));
close(pipe2[0]);
printf("-SORTED BUFF-\n%s\n\n", buf);
}
return 0;
}

Part 1
In your parent code, you have:
dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, sizeof(buf));
close(pipe1[1]);
This is problematic on multiple counts:
The parent's standard output is now the write end of the pipe used for sending information to the child. That means the parent will have to open a file or terminal or something to write the results of sort to its original standard output.
When you close(pipe1[1]), there is still an open file descriptor for the pipe (the parent's standard output), so sort never gets EOF on the pipe.
You didn't record how much data you read, so you don't know how much data you should write. You could be writing garbage to the pipe unless you know the file is bigger than 1024 bytes. You should capture the amount of data read from the file and only write that much data to the pipe. You should think about ensuring the information ends with a newline.
Since you wait() for the child to complete, but the child doesn't know its input is complete, you have a deadlock. You then have the code to read the input data, but it isn't clear where you're going to write because of the dup2().
First stage fix: remove the identified dup2().
Fretting about deadlocks
In principle, the whole design only works because sort has to read all its input before it can write any of its output. If you had a command such as awk or sed that can write output before it finishes reading its input, your two-way pipe scheme wouldn't work well on large volumes of data. The child might fill the pipe buffer (and not be able to write any more to it) while the parent is still trying to write and finds its pipe buffer is full. Both processes would be stuck in a write waiting for the other to read. There are ways around that — select(), poll(), multiple threads, etc. — but they're beyond the scope of what you want, or need, to deal with now.
Also, your program limits the input to sort to at most 1024 bytes. That isn't enough to fill any pipe buffer, which means that unless the executed command increases the amount of data it has to write back compared with what it reads in — for example, if you sent URLs to a process that fetched the data from those URLs — then you won't run into deadlocks.
Part 2
The child code seems to read the data from the pipe, then launches sort (but there's nothing left for sort to read), and seems to expect execlp() to return. The code simply needs to connect the correct ends of the pipes to standard input and output, close all the pipe file descriptors, and then execute sort. If execlp() returns, it failed — report the error.
Second stage fix: simplify the child process, and make sort do the reading and writing.
Working code
Lots of commented out bits left behind. Key error checking added. For example, check that the command line is correct before doing anything else. Often, you'd open the file before forking; this time, it is better not to do that. Report errors on standard error.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main (int argc, char **argv){
int pipe1[2];
int pipe2[2];
pid_t childpid;
FILE *fdin;
if (argc != 2)
{
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
pipe(pipe1);
pipe(pipe2);
// error handling
if ((childpid = fork()) == -1){
perror("fork");
exit(1);
}
// parent load file, write to pipe1
if (childpid != 0){
//long fsize;
char buf[1024];
close(pipe1[0]);
close(pipe2[1]);
fdin = fopen(argv[1], "r");
if (fdin == 0)
{
fprintf(stderr, "%s: failed to open file '%s'\n", argv[0], argv[1]);
exit(1);
}
//fseek(fdin, 0, SEEK_END);
//fsize = ftell(fdin);
//fseek(fdin, 0, SEEK_SET);
int nbytes = fread(buf, 1, sizeof(buf), fdin);
if (nbytes <= 0)
{
fprintf(stderr, "%s: no data in file '%s'\n", argv[0], argv[1]);
exit(1);
}
fclose(fdin);
//dup2(pipe1[1],STDOUT_FILENO);
write(pipe1[1], buf, nbytes);
close(pipe1[1]);
}
else if (childpid == 0){
//char buf[1024];
close(pipe1[1]);
close(pipe2[0]);
dup2(pipe2[1], STDOUT_FILENO);
dup2(pipe1[0], STDIN_FILENO);
close(pipe2[1]);
close(pipe1[0]);
//read(pipe1[0], buf, sizeof(buf));
//close(pipe1[0]);
//printf("%s\n\n", buf);
//dup2(pipe2[1], STDOUT_FILENO);
//close(pipe2[1]);
execlp("sort", "sort",(char *)0);
fprintf(stderr, "%s: failed to exec 'sort'\n", argv[0]);
exit(1);
}
// wait child
wait(NULL);
// parent read pipe 2 and print
if (childpid != 0){
char buf[1024];
int nbytes;
while ((nbytes = read(pipe2[0], buf, sizeof(buf))) > 0)
printf("%.*s", nbytes, buf);
}
return 0;
}
Note the careful trapping of sizes on both read operations.
Consider an input file:
Harlequin
Preposterous
Animagus
Zealot
Queensbury Rules
Quaternion
Hedwig
Tensor
Tenser
The output I get is:
Animagus
Harlequin
Hedwig
Preposterous
Quaternion
Queensbury Rules
Tenser
Tensor
Zealot
This looks correct to me.

The purpose is to have the parent that open the file and write it to a pipe. In the same time we have a child that create a second pipe and read it. And again in the same time we have a second child that exec sort.
We need 2 child and 2 pipe. The first parent wait the first child and the first child wait the second child.
I don't know if it's perfect because I can't test and this king of thing is very complex:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
static int wait_and_return(pid_t pid) {
int status;
if (waitpid(pid, &status, 0) == -1) {
perror("waitpid()");
return 1;
}
return status;
}
static pid_t create_pipe_and_fork(int fd_pipe[2]) {
if (pipe(fd_pipe) == -1) {
perror("pipe()");
return -1;
}
pid_t pid = fork();
if (pid == -1) {
close(fd_pipe[0]);
close(fd_pipe[1]);
perror("fork()");
return -1;
}
return pid;
}
static int exec_sort(int fd_in, int fd_out) {
if (dup2(fd_in, STDIN_FILENO) == -1 || dup2(fd_out, STDOUT_FILENO) == -1) {
close(fd_in);
close(fd_out);
perror("dup2()");
return 1;
}
close(fd_in);
close(fd_out);
execlp("sort", "sort", (char *)NULL);
perror("execlp()");
return 1;
}
static int child(int fd) {
int fd_pipe[2];
pid_t pid = create_pipe_and_fork(fd_pipe);
if (pid == -1) {
close(fd);
return 1;
}
if (pid != 0) {
close(fd);
close(fd_pipe[1]);
char buf[4048];
ssize_t ret;
while ((ret = read(fd_pipe[0], buf, sizeof buf)) > 0) {
if (ret > INT_MAX) {
close(fd_pipe[0]);
wait_and_return(pid);
return 1;
}
printf("%.*s", (int)ret, buf);
}
close(fd_pipe[0]);
return wait_and_return(pid);
} else {
close(fd_pipe[0]);
return exec_sort(fd, fd_pipe[1]);
}
}
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "wrong argument\n");
return 1;
}
int fd_pipe[2];
pid_t pid = create_pipe_and_fork(fd_pipe);
if (pid == -1) {
return 1;
}
if (pid != 0) {
close(fd_pipe[0]);
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("fopen():");
close(fd_pipe[1]);
wait_and_return(pid);
return 1;
}
char buf[4048];
size_t ret;
while ((ret = fread(buf, sizeof *buf, sizeof buf / sizeof *buf, file))) {
write(fd_pipe[1], buf, ret);
}
fclose(file);
close(fd_pipe[1]);
return wait_and_return(pid);
} else {
close(fd_pipe[1]);
return child(fd_pipe[0]);
}
}
It possible to inverse the role of main and the last child so the main will read the result and the child will open the file. I let you try.

Related

STDERR output is not being captured when running invalid command

I am trying to catch the output from running the command /bin/lsx -lah /.
The output should be: bash: /bin/lsx: no such file or directory
However, I am just not getting anything in the printf().
This is the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
int main() {
int link[2];
pid_t pid;
char foo[4096];
if (pipe(link)==-1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if(pid == 0) {
dup2 (link[1], STDOUT_FILENO);
close(link[0]);
close(link[1]);
execl("/bin/lsx", "ls", "-1", (char *)0);
die("execl");
} else {
close(link[1]);
int nbytes = read(link[0], foo, sizeof(foo));
printf("Output: (%.*s)\n", nbytes, foo);
wait(NULL);
}
return 0;
}
I am just wondering why the output is not being captured and printed in the bottom printf().
As John pointed out, you are only capturing stdout, not stderr, and well-formed programs usually send error messages to stderr (the die macro you have shown is an example of this).
A quick solution is to redirect the child processes' stderr to its stdout with another call to dup2
dup2(link[1], STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
which will redirect both output streams to the single pipe.
Alternatively, capture both streams with two pipes to retain their separation as they propagate.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define die(e) do { fprintf(stderr, "%s\n", e); exit(EXIT_FAILURE); } while (0);
ssize_t push_through(const char *prefix,
FILE *out, int in,
char *buf, size_t bufsz)
{
ssize_t bytes = read(in, buf, bufsz);
if (bytes > 0)
fprintf(out, "%s: (%.*s)\n", prefix, (int) bytes, buf);
return bytes;
}
int main(void)
{
pid_t pid;
int stdout_pipe[2];
int stderr_pipe[2];
char buffer[4096];
if (pipe(stdout_pipe) == -1 || pipe(stderr_pipe) == -1)
die("pipe");
if ((pid = fork()) == -1)
die("fork");
if (pid == 0) {
close(stdout_pipe[0]);
close(stderr_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
dup2(stderr_pipe[1], STDERR_FILENO);
close(stdout_pipe[1]);
close(stderr_pipe[1]);
execl("/bin/lsx", "ls", "-1", (char *) NULL);
perror("execl failed because");
die("execl");
} else {
ssize_t outbytes, errbytes;
close(stdout_pipe[1]);
close(stderr_pipe[1]);
do {
outbytes = push_through("out", stdout, stdout_pipe[0],
buffer, sizeof buffer);
errbytes = push_through("err", stderr, stderr_pipe[0],
buffer, sizeof buffer);
} while (outbytes > 0 || errbytes > 0);
wait(NULL);
}
}
In the event that execl fails, it might be useful to call perror to print a more detailed error message.
Note that expecting the error
bash: /bin/lsx: no such file or directory
is possibly misguided, as exec* functions only defer to a shell under certain conditions.
The only mention of a shell in man 3 exec is with regards to execlp, execvp, and execvpe:
If the header of a file isn't recognized (the attempted execve(2)
failed with the error ENOEXEC), these functions will execute the
shell (/bin/sh) with the path of the file as its first argument.
(If this attempt fails, no further searching is done.)

Storing output of Linux command in named pipe

My goal is to take a command which is input by the user and execute it with a forked child process, but rather than have the child process print it to the screen, store the output in a named pipe and have the parent process display the output after the child process has completed.
I'm attempting to do so by using dup2() to redirect standard output to the named pipe I've made, but the child process simply prints the output of the command and when attempting to read from the pipe in the parent process, I get the following error:
Error reading from pipe: Bad file descriptor
I've searched for similar questions on this site but have only found solutions for using regular pipes to store the output of exec(), and I wasn't able to adapt those solutions to named pipes. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define CMDSIZE 50
#define BUFSIZE 5000
int main() {
char cmd[CMDSIZE], arg[CMDSIZE], buf[BUFSIZE];
int fd, n;
pid_t pid = fork();
if (pid < 0) {
perror("Error creating process");
return 1;
}
else if (pid == 0) {
printf("SHELL > ");
fgets(buf, BUFSIZE, stdin);
sscanf(buf, "%s %s", cmd, arg);
memset(buf, 0, BUFSIZE);
printf("Working on request...\n");
unlink("cmdpipe");
mkfifo("cmdpipe", 0777);
fd = open("cmdpipe", 0777);
dup2(fd, STDOUT_FILENO);
close(fd);
if (arg[0] == '\0')
execlp(cmd, cmd, NULL);
else
execlp(cmd, cmd, arg, NULL);
}
else {
wait(NULL);
printf("...Output ready! Displaying now.\n");
fd = open("cmdpipe", 0777);
if ((n = read(fd, buf, BUFSIZE)) < 0) {
perror("Error reading from pipe");
return n;
}
close(fd);
printf("%s\n", buf);
}
return 0;
}
Thanks.

FIFO between multiple processes - Only printing from a single process

I'm trying to make a FIFO between two programs (one being a child process of the other) so that the child can write data back to the parent. Here's what I have so far:
(Parent)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_BUF 1024
int main(int argc, char *argv[]) {
//number of seperate processes to create
int num_processes = 4;
int i = 0;
//FIFO accross processes
int fd;
char * myfifo = "/tmp/myfifo";
char buf[MAX_BUF];
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
for (i; i < num_processes; i++) {
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
exit(1);
}
else if (pid == 0) {
//child now exec's
char* args[] = {"./child", "args", NULL};
execv("./child", args);
}
}
printf("Parent doing stuff\n");
//Parent wait for child
printf("Parent waiting on child\n");
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
if (fcntl(fd, F_GETFD) == -1) {
perror("fd failed");
exit(1);
}
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
//Wait for child processes to finish
int j = 0;
for (j; j < num_processes; j++) {
wait(NULL);
}
//Close FIFO
close(fd);
return 0;
}
(Child, created 4 times)
void main() {
printf("Completed\n");
//Create FIFO
int fd;
char * myfifo = "/tmp/myfifo";
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
if (fcntl(fd, F_GETFD) == -1) {
perror("open failed");
exit(1);
}
write(fd, "Hi", sizeof("Hi"));
//close(fd);
/* remove the FIFO */
//unlink(myfifo);
}
Right now, "Completed" is being printed 4 times, showing that there are 4 seperate processes running as there should be. However, only one "Received: Hi" is printed in the terminal. How come I am not getting a FIFO response from the other processes?
Any help would be greatly appreciated!
You need to check fd and make sure the open succeeded. And note that it can only succeed once, because the first child will unlink(myfifo).
The parent should also wait for all of the children to finish before reading from the fifo. And the parent should read the fifo in a loop until the fifo is empty.
The problem in your code is that there are multiple child writing to the same FIFO.
As pointed out also by user3386109 you have to wait each child and read the FIFO.
here is a sample code:
//Wait for child processes to finish
int child_status = 0;
while (wait(&child_status) != -1) {
if (WIFEXITED (child_status)) {
fprintf (stdout, "the child process exited normally, with exit code %d\n", WEXITSTATUS (child_status));
// Read The buffer
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
}
else fprintf (stderr, "the child process exited abnormally\n");
}
I also suggest to pass to the child an id (this is just a sample add checks if needed):
else if (pid == 0) {
//child now exec's
char mypid[10];
snprintf(mypid, 10, "%d", i);
char* args[] = {"./child", mypid, NULL};
execv("./child", args);
sleep(1);
That each child read in argv[1]
int mypid = atoi(argv[1]);
Please, see also this post: C Named pipe (fifo). Parent process gets stuck
Solved by putting my read statements into the loop waiting for the child processes to finish:
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
if (fcntl(fd, F_GETFD) == -1) {
perror("fd failed");
exit(1);
}
//Wait for child processes to finish
int j = 0;
for (j; j < num_processes; j++) {
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
wait(NULL);
}
//Close
close(fd);
return 0;

Sending C Command Line Arguments Through Pipe

I am trying to send my command line arguments through from the child process to the parent process using a pipe but can't figure out what I'm doing wrong. My code is below. Any help is appreciated. Thanks in advance.
int main(int argc, char argv[])
pid_t child;
int fd[2];
pipe(fd);
if((child = fork() == 0)
{
int len = strlen(argv[1]);
close(fd[0];
write(fd[1], argv[1], len);
exit(0);
}
else //Assuming process won't fail for now
{
char src[10]; //Just using 10 for now, no arguments have more than 10 characters
read(fd[0], src, (strlen(src)));
fprintf(stderr, "%s\n", src);
close(fd[0]);
}
}
You had a bunch of little errors but as far as I can see, believe it or not, this may be your real problem.
read(fd[0], src, (strlen(src)));
My guess is that the first char is null and you are successfully reading 0 bytes.
Change to
read(fd[0], src, (sizeof(src)));
In your larger project make sure you read and write in loops. You are not guaranteed to read or write what you specify.
You may need to close fd[1] inside the else block first.
check this example
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
if (argc != 2) {
fprintf(stderr, "Usage: %s <string>\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
close(pipefd[1]); /* Close unused write end */
while (read(pipefd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);
write(STDOUT_FILENO, "\n", 1);
close(pipefd[0]);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
You have assumed that fork() will not fail.
But what about pipe()??
Assume both get completed successfully, then closing fds properly is requered.
your if-else blocks should be like this.
if((child = fork() == 0)
{
int len = strlen(argv[1]);
close(fd[0]);//I assume this was your typo. otherwise it would not even get compiled
write(fd[1], argv[1], len);
close(fd[1]);
exit(0);
}
else //Assuming process won't fail for now
{
close(fd[1]);
char src[10]; //Just using 10 for now, no arguments have more than 10 characters
read(fd[0], src, (strlen(src)));
fprintf(stderr, "%s\n", src);
close(fd[0]);
}

pipe call and synchronization

I'm experimenting some problems with this code:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 30
#define Error_(x) { perror(x); exit(1); }
int main(int argc, char *argv[]) {
char message[SIZE];
int pid, status, ret, fd[2];
ret = pipe(fd);
if(ret == -1) Error_("Pipe creation");
if((pid = fork()) == -1) Error_("Fork error");
if(pid == 0){ //child process: reader (child wants to receive data from the parent)
close(fd[1]); //reader closes unused ch.
while( read(fd[0], message, SIZE) > 0 )
printf("Message: %s", message);
close(fd[0]);
}
else{//parent: writer (reads from STDIN, sends data to the child)
close(fd[0]);
puts("Tipe some text ('quit to exit')");
do{
fgets(message, SIZE, stdin);
write(fd[1], message, SIZE);
}while(strcmp(message, "quit\n") != 0);
close(fd[1]);
wait(&status);
}
}
Code works fine but I can't explain why! There is no explicit sync between parent and child processes. If the child-process executes before parent, read must return 0 and the process ends, but for some reason it waits for the parent execution. How do you explain this? Maybe I'm missing something.
(Edited)
Since you didn't use O_NONBLOCK in pipe2, read is blocking by default. Therefore it waits until data are written into the pipe.

Resources