2016-11-20 4 views
-2

Ich versuche, eine einfache Shell in c zu schreiben. Im Moment versuche ich, Rohre zur Arbeit zu bringen. Ich habe eine Struktur c, die ich in diese Funktion füttere, es enthält einen Platz zum Speichern der Rohr Datei-Deskriptor pipfd und enthält auch Informationen über die End-Tag jedes Befehls c->type (dies kann sein | || & & & etc). CommandPrev verfolgt nur den letzten Befehl, damit ich sehen kann, ob der Befehl unmittelbar zuvor ein Pipe-Tag hatte.Warum sprechen meine Rohre nicht miteinander?

Nachdem ich diese Funktion zu beenden, gebe ich dem Kind pid (den Wert zurück) zu waitpid auf dem Befehl, den ich mit execvp genannt warten

Wenn ich Befehle ausführen wie echo foo | echo bar I bar als Ausgang genau das bekommen, wie Ich würde erwarten und alles funktioniert super. Mein Problem ist, wenn ich versuche, einen Befehl auszuführen, der tatsächlich die Eingabe aus der ersten Hälfte der Pipe verwendet, bleibt alles hängen. Wenn ich etwas wie echo foo | wc -c ausführen bekomme ich keine Ausgabe und es hängt einfach für immer.

Ich kann sehen, dass diese Funktion für diese Art von Befehlen beendet ist, weil ich bei der Rückkehr drucke. Was passiert, ist, dass der Befehl, den ich mit execvp anrufe, nie passiert, also wartet meine Wartezeit auf immer.

Ich denke, dass irgendwie meine Verbindung zwischen den beiden Enden meiner Pfeife gebrochen ist. Entweder werden Dinge nie geschrieben, oder sie werden nie gelesen, oder das empfangende Ende der Pipe erkennt nie, dass die Schreibseite fertig ist und wartet nur für immer. Ich rufe alle meine Pfeifen sofort an, also bezweifle ich, dass es die letzte ist ... aber ich bin mir nicht sicher, wie ich diese drei Szenarien testen soll.

Dies ist mein Code:

pid_t start_command(command* c, pid_t pgid) { 
    (void) pgid; 

    // If its a pipe token, create a shared pipe descriptor 
    if (c->type == TOKEN_PIPE){ 
     pipe(c->pipefd); 
    } 

    // Fork a child process, run the command using `execvp` 
    pid_t child = fork(); 
    if (child == 0) { 
     // writing side of the pipe 
     if (c->type == TOKEN_PIPE){ 
      dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO); 
      close(c->pipefd); 
     } 
     // receiving side of the pipe 
     else if (commandPrev->type == TOKEN_PIPE){ 
      dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO); 
      close(commandPrev->pipefd); 
     } 

     // run the command 
     if (execvp(c->argv[0], c->argv) == -1) { 
      // fork failed 
      exit(-1); 
     } 
    } 
    else{ 
     // clean up, clean up, everybody, everywhere 
     if (commandPrev->type == TOKEN_PIPE){ 
      close(commandPrev->pipefd); 
     } 
    } 
    printf("return %i\n", getpid()); 
    return child; 
} 

Thank you!

+0

Überprüfen Sie Ihre syscalls für Fehler, sie werden nicht automatisch gedruckt. 'close (c-> pipefd);' scheint zu versuchen, ein Array zu schließen. –

+0

Verwenden Sie das 'shell'-Tag für Fragen, bei denen die Kenntnis der Shell-Spezifikationen und -Sprachen für die Beantwortung hilfreich sein kann. Das ist sehr, sehr selten wahr, wenn Leute Spielzeugmuscheln für die Schule schreiben. –

+0

@CharlesDuffy Mein schlechtes! Ich wusste es nicht, Entschuldigung – Twiigs

Antwort

0

Wie der andere Kommentator sagt, sehen Sie aus, als ob Sie versuchen, ein Array zu schließen. So etwas sollte besser funktionieren:

// writing side of the pipe 
if (c->type == TOKEN_PIPE){ 
    close(c->pipefd[READ_SIDE]); 
    dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO); 
    close(c->pipefd[WRITE_SIDE]); 
} 
// receiving side of the pipe 
if (commandPrev->type == TOKEN_PIPE){ 
    close(commandPrev->pipefd[WRITE_SIDE]); 
    dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO); 
    close(commandPrev->pipefd[READ_SIDE]); 
} 

Alternativ können Sie die aktiven Seiten des Rohres nach einem waitpid Anruf in der Mutter schließen. Etwas wie dieses:

waitpid(child, &status, 0); 

if (commandPrev->type == TOKEN_PIPE){ 
    close(commandPrev->pipefd[READ_SIDE]); 
} 
if (c->type == TOKEN_PIPE){ 
    close(c->pipefd[WRITE_SIDE]); 
} 
Verwandte Themen