Ghimpu Lucian Eduard
Ghimpu Lucian Eduard

Reputation: 520

Am I using close() wrongly?

I'm trying to make a program that runs any given Linux command until the users inputs "stop".

The father should make a child, which should also make a child.

So let's say A is the father, B is the son and C is the grandson.

A -> reads the command from user input and sends it to B

B -> reads the command from a pipe and sends it to C

C -> reads the command from the pipe and will use execl. The output should be sent to a pipe which is sent to B, and then B will display the output to the screen.

So I will have 3 pipes: 1 form A to B, 1 from B to C, and 1 form C to B.

pipe p1 : A to B
pipe p2 : B to C
pipe p3 : C to B

Here's my code:

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


int main()
{   
    int p1[2], p2[2],p3[3];
    pipe(p1);
    pipe(p2);
    pipe(p3);
    char cmd[20],buffer[128];

    while(1<2)
    {

        printf("Type a cmd: \n");
        scanf("%s20",cmd);


        if(strcmp(cmd,"stop")==0)
        {
            break;
        }
        else
        {
            close(p3[1]);
            close(p3[0]);
            close(p1[0]);
            close(p2[1]);
            close(p2[0]);

            write(p1[1],&cmd,sizeof(char)*20);
            if(fork()==0)
            {   

                close(p1[1]);
                close(p2[0]);
                close(p3[1]);

                read(p1[0],&cmd,sizeof(char)*20);
                write(p2[1],&cmd,sizeof(char)*20);

                if(fork()==0)
                {
                    close(p1[0]);
                    close(p1[1]);
                    close(p2[1]);
                    close(p3[0]);

                    read(p2[0],&cmd,sizeof(char)*20);
                    char bin[20]="/bin/";
                    strcat(bin,cmd);

                    dup2(p3[1],1);
                    execl(bin,bin,NULL);
                    exit(1);
                }

                wait(0);
                dup2(p3[0],0);
                while(read(p3[0],&buffer,sizeof(char)))
                {
                    printf("%s",buffer);
                }
                exit(1);    
            }   
        }
        wait(0);
    }
    return 0;
}

I think I'm using close() wrongly because I don't understand exactly what it does. AFAIK it's used because every time I use fork(), the FD is duplicated.

So far, it does compile and run, but if I input "ls", the program terminates.

If I remove all calls to close(), "ls" will work, but it will block, not allowing me to type a second command.

Upvotes: 0

Views: 86

Answers (1)

ilkkachu
ilkkachu

Reputation: 6517

Your program creates three pipes, then closes two of them (p2 and p3) completely before calling fork(). It also closes the read end of p1 at the same time. Your child processes will not get any usable file handles.

pipe(p1);
pipe(p2);
pipe(p3);
char cmd[20],buffer[128];

while(1<2) {
    ...
    else {
        close(p3[1]);
        close(p3[0]);
        close(p1[0]);
        close(p2[1]);
        close(p2[0]);
        ...
        write(p1[1],&cmd,sizeof(char)*20);

After the fork, the child closes the single remaining pipe file handle (that's not a problem, really), and then tries to read from the file handle already closed by the parent (that is):

        if(fork()==0) {
            ...   
            close(p1[1]);
            ...
            read(p1[0],&cmd,sizeof(char)*20);

Usually, you'd want to fork first, then close the unneeded file handles after that, i.e. for parent to child communication, only the parent should close the read end, and only the child should close the write end.

Of course, if the parent closes one end of the pipe, then in the next iteration of the loop, that file handle will not be available to a new child process, so you'd need to create a new pipe at that point. Or keep all the fd's open in the main program (but I can't remember if that will cause issues with pipes).

As for the fd's you pass from child to grandchild, you'll need to treat them the same way when doing that fork. Though I would suggest doing a two-process experiment first.

Upvotes: 3

Related Questions