views:

481

answers:

2

Hello,

I have now whittled this down to a minimal test case. Thus far I have been able to determine that this is an issue related to pseudo-terminals which come about with the pipe of ssh. Adding the '-t -t' to the ssh call improved things, in that now, it takes a second call to fgets() to cause the issue. I suspect that the stderr output of the ssh command somehow works into the issue, for now I have redirected stderr to stdout in the ssh code to execute. I do wonder if the "tcgetattr: Invalid argument" error is part of the problem, but am not sure how to get rid of that. It seems to come from the -t -t being present. I believe the -t -t is moving in the right direction, but I have to set up the pseudo terminal for stderr somehow and perhaps the test will work properly?

The Makefile:

test:
    gcc -g -DBUILD_MACHINE='"$(shell hostname)"' -c -o test.o test.c
    gcc -g -o test test.o

.PHONY: clean
clean:
    rm -rf test.o test

The test.c source file:

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

int
main(int argc, char *argv[])
{
  const unsigned int bufSize = 32;
  char buf1[bufSize];
  char buf2[bufSize];
  int ssh = argv[1][0] == 'y';
  const char *cmd = ssh ? "ssh -t -t " BUILD_MACHINE " \"ls\" 2>&1" : "ls";

  FILE *fPtr = popen(cmd, "r");

  if (fPtr == NULL) {
    fprintf(stderr,"Unable to spawn command.\n");
        perror("popen(3)");
        exit(1);
  }
  printf("Command: %s\n", cmd);
  if (feof(fPtr) == 0 && fgets(buf2, bufSize, fPtr) != NULL) {
    printf("First result: %s\n", buf2);
    if (feof(fPtr) == 0 && fgets(buf2, bufSize, fPtr) != NULL) {
      printf("Second result: %s\n", buf2);
      int nRead = read(fileno(stdin), buf1, bufSize);

      if (nRead == 0) {
        printf("???? popen() of ssh consumed the beginning of stdin ????\n");
      } else if (nRead > 0) {
        if (strncmp("The quick brown fox jumped", buf1, 26) != 0) {
          printf("??? Failed ???\n");
        } else {
          printf("!!!!!!!   Without ssh popen() did not consume stdin   !!!!!!!\n");
        }
      }
    }
  }
}

This shows it running the passing way:

> echo "The quick brown fox jumped" | ./test n
Command: ls
First result: ARCH.linux_26_i86

Second result: Makefile

!!!!!!!   Without ssh popen() did not consume stdin   !!!!!!!

This shows it running the failing way:

> echo "The quick brown fox jumped" | ./test y
Command: ssh -t -t hostname "ls" 2>&1
First result: tcgetattr: Invalid argument

Second result: %backup%~           gmon.out

???? popen() of ssh consumed the beginning of stdin ????
+1  A: 

I am suspicious that the local char array inside testIt and that outside it are both named buf.

What if you renamed the local array buflocal and left the other one buf?

Different results?

  • Laurence
lcbrevard
I changed the name and it did not help. I have also ran Valgrind and it reports no memory corruption.
WilliamKF
A: 

Okay, I have got this working finally. The secret was to supply /dev/null as the input to my ssh command as follows from the test case above:

      const char *cmd
        = ssh ? "ssh -t -t " BUILD_MACHINE " \"ls\" 2>&1 < /dev/null" : "ls";

However, while the code works correctly, I get a nasty message which apparently I can ignore for my purposes (although I'd like to make the message go away):

tcgetattr: Inappropriate ioctl for device
WilliamKF