2014-11-27 5 views
0
  • У меня есть программа, которая popen() к другому, а также dup() стандартный вывод
  • При вызове из другого процесса (например, на примере PHP) или через SSH, процесс не выходит.

process_test.c:Почему dup() и popen() не позволяют моему процессу выйти из него при вызове из другого процесса?

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

int main() { 
    int out; 

    out = dup(STDOUT_FILENO); 
    // close(out); 

    popen("sleep 10\0", "r"); 
} 

Compile с gcc process_test.c, работать с:

  • ./a.out -> выходит нормально
  • ruby -e 'system("./a.out");' -> нормально завершается
  • php -r passthry("./a.out"); -> висит
  • ssh remotehost ./a.out -> висит
  • , когда я не dup STDOUT или закрыть DUP, он не висит

Это самый короткий воспроизводимый код, который я мог найти, который показывает мне поведение я хотел бы чтобы лучше понять.

Чтобы извлечь это из нескольких PHP-приложений/фреймворков, потребовалось несколько часов, используя fork/pcntl/etc. чтобы измерить их отношения, т. е. я не писал этого или не сделал это; но, очевидно, весь смысл этого потерялся из-за того, что я все разобрал.

Вопросы

  • Почему некоторые вызовы вешают (PHP, SSH) и другие не (рубин)?
  • Даже когда я закрываю fd после popen, моя программа зависает; Зачем?

ответ

0

Потому что при вызове программы через ssh дуп на stdoud производится с помощью ssh, поэтому, когда ssh пытается завершить, это невозможно, потому что в stdout также открыт другой канал.

Я пытаюсь дать вам лучший ответ: stdout - это номер канала 1, если я правильно помню. Создавая дуп, у нас также есть новый канал 3, который указывает на стандартный вывод. Когда ssh попытается закрыть канал 2 togheter на канал 0 и 2 (stdinput и stderr), ssh не может закрыться, потому что есть другой ресурс, который занимает канал 3 или лучше stdout.

Я надеюсь, что это достаточно ясно Гаэтано

Если я запустить демо, как это и я получаю ERRNO = 15, или это может быть 16, как описано в конце этого ответа. Но, если я запускаю его по-другому:

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

int main() { 
    int out; 
    int status; 

    out = dup(STDOUT_FILENO); 
    // close(out); 
    FILE *fp = popen("sleep 10\0", "r"); 
    status = pclose(fp); 
    if (status == -1) { 
      printf("pclose error: %d", errno); 
    } 
    close(out); 
} 

Я не получаю больше ошибок. Чтобы проверить ошибку при bash, я использую: echo $?

Это означает, что перед выходом из программы c вам необходимо повторно открыть все выделенные ресурсы.

Я надеюсь, что это все.

Лучшие reagards Гаэтано

#define ENOTBLK  15 /* Block device required */ 
    #define EBUSY  16 /* Device or resource busy */ 
+0

Я читал, что вы написали, но некоторые формулировки сбивает с толку: «... чтобы закрыть канал 2 совмещены с каналом 0 и 2 ...», что это такое должен означать? И вопрос: почему вызывающий (ssh) зависит от таких внутренних деталей, что делает этот процесс, я имею в виду, что он выглядит настолько хрупким? Например. Не имеет значения, когда я закрываю обманутый канал * после * popen(), ssh также не выйдет. – mark

+0

Я перефразировал свои вопросы, а также добавил твист, что даже закрытие fd ** после того, как ** 'popen' не будет выходить в описанных обстоятельствах. – mark

+0

Процесс ssh, если вы смотрите на исходный код, похож на rlogin или telnet: после открытия и установления соединения с удаленной программой запустите его, и поэтому входной канал ssh отображается на входном канале удаленной программы, поэтому для канала 1 и 2. ssh закроет соединение, когда все каналы открыты (т.е.: 0, 1, 2) закрыты. Поэтому, поскольку вы дублировали 1 канал, чтобы выполнить некоторые другие работы, ssh закончится, когда этот процесс завершится и закроет дублированный канал 1. Кажется, очень сложно описать, что 30 лет назад использовалось много такого поведения .... – gaetanoM