Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
418 views
in Technique[技术] by (71.8m points)

c++ - Toy shell not piping correctly

I'm not going to lie. This is a homework question. However, as far as I'm concerned, the points are gone baby gone. Right now, I'm just looking for an answer, because I -think- I might be insane.

The goal of this program is to execute the command ps -A | grep (inputstring) | wc -l in a way similar to how the shell does it. So, I spawn the processes, and have them wait on each other. The newest process, the great-grandchild, execlp("ps","ps","-A",NULL) which replaces itself with the ps -A process. Before it execlp, I make sure its standard output is going to the pipe output. The next process in line is wait()ing, and already has itself set up so that the input pipe goes to standard in, and standard out goes to the output pipe, and it will execute grep, and so on.

I'm almost positive I have it set up correctly. And yet... the program does. Not. Work.

#include <stdlib.h>
#include <iostream>
#include <string>

#define MAXLINE 1500
#define READ 0
#define WRITE 1

using namespace std;

int main( int argc, char** argv ) {
//* start of input block
if ( argc != 2 ) {
    cout << "Usage: ./a.out arg1" << endl;
    return 0;
}
string in = argv[1];
// end of input block */
int pipeA[2], pipeB[2], pid, stat;

// get our first set of pipes
if ( pipe(pipeA) < 0 ) {
    cerr << "Pipe error.
";
    exit(-1);
}
if ( pipe(pipeB) < 0 ) {
    cerr << "Pipe error.
";
    exit(-1);
}

// make the first fork
if ( (pid = fork() ) < 0 ) { cerr << "Fork error.
"; exit(-1); }

if ( pid > 0 ) {    // parent case
    wait(&stat);
} else {            // child case
    if ( (pid = fork()) < 0 ) { cerr << "Fork Error
"; exit(-1); }
    if ( pid > 0 ) {    // child
        wait(&stat);
        dup2(pipeA[READ],READ);
        execlp("wc","wc","-l",NULL);
    } else {    // grand-child
        if ( (pid = fork()) < 0 ) { cerr << "Fork Error
"; exit(-1); }
        if ( pid > 0 ) {    // still grand-child
            wait(&stat);
            dup2(pipeB[READ],READ);  
            dup2(pipeA[WRITE],WRITE); 
            close(pipeB[READ]);
            execlp("grep","grep",in.c_str(),NULL);
        } else {    // great grand-child
            dup2(pipeB[WRITE],WRITE); // t now goes to pipeB[1]
            close(READ);
            close(pipeB[READ]);
            execlp("ps", "ps", "-A", NULL);
        }
    }
}
return 0;
}

EDIT: Changed to the two-pipe variant of my code.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I'm virtually certain this is what you're trying to do. Apologies in advance for the sloppy coding. its somewhat late here and I really should be sleeping right now:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>

#define READ 0
#define WRITE 1

// ps -A | grep argv[1] | wc -l

int main( int argc, char** argv )
{
    // start of input block
    if ( argc != 2 )
    {
        std::cout << "Usage: ./a.out arg1" << std::endl;
        return 0;
    }
    
    // make local copy of argument
    std::string in = argv[1];
    int fd1[2], fd2[2], pid;
    
    // allocate two pipe sets
    if (pipe(fd1) < 0 || pipe(fd2) < 0)
    {
        perror("Failed to create pipe.");
        return EXIT_FAILURE;
    }
    
    // launch first child process.
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(1)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // wc -l process. 
        //  stdin  = fd2(read)
        close(fd1[READ]);
        close(fd1[WRITE]);
        close(fd2[WRITE]);
        dup2(fd2[READ],STDIN_FILENO);
        execlp("wc","wc","-l",NULL);
    }
    
    // fork again. this time for grep
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(2)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // grep argv[1] process.
        //  stdin  = fd1(read)
        //  stdout = fd2(write)            
        close(fd1[WRITE]);
        close(fd2[READ]);
        dup2(fd2[WRITE], STDOUT_FILENO);
        dup2(fd1[READ], STDIN_FILENO);
        execlp("grep", "grep", in.c_str(), NULL);
    }
    
    //  fork once more. this time for ps -A
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(3)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // ps -A process.
        //  stdout = fd1(write)
        close(fd2[WRITE]);
        close(fd2[READ]);
        close(fd1[READ]);
        dup2(fd1[WRITE], STDOUT_FILENO);
        execlp("ps", "ps", "-A", NULL);
    }
    
    int stat=0;
    wait(&stat);

    return EXIT_SUCCESS;
}

On my system, ps -A reports 141 lines, of those 41 have the word System somewhere within, verified by simply running ps -A | grep System | wc -l. The above code generates precisely the same output.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...