Two Children to execute ls -la | grep using pipes

420 views Asked by At

Hey there i have a Problem understanding where this Code Fails. It probably Fails where execvpe(grep) is executed(Console: "Grep Error").

Heres the Code:

int main(int argc, char *argv[]){

   printf("filter.c\n");

   int fd[2];
   pid_t ls,grep;


   if(argc<3){
    printf("Bitte 2 Argumente angeben <Verzeichnis> <Suchmuster>");     
    exit(-1);
   }

   char verzeichnis[256];
   char suchmuster [256];
   char kind       [256];

   strcpy(verzeichnis,argv[1]);
   strcpy(suchmuster ,argv[2]);

   if(pipe(fd)<0){
       printf("Pipe fehlgeschlagen\n");
       return -1;
   }

   if((ls=fork())==-1){
    //fehler
    printf("Fork ls fehlgeschlagen\n");
    exit(-1);
   } else if(ls==0){
    //kind
    printf("\nChild1 laueft(ls)\n");
    if(dup2(fd[1],STDOUT_FILENO)==-1){//dupliziert fd[1]
        printf("Dup failed(ls)\n");
        return -1;
    }

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


       char *argu[]={"-la",verzeichnis,NULL};
       if(execvpe("bin/ls",argu,NULL)==-1){//EXECVE
           printf("ls error");
           return -1;
       }
       return -1    }

   if((grep=fork())==-1){
       //fehler
       printf("Forken von grep fehlgeschlagen\n");
       return -1;
   } else if(grep==0){
       //children2
       printf("Child 2 lauft (grep)\n");
       if(dup2(fd[0],STDIN_FILENO)==-1){
           printf("dup2 fd[0] fehlgeschlagen\n");
           return -1;
       }
       close(fd[0]);
       close(fd[1]);


       char *argu[]={"bin/grep",suchmuster,NULL};       
       if(execvpe("bin/grep",argu,NULL)==-1){
           printf("Grep error");
           return -1;
       }
       return -1;
   }
   close(fd[0]);
   close(fd[1]);

   while(wait(NULL)>0);//while()
   return 0;


   //   exit(0);
   }

So i guess there is a Problem writing and or reading to/from the pipe. Does anyone know my Problem? :/

1

There are 1 answers

2
John Bollinger On BEST ANSWER

If the given path to the executable contains a / character then no search is performed. In that case the given path is resolved, if necessary, relative to the process's current working directory at the time of the call. That is rarely what one wants, and your case does not look like an exception. Morevover, if indeed you're going to specify a path to the binary instead of a simple name, then you get no advantage whatever from the path-searching variants of exec.

Furthermore, the last argument to execvpe() is supposed to be a pointer to the first element of a NULL-terminated array of char *. Although the pointed-to array might have no elements other than the terminator, I find no documentation that the argument itself is permitted to be NULL. If you indeed want to specify empty environments for the exec'ed programs, then, both execvpe() calls should take this general form:

char *argu[] = { "grep", suchmuster, NULL };      
char *env[] = { NULL };
if (execvpe("/bin/grep", argu, env) == -1) {

Furthermore, execing the external processes with empty environments is suspect, though not necessarily wrong. For this purpose I don't see much advantage, and you could save yourself some trouble by using one of the exec functions that just provides a copy of the calling process's environment to the exec'ed image. execvp(), for example, would be the one closest to execvpe() that has that characteristic.

Moreover, it seems a bit silly to pack up the program arguments into an array that you use only for the exec call. The varargs variants of exec circumvent any need to do that (execl(), etc.).

The exec functions return only on error. You can test the return value, but if these functions return at all then their return values are always -1.

Taking all that into account, therefore, and supposing that it would be ok to give grep and ls copies of the parent process's environment, this is the general form I would suggest for your exec calls:

       execl("/bin/grep", "grep", suchmuster, NULL);
       // an error occurred
       perror("execing grep");
       _Exit(1);