Замена и последующее открытие stdin / stdout через ssh - PullRequest
5 голосов
/ 05 августа 2011

Я работаю над системой, которая взаимодействует с дочерними процессами, используя каналы к stdin и stdout. Дочерние процессы используют библиотеку API для облегчения этой связи, и мне нужно написать модульные тесты для библиотеки. Единственный способ выяснить, как правильно протестировать эти функции, - заменить stdin / stdout конвейерами, чтобы при вызове функций тесты могли выдавать себя за родительскую систему.

/* replace stdin and stdout with pipes */
void setup(void) {
  pipe(in_sub);
  pipe(out_sub);

  dup2(out_sub[1], fileno(stdout));
  dup2( in_sub[0],  fileno(stdin));
  read_from = fdopen(out_sub[0], "rb");
  write_to  = fdopen( in_sub[1], "wb");

  stdout_t = fopen("/dev/tty", "wb");
  stdin_t  = fopen("/dev/tty", "rb");
}

/* reopen stdin and stdout for future test suites */
void teardown(void) {
  fclose(read_from);
  fclose(write_to);

  stdout = stdout_t;
  stdin  = stdin_t;

  close(in_sub[0]);
  close(in_sub[1]);
  close(out_sub[0]);
  close(out_sub[1]);
}

Я попытался просто сохранить stdin и stdout в temps и использовать fdopen () для них (должно работать, потому что они FILE *), но это не приводит к тому, что все правильно записывается в канал. Этот код отлично работает при запуске непосредственно из оболочки хоста. Проблема возникает при запуске через SSH. Модульные тесты выполняются отлично, но когда я собираюсь написать что-либо в стандартный вывод после этого набора тестов, я получаю сообщение об ошибке сломанного канала.

Что я могу сделать, чтобы избежать использования dup2, чтобы stdin и stdout никогда не закрывались, или как я могу снова открыть stdin и stdout, чтобы они корректно работали в оболочке и поверх ssh?

1 Ответ

3 голосов
/ 06 августа 2011

stdin, stdout - это просто FILE *, указывающий на структуру (объект), для которой fd имеет значение 0 (и 1). Следовательно, когда вы делаете dup2, файлы 0 и 1 больше не работают. Что вам нужно сделать, это создать новый файловый объект с нуля до того, как выполнит dup2, так что это может быть все, что вам нужно;

void setup(void) {
  int dupin, dupout;

  dupin = dup(0);  // Create an extra fd to stdin
  dupout = dup(1);  // create an extra fd to stdout

  pipe(in_sub);
  pipe(out_sub);

  dup2(out_sub[1], fileno(stdout));
  dup2( in_sub[0],  fileno(stdin));
  read_from = fdopen(out_sub[0], "rb");
  write_to  = fdopen( in_sub[1], "wb");

  stdout_t = fdopen(dupout, "wb");
  stdin_t  = fdopen(dupin, "rb");
}
...