totemc
totemc

Reputation: 23

C: Not detecting EOF in pipe from parent to child process

I'm taking a programming course focusing on C, and we're going through pipes and processes at the moment. An in class activity was assigned where I have to have a parent create a child to print input that is piped from the parent. I can get the program to pipe input to the child and output it, but when I ctrl + D for EOF, I can still enter input (without output).

I tried following my logic on paper, and it seems correct, but something is wrong. I've tried to hardcode a phrase that I could write so that I can exit my child, but I get broken pipes when I try to remedy the situation.

Here are my 2 files:

newshell.c

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

int main(void){
    pid_t child1;
    int fd[2];
    char buffer1[100];
    int bytes;

    pipe(fd);
    child1 = fork();

    if (child1 == 0){
        dup2(fd[0],fileno(stdin));
        close(fd[1]);
        printf("You are in the child.\n");
        execlp("./printdata","printdata.c",0);
    }
    else {
        dup2(fd[1],fileno(stdout));
        close(fd[0]);
        while(fgets(buffer1,sizeof(buffer1),stdin) != NULL){
            write(fd[1],buffer1,(strlen(buffer1)+1));
        }
        write(fd[1],"999",sizeof("999"));
        wait(0);
        close(fd[1]);
        close(fd[0]);

        printf("Child ended. You are in the parent.\n");
    }
    return 0;
}

printdata.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void){
    char buffer[100];
    int bytes;
    printf("You're in the new process\n");
    while(bytes = read(fileno(stdin),buffer,sizeof(buffer)) >= 0){
        printf("%s\n",buffer);
        if (strcmp(buffer,"999") == 0){
            return 0;
        }
    }
    printf("Done here\n");
    return 0;
}

The logic here is that I create a child process in the parent that waits for input from the parent. I hardcoded a 'sentinel' (as my professor calls it) since my EOF wasnt being detected when I input it. The teacher accepted what I had since most people didn't finish the assignment, but I want to know why it isn't working for my own sake.

Thank you.

Upvotes: 2

Views: 1312

Answers (2)

William Pursell
William Pursell

Reputation: 212356

The parent needs to close fd[1] before it calls wait. As long as any process has the write side of the pipe open, the read in the child is going to block. In your case, the parent is holding the write side open, waiting for the child to terminate. And the child is blocked on a read waiting for the parent to close the write side of the pipe. In other words, write:

 close(fd[1]);
 wait(0);

And, as ctx points out, you need to either close stdout in the parent, or stop the pointless dup2.

Upvotes: 1

Ctx
Ctx

Reputation: 18420

The point is: When you press CTRL+D, you signal EOF on stdin of the parent. So the parent leaves this loop

while(fgets(buffer1,sizeof(buffer1),stdin) != NULL)

since fgets() returns NULL on EOF.

But now, you need to close fd[1] and fileno(stdout) (since you dupped it and do both before calling wait(0)), because closing the last filedescriptor refering to that pipe will signal EOF on input to the child process! It is a bit unclear to me why you dup2() fd[1] to fileno(stdout) anyway, maybe you should leave that out.

After these modifications it should work as expected.

Upvotes: 2

Related Questions