Frage

Ich bin der Umsetzung Rohrleitungen auf einem simulierten Dateisystem in C ++ (mit überwiegend C). Es braucht Befehle in dem Host-Shell laufen, aber die Rohrleitung selbst auf dem simulierten Dateisystem auszuführen.

Ich konnte dies erreichen mit den pipe(), fork() und system() Systemaufrufe, aber ich würde zu verwenden popen() bevorzugen (die Griffe ein Rohr zu schaffen, ein Prozess, gabeln und Leiten eines Befehls an die Shell). Dies kann nicht möglich sein, weil (ich glaube) Ich brauche von dem übergeordneten Prozess des Rohres, auf dem Kind Prozess Ende lesen, schreiben zu können, die Ausgabe wieder von dem Kind schreiben, und schließlich, dass die Ausgabe von dem Elternteil zu lesen. Der Mann Seite für popen() auf meinem System sagt ein bidirektionaler Rohr ist möglich, aber mein Code muss auf einem System mit einer älteren Version unterstützt nur unidirektionale Leitungen laufen.

Mit den getrennten Gespräche über, kann ich öffnen / schließen Rohre, dies zu erreichen. Ist das möglich mit popen()?

Für ein triviales Beispiel, ls -l | grep .txt | grep cmds Ich muss laufen:

  • Öffnen ein Rohr und Verfahren zu laufen ls -l auf dem Host; Lesen Sie seine Ausgabe zurück
  • die Ausgabe des ls -l zurück zu meinem Simulator
  • Öffnen Sie ein Rohr und Verfahren zu laufen grep .txt auf dem Rechner, auf dem verrohrt Ausgabe von ls -l
  • Rohr der Ausgang dieses zurück an den Simulator (klemmt hier)
  • Öffnen Sie ein Rohr und Verfahren zu laufen grep cmds auf dem Rechner, auf dem verrohrt Ausgabe von grep .txt
  • Rohr der Ausgang dieses zurück an den Simulator und drucken

Mann popen

Von Mac OS X:

  

Die popen() Funktion 'öffnet' a   Prozess durch einen bidirektionalen Schaffung   Rohr, Forking, und die Schale aufruft.   Alle Ströme geöffnet von früheren popen()   Anrufe in dem Eltern-Prozess geschlossen   in dem neuen Kind-Prozess.   Historisch gesehen wurde, popen() umgesetzt   mit einer unidirektionalen Leitung; daher,   nur viele Implementierungen von popen()   erlauben es dem Modus Argument angeben   Lesen oder Schreiben, nicht beide. weil   popen() wird nun umgesetzt eine mit   bidirektionale Leitung, das Modusargument   kann verlangen, Strom einen bidirektionale Daten.   Das Modus-Argument ist ein Zeiger auf einem   nullterminierten String, der sein muss,   ‚R‘ für das Lesen, ‚W‘ für das Schreiben, oder   'R +' für das Lesen und Schreiben.

War es hilfreich?

Lösung

Sie scheinen Ihre eigene Frage beantwortet zu haben. Wenn Ihr Code Bedürfnisse der Arbeit auf einem älteren System, das nicht popen Öffnung bidirektionale Leitungen nicht unterstützt, dann werden Sie nicht zu verwenden popen der Lage sein (zumindest nicht die, die geliefert wird).

Die eigentliche Frage würde über die genaue Fähigkeiten der älteren Systeme in Frage. Insbesondere muss ihre pipe Unterstützung zu schaffen bidirektionale Leitungen? Wenn sie einen pipe haben, die eine bidirektionale Rohr schaffen kann, aber popen das nicht, dann würde ich den Hauptstrom des Codes zu verwenden popen mit einem bidirektionalen Rohr schreiben, und eine Implementierung von popen liefern, die eine bidirektionale Rohr verwenden können , die in eine kompilierte wird verwendet, wo nötig.

Wenn Sie Systeme alt genug, um unterstützen müssen, dass pipe unterstützt nur unidirektionale Leitungen, dann sind Sie ziemlich fest mit der Verwendung von pipe, fork, dup2 usw., auf eigene Faust. Ich würde wahrscheinlich die noch wickle in einer Funktion, dass Werke fast wie eine moderne Version von popen, sondern ein Datei-Handle zurückzugeben, füllt in einer kleinen Struktur mit zwei Datei-Handles, eine für die Kinder stdin, die andere für das Kind stdout.

Andere Tipps

Ich würde vorschlagen, dass Sie Ihre eigene Funktion zu schreiben für Sie die Leitung / Forking / System-ing zu tun. Sie könnten die Funktion haben, Laich einen Prozess und Rückkehr Lese / Schreib-Datei-Deskriptoren, wie in ...

typedef void pfunc_t (int rfd, int wfd);

pid_t pcreate(int fds[2], pfunc_t pfunc) {
    /* Spawn a process from pfunc, returning it's pid. The fds array passed will
     * be filled with two descriptors: fds[0] will read from the child process,
     * and fds[1] will write to it.
     * Similarly, the child process will receive a reading/writing fd set (in
     * that same order) as arguments.
    */
    pid_t pid;
    int pipes[4];

    /* Warning: I'm not handling possible errors in pipe/fork */

    pipe(&pipes[0]); /* Parent read/child write pipe */
    pipe(&pipes[2]); /* Child read/parent write pipe */

    if ((pid = fork()) > 0) {
        /* Parent process */
        fds[0] = pipes[0];
        fds[1] = pipes[3];

        close(pipes[1]);
        close(pipes[2]);

        return pid;

    } else {
        close(pipes[0]);
        close(pipes[3]);

        pfunc(pipes[2], pipes[1]);

        exit(0);
    }

    return -1; /* ? */
}

Sie können addieren, was Funktionen, die Sie dort benötigen.

POSIX legt fest, dass der popen() Anruf nicht bi ausgelegt ist, zu schaffen, -directional Kommunikation:

  

Das Argument Modus popen () ist eine Zeichenkette, die angibt, I / O-Modus:

     
      
  1. Wenn Modus r ist, wenn das Kind Prozess gestartet wird, wird sein Dateideskriptors STDOUT_FILENO das beschreibbare Ende des Rohres, und der Dateideskriptor fileno (Strom) in dem anrufenden Prozess, in dem Strom die Stromzeiger von popen zurückgegeben wird () wird das lesbare Ende des Rohres sein.
  2.   
  3. Wenn Modus w, wenn das Kind dabei, seine Dateideskriptors STDIN_FILENO gestartet wird das lesbare Ende des Rohres, und der Dateideskriptor fileno (Strom) in dem anrufenden Prozess, in dem Strom die Stream-Zeiger von popen zurück ( ) wird das beschreibbare Ende des Rohres sein.
  4.   
  5. Wenn Modus ein anderer Wert ist, ist das Ergebnis nicht spezifiziert.
  6.   

All portablen Code wird keine Annahmen darüber hinaus machen. Die BSD popen() ist ähnlich zu dem, was Ihre Frage beschreibt.

Zusätzlich Rohre unterscheiden sich von Steckdosen und Jedes Rohr Dateideskriptor ist unidirektional. Sie würden zwei Rohre schaffen, eine für jede Richtung konfiguriert ist.

In einem der netresolve Backends Ich rede mit einem Skript und deshalb muss ich schreiben zu seine stdin und von seinem stdout lesen. Die folgende Funktion führt einen Befehl mit stdin und stdout zu einem Rohr umgeleitet. Sie können es an Ihre Bedürfnisse anpassen verwenden und anpassen.

static bool
start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
{
    int p1[2], p2[2];

    if (!pid || !infd || !outfd)
        return false;

    if (pipe(p1) == -1)
        goto err_pipe1;
    if (pipe(p2) == -1)
        goto err_pipe2;
    if ((*pid = fork()) == -1)
        goto err_fork;

    if (*pid) {
        /* Parent process. */
        *infd = p1[1];
        *outfd = p2[0];
        close(p1[0]);
        close(p2[1]);
        return true;
    } else {
        /* Child process. */
        dup2(p1[0], 0);
        dup2(p2[1], 1);
        close(p1[0]);
        close(p1[1]);
        close(p2[0]);
        close(p2[1]);
        execvp(*command, command);
        /* Error occured. */
        fprintf(stderr, "error running %s: %s", *command, strerror(errno));
        abort();
    }

err_fork:
    close(p2[1]);
    close(p2[0]);
err_pipe2:
    close(p1[1]);
    close(p1[0]);
err_pipe1:
    return false;
}

https://github.com/crossdistro/netresolve /blob/master/backends/exec.c#L46

(habe ich den gleichen Code in popen gleichzeitigen Lesen und Schreiben )

Kein Bedarf, zwei Rohre zu schaffen und eine FileDescriptor in jedem Prozess zu verschwenden. Verwenden Sie einfach eine Steckdose statt. https://stackoverflow.com/a/25177958/894520

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top