tags:

views:

105

answers:

1

I have a homework to do that says the following:

Write a program in C that creates a child who will also create a child, make a pipe between the three processes, the fist process(father) will connect the second(child) and the child will connect with the third (child of the child). Our program should display the total number of system users who use bash as default shell. The result of the program should be identical to the "cat / etc / passwd | grep" / bin / bash $ "| wc-l"

I am confused with the first child and the method that we close the first pipe and open the second in the same time. If you reply me with the right code I 'll undestand it right once.

Thank you.

Here is what I 've wrote so far:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
main()
{
int pid, pid2;
int fd[2];
int fd2[2];
char *arg[3];
char *arg2[3];
char *arg3[3];  
if (pipe(fd) == -1)
{
    perror("pipe");
    exit(1);
}
pid = fork();
if (pid == -1)
{
    perror("fork");
    exit(2);
}
if (pid == 0)
{
    if (pipe(fd2) == -1)
    {
        perror("pipe");
        exit(11);
    }
    pid2=fork();
    if(pid2 == -1)
    {
        perror("fork 2");
        exit(22);
    }
    if (pid2 == 0)
    {
        //i am child 2 (child of the child)
        close (fd2[1]);
        dup2 (fd2[0],0);
        close (fd2[0]);
        arg3[0] = "wc";
        arg3[1] = "-l";
        arg3[2] = NULL;
        execvp("wc", arg3);
        perror("execvp second child");
    }
    else
    {
        //i am child 1
        close (fd[1]);
        dup2(fd[0],0);
        close (fd[0]);
        close (fd2[0]);
        dup2(fd2[1],1);
        close (fd2[1]);
        arg2[0] = "grep";
        arg2[1] = "/bin/bash$";
        arg2[2] = NULL;
        execvp("grep", arg2);
        perror("execvp first child");
    }
}
else
{
    //i 'm the father
    close (fd[0]);
    dup2(fd[1],1);
    close (fd[1]);
    arg[0] = "cat";
    arg[1] = "/etc/passwd";
    arg[2] = NULL;
    execvp("cat", arg);
    perror("execvp father");    
}   

}

+2  A: 

Your program very nearly works. What's missing is

    //i am child 2 (child of the child)
    close (fd[1]);
    close (fd[0]);

The pipe you called fd is for communicating between 'cat' and 'grep'. What's happening in your current code is that cat dumps the file and exits, closing its output. Grep reads all of that and waits for the EOF on its input. Since "child 2" still has the input side of the pipe open (it inherited it via fork), grep waits forever. If run your program and then type ps you should see a grep and a wc hanging around waiting to finish.

The other thing you would normally do when constructing a pipeline like this is arrange it so that the final task (in this case wc) is the one that the shell is waiting for. As written, when your program is run from the shell it will appear to finish when cat finishes, and the output of wc will print as if from a background task. If you arrange the pipe so that wc is under "i am child 1" then the shell will be waiting for wc instead.

Alternatively you could fork all of the three processes off and "child 1" would invoke wait() to wait for all of them before exiting. That waiting process would be like your own tiny shell.

Ben Jackson
Thank you for your help!!! What can I do to my program to stop waiting...? (answer in code please)
George
You only have to add the two lines I showed above. By closing fd[1] there is only one process (cat) that still has fd[1] open, and when it exits, fd[1] is closed and fd[0] sees EOF, allowing grep to finish.
Ben Jackson
George
Ben Jackson
Sorry but my english aren't the best availabe and I can't understand tottaly your answer and this is why i prefer to answer with code... Another question that I have is if we can make the same code with FIFO and in what way?Thanks for your patience again.(I'm newbie to linux...)
George
Your shell is waiting for "i'm the father" to finish. cat finishes and your shell prints a prompt. Then wc finishes and prints the result. Simple fix: Move "wc" into "i'm the father". Then your shell will wait for wc.
Ben Jackson
I cannot fix it... grep: (standard input): Bad file descriptor..can you give me code please?
George