C Обнаружить ошибку в дочернем процессе popen. - PullRequest
2 голосов
/ 08 июня 2019

Я использую popen, чтобы прочитать вывод сторонней программы.Я хотел бы обнаруживать и перезапускать вещи, если подпрограмма дает сбой.

Как бы я это сделал?Если ребенок умирает, процесс не завершается нормально и поэтому не может использовать WEXITSTATUS для проверки.

Есть ли другой способ?

Вот простой пример:

PINGER.C

#include <string.h>
#include <stdio.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
    int i = 0;
    while (1)
    {
        //fprintf(stderr, "StdErr %d\n", i);
        printf("stdout %d\n", i++);
        fflush(stdout);

        if (i == 5)
            i = i / 0; // Die a horrible death

        sleep(1);
    }
}

WATCHER.C

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>

int
main(int argc, char **argv)
{
    char *cmd = "./pinger";
    printf("Running '%s'\n", cmd);

    FILE *fp = popen(cmd, "r");
    if (!fp)
    {
        perror("popen failed:");
        exit(1);
    }

    char inLine[1024];
    int  bytesRead = 0;
    int  i = 0;

    while (fgets(inLine, sizeof(inLine), fp) != NULL)
    {
        int len = strlen(inLine);
        if (inLine[len-1] == '\n')
            inLine[len-1] = '\0';

        printf("Received: '%s'\n", inLine);
    }

    printf("feof=%d ferror=%d: %s\n", feof(fp), ferror(fp), strerror(errno));

    int rc = pclose(fp);
    printf("pclose returned: %d. IFEXITED=%d\n", rc, WIFEXITED(rc));
}

Вот вывод:

$ ./popenTest
calling popen
Running './pinger'
pipe open
Received: 'stdout 0'
Received: 'stdout 1'
Received: 'stdout 2'
Received: 'stdout 3'
Received: 'stdout 4'
feof=1 ferror=0: Success
pclose returned: 8. IFEXITED=0 EXITSTATUS=0

( Согласно этому сообщению , вы на самом деле не можете использовать WEXITSTATUS, если команда не завершилась нормально, но я все равно попытался)

Ответы [ 2 ]

0 голосов
/ 08 июня 2019

Прочитайте спецификацию POSIX pclose()popen() тоже).В нем говорится:

Возвращаемое значение

При успешном возвращении pclose() возвращает статус завершения интерпретатора командного языка.В противном случае pclose() должен вернуть -1 и установить errno для указания ошибки.

Таким образом, вы можете получить статус выхода процесса косвенно через возвращаемое значение pclose().Это будет число от 0 до 255. Оболочки часто сообщают о «смерти ребенка по сигналу», возвращая значение 128 + signal_number.В спецификации описываются обстоятельства, при которых статус может быть недоступен (например, ваша программа позвонила wait() и получила информацию для процесса, открытого popen() до того, как вы позвонили pclose()).Чтение спецификации popen() объясняет использование «интерпретатора командного языка» в спецификации pclose().

0 голосов
/ 08 июня 2019

Процесс возвращает состояние выхода, возвращаясь из своей функции main () с кодом выхода или вызывая _exit (код состояния). Если процесс завершается ненормально, например, из-за сигнала или сбоя, у процесса никогда не будет шанса сделать что-либо из этого, поэтому нет exitstatus.

В этом случае все, что вы можете знать, это то, что процесс завершается с ошибкой.

Если вы хотите перезапустить во всех случаях, когда программа завершает работу в случае ошибки, вам нужно проверить WIFEXITED и WEXITSTATUS:

do {
    rc = run_your_child_process();

} while (!WIFEXITED(rc) || WEXITSTATUS(rc) == 0);

// child terminated without error
...