Bind the pipe to stdin, there is a blocking problem - c

I want to associate the standard output of the parent process with the standard input of the child process through an anonymous pipe. I did achieve my needs, but I also encountered a problem: the program blocks when calling scanf, even if stdin is set to none Buffer, replace scanf with read to run normally! I know this has something to do with the standard I/O function buffer, but I don't know the internal reason, I hope I can get help, thank you!
Code:
int main(void)
{
int fd[2];
int cpid;
pipe(fd);
if((cpid = fork()) < 0)
{
perror("fork error");
exit(-1);
}
else if(cpid == 0)
{
sleep(1);
char buf[100] = {0};
close(fd[1]);
if(dup2(fd[0], 0) < 0)
{
perror("parent - dup2 error");
exit(-1);
}
setbuf(stdin, NULL);
scanf("%s", buf);
//read(0, buf, 100);
printf("child: \n\t%s", buf);
return 0;
}
sleep(1);
close(fd[0]);
if(dup2(fd[1], 1) < 0)
{
perror("parent - dup2 error");
exit(-1);
}
setbuf(stdout, NULL);
printf("123");
wait(NULL);
return 0;
}

Problem is that to scanf to terminates its reading, necessitate that the data is ended in some way.
You are reading a string, but how scanf can know that there is nothing after 123? So it is waiting for something, either the end of communication, space, newlines, whatever can tell it that a string is fully available.
Try adding a simple spacing, a new line in the writing part:
printf("123 ");
or
printf("123\n");
Note that as is, you can not use the closing solution, just because you forgot to close the original descriptors after the dup.
Rewrite the code like this:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(void) {
int fd[2];
int cpid;
pipe(fd);
if((cpid = fork()) < 0) {
perror("fork error");
exit(-1);
}
else if(cpid == 0) {
sleep(1);
char buf[100] = {0};
close(fd[1]);
if(dup2(fd[0], 0) < 0) {
perror("parent - dup2 error");
exit(-1);
}
close(fd[0]); // close not useful original desriptor
setbuf(stdin, NULL);
scanf("%s", buf);
printf("child: \n\t%s", buf);
return 0;
}
sleep(1);
close(fd[0]);
if(dup2(fd[1], 1) < 0) {
perror("parent - dup2 error");
exit(-1);
}
close(fd[1]); // close not useful original desriptor
setbuf(stdout, NULL);
printf("123");
close(1); // close the "connexion" (ie the last open for writing descriptor on the pipe)
wait(NULL);
return 0;
}

Related

Pipe to sort and back to main

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.

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;

duplicate file descriptor to point to pipe

My program will pick a random number and have the use guess what it is. I am almost done with it, except I need to duplicate the file descriptors to point to a pipe, and I'm not entirely sure how to do that. I think i'd have to use dup2, but I'm not entirely sure how to implement it. Anything helps. Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int pid;
int n;
char buf[101];
int pfdA[2];
int pfdB[2];
// CREATE FIRST PIPE
if (pipe(pfdA) == -1)
{
perror("pipe failed");
exit(-1);
}
// CREATE 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
// CLOSE ends of FIRST pipe you don't need anymore
close(pfdA[0]);
close(pdfA[1]);
// duplicate file descriptor 1 to point to SECOND pipe
// CLOSE 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);
// SEND NUM to Child process
write(pdfA[1], NUM, strlen(NUM));
// READ 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);
}
I think i'd have to use dup2, but I'm not entirely sure how to
implement it.
You are right.
// duplicate file descriptor 0 to point to FIRST pipe
dup2(pfdA[0], 0);
...
// duplicate file descriptor 1 to point to SECOND pipe
dup2(pfdB[1], 1);

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]);
}

How to loop through stdin & pipe output to a child execl command in C?

I have been trying to figure out how to loop through stdin from a file, then send it to a child process who sorts int using execl(). The code below works in that it takes the file & sorts the lines, but I am not seeing the "end of sentence" debug string I have added. Somehow this part of the code is being bypassed. I could use some help understanding the flow of data as it comes in from the file, then gets printed out to the screen.
int main(int argc, char *argv[])
{
pid_t p;
int status;
int fds[2];
FILE *writeToChild;
char word[50];
if(pipe(fds) == -1) {
perror("Error creating pipes");
exit(EXIT_FAILURE);
}
switch(p = fork()) {
case 0: //this is the child process
close(fds[1]); //close the write end of the pipe
execl("/usr/bin/sort", "sort", (char *) 0);
break;
case -1: //failure to fork case
perror("Could not create child");
exit(EXIT_FAILURE);
default: //this is the parent process
close(fds[0]); //close the read end of the pipe
writeToChild = fdopen(fds[1], "w");
wait(&status);
break;
}
while (fscanf(stdin, "%s", word) != EOF) {
//the below isn't being printed. Why?
fprintf(writeToChild, "%s end of sentence\n", word);
}
return 0;
}
Your primary problem is that you have the wait() in the wrong place. You wait for the child to die before you've written anything to it. You also have a secondary problem that don't redirect the read end of the pipe to the sort process's standard input.
You're not closing fds[0] in the child; cleanliness suggests that you should. You do need to fclose(writeToChild) before waiting; the sort won't stop until the parent has closed the pipe to the child.
These changes (and a few other ones) lead to:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
pid_t p;
int status;
int fds[2];
FILE *writeToChild;
char word[50];
if (pipe(fds) == -1)
{
perror("Error creating pipes");
exit(EXIT_FAILURE);
}
switch (p = fork())
{
case 0: //this is the child process
close(fds[1]); //close the write end of the pipe
dup2(fds[0], 0);
close(fds[0]);
execl("/usr/bin/sort", "sort", (char *) 0);
fprintf(stderr, "Failed to exec sort\n");
exit(EXIT_FAILURE);
case -1: //failure to fork case
perror("Could not create child");
exit(EXIT_FAILURE);
default: //this is the parent process
close(fds[0]); //close the read end of the pipe
writeToChild = fdopen(fds[1], "w");
break;
}
if (writeToChild != 0)
{
while (fscanf(stdin, "%49s", word) != EOF)
{
//the below isn't being printed. Why?
fprintf(writeToChild, "%s end of sentence\n", word);
}
fclose(writeToChild);
}
wait(&status);
return 0;
}

Resources