2011-01-30 3 views
4

Essayer de mettre en place une coque, principalement de la tuyauterie. J'ai écrit ce cas de test dont je m'attends à simplement ls à wc ... ça ne marche vraiment pas comme prévu. Il imprime ls sur le terminal puis imprime la mémoire épuisée. Je suis très perdu dans la façon de résoudre ce problème et de le faire fonctionner. find_path fonctionne dans tous mes tests. Editer - Je dois utiliser execv pour le projet, c'est une chose de classe, mais je l'ai essayé avec execvp juste au cas où il ferait exactement la même chose. Aussi ce n'est qu'un exemple, un test pour voir pourquoi ça ne marche pas, j'appelle fork deux fois pour les deux commandes et waitpid car je n'ai rien d'autre à faire.C Unix Pipes Exemple

#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdio.h> 
int find_path(char* execname, char** dst) 
{   
     char *path = getenv("PATH"); 
     path = strdup(path); 
     char *pos; 
     path = strtok_r(path, ":", &pos); 
     char *originalpath = path; 
     do 
     { 
       char* test = (char*)calloc(strlen(path) + strlen(execname) + 2, sizeof(char)); 
       test = strcpy(test, path); 
       int testlen = strlen(test); 
       (*(test+testlen)) = '/'; 
       strcpy(test + testlen + 1,execname); 
       struct stat buf; 
       int result = stat(test, &buf); 
       if (result == 0) 
       { 
         *dst = test; 
         free (originalpath); 
         return 1; 
       } 
       else 
       { 
         free(test); 
       } 

     } while ((path = strtok_r(NULL, ":", &pos)) != NULL); 
     free(originalpath); 
     return 0; 
} 

int main() 
{ 
    char *cmd1 = "ls"; 
    char *cmd2 = "wc"; 
    int filedes[2]; 
    pipe(filedes); 
    char** argv = (char**)calloc(1, sizeof(char*)); 
    argv[0] = (char*)malloc(sizeof(char*)); 
    argv[0] = NULL; 

    pid_t pid = fork(); 
    if (pid == 0) 
    { 
     char *path; 
       find_path(cmd1, &path); 
     dup2(filedes[1],stdout); 

     execv(path,argv); 
    } 
    pid = fork(); 
    if (pid == 0) 
    { 
     dup2(filedes[0], stdin); 
     char *path; 
     find_path(cmd2, &path); 
     execv(path, argv); 

    } 
    else 
     waitpid(pid); 

} 
+0

Avez-vous regardé la course de l'an dernier "Comment implémenter un shell avec des questions ... fork ... pipe ... exec ..."? La réponse est probablement dans un (plus probablement beaucoup) de ceux. –

Répondre

8

Souvent, lorsqu'il est difficile de déboguer un programme, il est préférable de le simplifier un peu pour éliminer les sources d'erreur. Voici votre programme, simplifié pour supprimer find_path comme source d'erreurs:

#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <stdio.h> 

int main(void) 
{ 
    int filedes[2]; 
    pipe(filedes); 

    /* Run LS. */ 
    pid_t pid = fork(); 
    if (pid == 0) { 
     /* Set stdout to the input side of the pipe, and run 'ls'. */ 
     dup2(filedes[1], 1); 
     char *argv[] = {"ls", NULL}; 
     execv("/bin/ls", argv); 
    } else { 
     /* Close the input side of the pipe, to prevent it staying open. */ 
     close(filedes[1]); 
    } 

    /* Run WC. */ 
    pid = fork(); 
    if (pid == 0) { 
     dup2(filedes[0], 0); 
     char *argv[] = {"wc", NULL}; 
     execv("/usr/bin/wc", argv); 
    } 

    /* Wait for WC to finish. */ 
    waitpid(pid); 
} 

Cela devrait se comporter comme prévu.

Au cours de simplification, quelques erreurs sont sortis:

  • argv[] n'était pas correctement configuré, en particulier, argv [0] était à NULL;
  • Le programme ne fermait pas le côté d'entrée du tuyau qui était donné à ls. Quand ls a terminé, le tuyau n'était pas fermé (parce que le processus wc l'avait toujours ouvert), empêchant wc de finir jamais.
  • Le programme a été source de confusion les valeurs stdout et stdin (qui sont de type FILE*) avec les numéros de descripteur de fichier 0 et 1 (utilisé par dup, pipe, etc.)
+0

Génial, vous avez toutes mes erreurs stupides. Dans mes tests, j'ai essayé tout ce que vous avez suggéré, sauf que j'ai complètement oublié le premier argument de ligne de commande passé devrait être le nom de l'exécutable! Merci beaucoup. – Ben

1

Il y a beaucoup que vous pouvez faire pour améliorer ce code (par exemple briser ce en fonctions plus petites serait un début), mais je soupçonne que votre hors de question de la mémoire est du code dans find_path(), que vous pourrait éviter complètement en utilisant execvp qui permettra de localiser l'exécutable en utilisant le mécanisme standard PATH pour vous. C'est probablement une bonne idée d'installer un gestionnaire de signal en utilisant sigaction pour gérer SIGCHLD et d'appeler waitpid depuis le gestionnaire de signal, au lieu d'invoquer simplement waitpid() ad-hoc comme vous le faites. Vous semblez forcer plus de fois que vous voulez, et vous ne vérifiez pas les erreurs. J'espère que ces suggestions aident.

+0

J'ai édité mon post pour expliquer pourquoi j'utilise find_path, mais execvp fait la même chose, et attendre n'est peut-être pas le meilleur moyen mais je crée simplement un exemple du problème ici, donc pas vraiment lié à l'erreur. – Ben