3

I'm trying to simulate the behaviour of the terminal in linux building a minishell in c code, but I've encountered a problem when trying to implement command sequences, since the output of the first one won't be properly received by the next one through pipes. The way we want to implement this is passing the standard output of the first command (child 1) to the second one (child 2, born after child 1 is dead) via pipes, and using this as the standard input for the second. Please note that I'm using a fork() statement just at the beginning of the for loop, so each iteration creates a child that dies before another one is born.

I've tried to use other commands other than dup2 but nothing won't work. Furthermore, the first command seems to return the list already sorted when using a command example like "ls | sort" and intercepting the output of the first one.

argvv is a char *** type variable that contains one entry for each command in the first level, and for each command an entry with each argument in the second level

/*pipes have been created already; p1, p2 (p2 only useful for sequences of 3 commands)*/

for (command_counter = 0; command_counter < num_commands; command_counter++)
        {

            int chid = fork();

            switch (chid)
            {
                case 0: // child


                //COMMAND EXECUTION


                /*Running commands with pipes */

                    /*Data is only ran through pipes if there's more than one command*/

/*we only implemented the version for two commands so far*/

                /*...*/
                if(num_commands==2)
                {
                    /*Data is only ran through pipes if there's more than one command*/
                    if(command_counter==0)
                    {//The first command takes no input from pipe
                        close(p1[0]);
                        close(p2[0]);
                        close(p2[1]);
                        dup2(p1[1], 1);
                        close(p1[1]);
                    }
                    if(command_counter==1)
                    { //Last command takes input only, output goes to stdout or output file
                        close(p2[1]);
                        close(p2[0]);
                        close(p1[1]);
                        dup2(p1[0], 0);
                        close(p1[0]);
                    }

                }


                execvp(argvv[command_counter][0], argvv[command_counter]);

                case -1:    // error
                perror("Couldn't create child process\n");
                exit(-1);

                default:
                    // father
                        waitpid(chid, 0, 0);

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

I expected the program to work fine, but it just stops in the execution of the sort command. I'm pretty sure the fault is in the use of dup2 about the second for iteration, but I'd like to know for sure what should I do to fix it

alestarbucks
  • 119
  • 1
  • 9

1 Answers1

1

You have got a couple of things right:

  1. You are creating a new process and checking the status correctly.
  2. You are right to close all file handles of the pipe which the child and the parent processes do not need.

What you need to get right:

When child[command_counter] is created, it shares the pipe of child[command_counter-1] (if command_counter >= 0), and the pipe of child[command_counter +1] (if command_counter +1 < num_commands).

You should start waiting for children only after the last child is created. If you start waiting earlier, then one of the pipes might get filled, and the system will start waiting for a process to read the pipe. But if the last child was not created yet, then nobody is reading the pipe, and the whole thing enters a deadlock. (nobody is reading a pipe when the writer is waiting for it to be read-from).

If you create all processes up-front, before starting to wait, then don't forget to close all pipes in the parent process before starting to wait. Otherwise, when the first child finishes, the following child will not get an EOF signal since the pipe is still open (by the parent).

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33