Frage

Ich habe viel Mühe, den Aufbau einer ‚Mittelsmann‘ Logger - die Absicht, sie auf dem Weg in / usr / bin über ein Element zu platzieren ist und erfassen alles zu und von der Anwendung gehen. (Black-Box-3rd-Party-App aus irgendeinem Grunde FTP scheitern.) Sobald laufen, gabelt der Mittelsmann, umleiten stdout und stdin zu / von Rohren, die die übergeordneten Kontrolle hat, und führen Sie dann das Programm in / usr / sind. (Fest programmiert, ja, ich weiß, ich bin schlecht.)

Allerdings, wenn ich Umfrage run (), werden die Dinge seltsam. Ich verliere den Griff meine Logdatei, die Umfrage auf der Ausgangsleitung von dem Kind wirft einen Fehler, Katzen und Hunde zu leben beginnen zusammen, und so weiter.

Kann jemand etwas Licht in diese?

Hier ist, was ich zur Zeit habe ... Die poll () in Frage mit nicht-eingerückt Kommentaren zum leichteren Lage gekennzeichnet ist.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>

#define MAX_STR_LEN 1024
static int directionFlag; /* 0 = input, 1 = output */
static int eofFlag;

/* Splits the next char from the stream inFile, with extra
information logged if directionFlag swaps */
void logChar(int inFilDes, int outFilDes, FILE *logFile, int direction)
{
    char inChar = 0;
    if(read(inFilDes, &inChar, sizeof(char)) > 0)
    {

        if(direction != directionFlag)
        {
            directionFlag = direction;
            if(direction)
            {
                fprintf(logFile, "\nOUTPUT: ");
            } else {
                fprintf(logFile, "\nINPUT: ");
            }
        }

        write(outFilDes, &inChar, sizeof(char));
        fputc(inChar, stderr);
        fputc(inChar, logFile);
    } else {
        eofFlag = 1;
    }
    return;
}

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

    int childInPipe[2];
    int childOutPipe[2];

    eofFlag = 0;

    /* [0] is input, [1] is output*/

    if(pipe(childInPipe) < 0 || pipe(childOutPipe) < 0) {
        fprintf(stderr,"Pipe error; aborting\n");
            exit(1);
    }

    if((pid = fork()) == -1){
        fprintf(stderr,"Fork error; aborting\n");
        exit(1);
    }

    if(pid)
    {
        /*Parent process*/

        int i;
        int errcode;
        time_t rawtime;
        struct tm * timeinfo;
        time(&rawtime);
        timeinfo=localtime(&rawtime);

        struct pollfd pollArray[2] = {
            { .fd = 0, .events = POLLIN, .revents = 0 },
            { .fd = childOutPipe[0], .events = POLLIN, .revents = 0 }
        };
        /* Yet again, 0 = input, 1 = output */

        nfds_t nfds = sizeof(struct pollfd[2]);

        close(childInPipe[0]);
        close(childOutPipe[1]);

        /* We don't want to change around the streams for this one,
        as we will be logging everything - and I do mean everything */

        FILE *logFile;
        if(!(logFile = fopen("/opt/middleman/logfile.txt", "a"))) {
            fprintf(stderr, "fopen fail on /opt/middleman/logfile.txt\n");
            exit(1);
        }

        fprintf(logFile, "Commandline: ");

        for(i=0; i < argc; i++)
        {
            fprintf(logFile, "%s ", argv[i]);
        }
        fprintf(logFile, "\nTIMESTAMP: %s\n", asctime(timeinfo));

        while(!eofFlag)
        {

// RIGHT HERE is where things go to pot
            errcode = poll(pollArray, nfds, 1);
// All following fprintf(logfile)s do nothing
            if(errcode < 0) {
                fprintf(stderr, "POLL returned with error %d!", errcode);
                eofFlag = 1;
            }
            if((pollArray[0].revents && POLLERR) & errno != EAGAIN ) {
                fprintf(stderr, "POLL on input has thrown an exception!\n");
                fprintf(stderr, "ERRNO value: %d\n", errno);
                fprintf(logFile, "POLL on input has thrown an exception!\n");
                eofFlag = 1;
            } else if(pollArray[0].revents && POLLIN) {
                logChar(pollArray[0].fd, childInPipe[1], logFile, 0);
            } else if((pollArray[1].revents && POLLERR) & errno != EAGAIN ) {
                fprintf(stderr, "POLL on output has thrown an exception!\n");
                fprintf(stderr, "ERRNO value: %d\n", errno);
                fprintf(logFile, "POLL on output has thrown an exception!\n");
                eofFlag = 1;
            } else if(pollArray[1].revents && POLLIN) {
                logChar(pollArray[1].fd, 1, logFile, 1);
            }

        }

        fclose(logFile);

    }
    else
    {
        /*Child process; switch streams and execute application*/
        int i;
        int catcherr = 0;
        char stmt[MAX_STR_LEN] = "/usr/bin/";

        close(childInPipe[1]);
        close(childOutPipe[0]);

        strcat(stmt, argv[0]);

        if(dup2(childInPipe[0],0) < 0) {
            fprintf(stderr, "dup2 threw error %d on childInPipe[0] to stdin!\n", errno);
        }
//      close(childInPipe[0]);

        if(dup2(childOutPipe[1],1) < 0)
        {
            fprintf(stderr, "dup2 threw error %d on childInPipe[1] to stdout!\n", errno);
        }

        /* Arguments need to be in a different format for execv */
        char* args[argc+1];
        for(i = 0; i < argc; i++)
        {
            args[i] = argv[i];
        }
        args[i] = (char *)0;

        fprintf(stderr, "Child setup complete, executing %s\n", stmt);
        fprintf(stdout, "Child setup complete, executing %s\n", stmt);

        if(execv(stmt, args) == -1) {
            fprintf(stderr, "execvP error!\n");
            exit(1);
        }
    }
    return 0;
}


EDIT 6/23/09 12.20

Nach Updates, habe ich versucht zu laufen ‚Banner‘ durch dieses Programm, und hier ist der Ausgang ich ...

Child setup complete, executing /usr/bin/banner
POLL on output has thrown an exception!
ERRNO value: 0

Die Logdatei hat folgende Möglichkeiten:

Commandline: banner testing 
TIMESTAMP: Tue Jun 23 11:21:00 2009

Der Grund ERRNO hat eine 0 in es ist, weil Umfrage () gibt nur gut; es ist die pollArray [1] .revents die zurück mit einem Fehler kam, die als mit einem Fehler childOutPipe [0] bedeutet, abgefragt. logChar (), soweit ich das beurteilen kann, wird nie genannt.

Ich werde Splitting auszuprobieren poll () in zwei verschiedene Anrufe.


Okay, der Moment, als ich poll () - auch auf stdin, die mit einer Fehlermeldung nicht zurück - es tötet meine Fähigkeit zum logFile zu schreiben. Auch entdeckt, dass die I while () Schleife mehrmals ausgeführt wird, bevor der Ausgang poll mit einem Fehler kommt zurück auf dem Rohr. Ich bin immer davon überzeugt, dass poll () ist einfach eine verlorene Sache.
Jeder Versuch, logFile schreiben nicht nach der Umfrage (), selbst ein erfolgreicher poll (), mit errno auf „Bad Dateinummer“ gesetzt. Dies sollte wirklich nicht passieren. Ich kann ehrlich nicht vorstellen, wie es wäre meine Datei-Handle werden zu beeinflussen.
Okay, also anscheinend bin ich ein Idiot. Danke, dass ich gerade Einstellung; Ich war nfds unter der Annahme war eine Byte-Größe, keine Array Größe. Das ist fixiert, und voila! Es ist nicht zu töten meine logFile mehr behandeln.

War es hilfreich?

Lösung

Die wirklichen Probleme:

1. (aber minor) Problem

struct pollfd pollArray[2] = {{0, POLLIN, 0}, {childOutPipe[0], POLLIN, 0}};

Sie machen möglicherweise ungerechtfertigte Annahmen über die Reihenfolge und Inhalt von ‚struct pollfd‘. Alle Standard sagt, ist, dass es (mindestens) drei Mitglieder; es sagt nichts über die Reihenfolge, in der sie erscheinen.

  

Der Header wird die pollfd Struktur definieren, die zumindest die folgenden Elemente umfassen soll:

int    fd       The following descriptor being polled. 
short  events   The input event flags (see below). 
short  revents  The output event flags (see below). 

Da Sie C99 verwenden, verwenden Sie die sichere Initialisierung Notation:

    struct pollfd pollArray[2] =
    {
        { .fd = 0,               .events = POLLIN, .revents = 0 },
        { .fd = childOutPipe[0], .events = POLLIN, .revents = 0 },
    };

Sie können die 0 für Standardeingabe mit FILENO_STDIN von <fcntl.h> ersetzen.

2. (das Haupt) Problem

    nfds_t nfds = sizeof(pollArray);

Die Größe der Umfrage Array ist wahrscheinlich 16 (Byte) - auf den meisten, aber nicht alle Maschinen (32-Bit und 64-Bit). Sie müssen die Dimension des Umfrage-Array (die 2). Aus diesem Grund bricht die Hölle los; das System wird bei Müll suchen und verwirrt.

Addressing Kommentar :

, um die Dimension eines Arrays in der lokalen Datei oder Funktion definiert, um zu finden (aber keine Array-Parameter in eine Funktion übergeben, noch ein Array in einer anderen Datei definiert), eine Variante des Makro verwenden:

#define DIM(x) (sizeof(x)/sizeof(*(x)))

Dieser Name erinnert in der trüben, fernen Vergangenheit die Verwendung von BASIC zurück; andere Namen, die ich gesehen habe, sind NELEMS oder ARRAY_SIZE oder DIMENSION (horcht auf Fortran IV zurück), und ich bin sicher, es gibt viele andere.

Was passiert ist, dass, weil Sie nicht nfds bis 2 einstellen, wird der Systemaufruf Daten nach dem eigentlichen struct pollfd Array zu lesen, und zu versuchen, dem Kopf oder Schwanz von Sachen zu machen, die kein struct pollfd ist. Insbesondere schreibt es wahrscheinlich in dem, was Sie gesagt haben es das revents Feld einer Zeile in der struct pollfd Array ist, aber der eigentliche Raum ist das Protokoll FILE *, so dass völlig verkorkst ist. Ähnliches gilt für andere lokale Variablen. Mit anderen Worten, haben Sie einen Stapelpufferüberlauf bekommen - auch bekannt als Stack-Überlauf, einen Namen, der schwach vertraut sein sollte. Aber es geschieht, weil Sie es programmiert ist.

Fix:

    nfds_t nfds = DIM(pollArray);

3. (mittlere Qualität) Problem

   poll(pollArray, nfds, 1);
   if (errcode < 0) {

Das Ergebnis poll() wird nicht gespeichert, und die Variable errcode wird nie ein Wert zugewiesen, aber Sie überprüfen, was der Wert unmittelbar danach ist. Der korrigierte Code würde wahrscheinlich lesen:

errcode = poll(pollArray, nfds, 1);
if (errcode < 0)
{
    fprintf(stderr, "POLL returned with error %d!\n", errcode);
    eofFlag = 1;
}

Beachten Sie das Newline-Zeichen zu der Fehlermeldung hinzugefügt - Sie es brauchen. Oder:

if (poll(pollArray, nfds, 1) < 0)
{
    int errnum = errno;
    fprintf(stderr, "POLL returned with error (%d: %s)\n",
            errnum, strerror(errnum));
    eofFlag = 1;
}

Im zweiten Fall würden Sie ‚#include <errno.h>‘ in der Header-Liste hinzufügen. Speichern Sie den Wert von errno bewahrt es vor Veränderung durch Funktionsaufrufe - aber Sie können errno nur zuverlässig testen, wenn eine Funktion (Systemaufruf) ausgefallen ist. Auch erfolgreiche Funktionsaufrufe verlassen können errno nicht Null. (Zum Beispiel auf einigen Systemen, wenn stderr nicht an einen Terminal geht, den Wert von errno nach einem I / O-Aufruf ist ENOTTY, auch wenn der Anruf als Ganze erfolgreich war.)


Zurück Wiederkäuen

Einige frühere Gedanken auf, was könnte das Problem sein; Ich denke, es gibt noch einige nützliche Informationen hier unten.

Ich vermute, Ihr Problem ist, dass poll() ‚Schäden‘ die Menge der abgefragten Deskriptoren, und Sie haben es auf jeder Schleife neu zu erstellen. (mit der Hand-Seite auf der

scroll top