Не удается прочитать вывод команды с помощью функции popen

#c #linux #process #popen #pid

#c #linux #процесс #popen #pid

Вопрос:

В Linux я нахожу pid процесса, открывая канал с помощью команды «pidof process_name», а затем считываю его вывод с помощью функции fgets. Но время от времени не удается найти pid. Ниже приведен мой код для поиска pid моего процесса.

 int FindPidByProcessName(char *pName)
{
    int pid = -1;
    char line[30] = { 0 };
    char buf[64] = { 0 };

    sprintf(buf, "pidof %s", pName);

    //pipe stream to process
    FILE *cmd = popen(buf, "r");

    if (NULL != cmd)
    {
        //get line from pipe stream
        fgets(line, 30, cmd);
        //close pipe
        pclose(cmd); cmd = NULL;

        //convert string to unsigned LONG integer
        pid = strtoul(line, NULL, 10);
    }

    return pid;
}
  

На выходе иногда появляется pid = 0, даже если процесс доступен в выводе команды «ps».
Итак, я пытаюсь найти основную причину этой проблемы, и я обнаружил, что что-то вроде механизма буфера ввода / вывода может создать проблему в моем сценарии.

Поэтому я пытаюсь использовать функцию sync () перед открытием popen(), и, как ни странно, моя функция начинает работать со 100% точностью.

Теперь функция sync () занимает слишком много времени (примерно 2 минуты) для завершения ее выполнения, что нежелательно. Поэтому я пытаюсь использовать fflush(), fsync() и fdatasync (), но все они не работают должным образом.

Итак, пожалуйста, кто-нибудь скажет мне, какова была точная первопричина этой проблемы и как решить эту проблему надлежащим образом?

Комментарии:

1. Я не понимаю вашего while цикла — вы вызываете только popen один раз, почему вы зацикливаетесь при чтении вывода?

2. Извините за недопонимание, это просто формат кодирования, который я использую для написания функций. Здесь это не имеет значения, поскольку это while(0). Это не будет зациклено.

3. Когда pid есть 0 , каково содержимое line ?

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

5. Добавьте какой-нибудь код, который выполняется, perror если fgets возвращается значение null, и сообщите нам, что это за сообщение об ошибке.

Ответ №1:

Хорошо, основная причина ошибки хранится в переменной errno (которую, кстати, вам не нужно инициализировать). Вы можете получить информативное сообщение с помощью функции

 perror("Error: ");
  

Если вы используете perror, интерпретируется переменная errno, и вы получаете описательное сообщение.

Другой способ (правильный способ!) найти первопричину — это скомпилировать вашу программу с флагом -g и запустить двоичный файл с помощью gdb.

Редактировать: я настоятельно рекомендую использовать отладчик gdb, чтобы вы могли точно посмотреть, по какому пути следует ваш код, чтобы вы могли объяснить описанное вами странное поведение.

Второе редактирование: Errno сохраняет последнюю ошибку (возвращаемое значение). Вместо того, чтобы вызывать функции, как вы это делаете, вы должны немедленно написать и проверить errno:

 if ((<function>) <0) {
  perror("<function>: ");
  exit(1);
}
  

Комментарии:

1. Я ценю ваши мысли. Но я уже выполнял отладку с помощью gdb, чтобы найти основную причину. Здесь дело в том, что в fgets() не выводится вывод при попытке прочитать ФАЙЛ *. Итак, это моя проблема с некоторым механизмом буфера ввода-вывода.

2. @ravibhuva9955 что возвращает fgets()? Вы можете использовать команду strace для мониторинга системных вызовов ваших программ (включая операции ввода-вывода).

3. в этом случае fgets возвращает NULL.

4. Хорошо, один случай (из всех других ошибок), когда fgets возвращает null, — это когда это EOF. Можете ли вы подтвердить, что это не так? Потому что, если это EOF (нечего читать в канале), это нормальное поведение