George M
George M

Reputation: 23

Dealing with pipes in C

I am trying to implement a shell in C language on Linux.This project that I am working on, asks to create a shell in C, starting from creating a very basic one (myShell), which goes deeper step by step.First I had to create a shell with simple commands like

ls,pwd,echo,date,time

(shell1).

After that, my Shell had to be improved so it could sort things from files (txt's for example) (shell2) and as it goes on, I had to do more by developing it, and make it execute commands like

sort -r,sort -u.(shell3).

Until the 3rd shell, I was working with redirections and everything was going well.

Now for the 4th shell, I am supposed to make it run commands with pipes, e.g. ls -l /home/ | sort > out.txt. I have managed to make the command work, the out.txt file gets created succesfully and is sorted accordingly. There is a while() on my code, so that after every command that I give to the shell it asks for the next one etc. etc.. But when the above example command is given and the pipes are used, the program stops. The terminal doesn't show "myShell4>" but Desktop$ and it basically exits the shell. Giving it simple commands like "ls -l" ,that don't use the pipes, works perfectly, so from that I realise that the problem is in the pipes and that they stop my program from looping.

The part where this happens in my code:

//CHILD
dup2(pipefd[1],1);
close(pipefd[0]);
execute(cmd,path,argm);

//PARENT
dup2(pipefd[0],0);
close(pipefd[1]);
execlp(cmd2,cmd2,NULL);

Any thoughts? Thanks in advance!

Upvotes: 0

Views: 178

Answers (1)

Diego
Diego

Reputation: 1819

The parent is the shell, right? Don't exec there; create children for both ends of the pipe and wait for them in the parent. If you do, the shell will be replaced and no longer run after the command ends.

Below is some pseudo-code for a pipe between two commands:

int pipefd[2];
pipe (pipefd);

// child for first command
if (fork () == 0) {
   // setup in redirection if any
   ...
   // setup out redirection
   close (pipefd[0]);
   dup2 (pipefd[1], STDOUT_FILENO);
   ...

   exec (cmd1, ...);
   exit (1);
}

// child for second command
if (fork () == 0) {
    // setup in redirection
    close (pipefd[1]);
    dup2 (pipefd[0], STDIN_FILENO);
    // setup out redirection if any
    dup2 (output_file_fd, STDOUT_FILENO);

    exec (cmd2, ...);
    exit (1);
}

close (pipefd[0]);
close (pipefd[1]);

// parent waits and then restarts the loop
wait (NULL);
wait (NULL);

Things get more complicated for a list of more than two commands connected by pipes.

Upvotes: 1

Related Questions