Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pipes, dup2 and exec()

I have to write a shell that can run pipes. For example commands like ls -l | wc -l". I have successfully parsed the command given by the user as below:

"ls" = firstcmd

"-l" = frsarg

"wc" = scmd

"-l" = secarg

Now I have to use two forks since the commands are two and a pipe. The code block that I wrote to exec the command is the following:

pid_t pid;
int fd[2];

pipe(fd);
pid = fork();

if(pid==0)
{        
    dup2(fd[WRITE_END], STDOUT_FILENO);
    close(fd[READ_END]);
    execlp(firstcmd, firstcmd, frsarg, (char*) NULL);
}
else
{ 
    pid=fork();

    if(pid==0)
    {
        dup2(fd[READ_END], STDIN_FILENO);
        close(fd[WRITE_END]);
        execlp(scmd, scmd, secarg, (char*) NULL);
    }
}

So when I run my shell and I enter the command ls -l | wc -l (for example) the result from the execs doesn't show up but the shell keeps running normally.

The strange thing is that the result of the command shows only when I terminate my shell with "exit" or "^C".

What is wrong with that output? Why doesn't it show up right after I enter the command?

like image 374
Aris Kantas Avatar asked Nov 24 '15 02:11

Aris Kantas


People also ask

What is dup2 in pipe?

We use the dup2() system call to duplicate the writing file descriptor of the pipe (pfd[1]) onto the standard output file descriptor, 1. We don't need the input end of the pipe (pdf[0]), so we close it. 6. Once that is done, we simple call execvp() to run the program.

How does dup2 work in C?

The dup2() function duplicates an open file descriptor. Specifically, it provides an alternate interface to the service provided by the fcntl() function using the F_DUPFD constant command value, with fildes2 for its third argument. The duplicated file descriptor shares any locks with the original.

What is pipe Linux?

A pipe is a form of redirection (transfer of standard output to some other destination) that is used in Linux and other Unix-like operating systems to send the output of one command/program/process to another command/program/process for further processing.


Video Answer


1 Answers

You need to close all the pipe descriptors in both the parent process and the child process (after duplication in the child process). In your code the main issue is that, the wc process does not exit because there are still writers present (since the parent process has not closed the write end). Changes shown below. I have also added the waitpid in the parent process to wait for the wc process.

pid_t pid;
int fd[2];

pipe(fd);
pid = fork();

if(pid==0)
{
    dup2(fd[WRITE_END], STDOUT_FILENO);
    close(fd[READ_END]);
    close(fd[WRITE_END]);
    execlp(firstcmd, firstcmd, frsarg, (char*) NULL);
    fprintf(stderr, "Failed to execute '%s'\n", firstcmd);
    exit(1);
}
else
{ 
    pid=fork();

    if(pid==0)
    {
        dup2(fd[READ_END], STDIN_FILENO);
        close(fd[WRITE_END]);
        close(fd[READ_END]);
        execlp(scmd, scmd, secarg,(char*) NULL);
        fprintf(stderr, "Failed to execute '%s'\n", scmd);
        exit(1);
    }
    else
    {
        int status;
        close(fd[READ_END]);
        close(fd[WRITE_END]);
        waitpid(pid, &status, 0);
    }
}
like image 117
user1969104 Avatar answered Sep 30 '22 20:09

user1969104