sal_guy
sal_guy

Reputation: 319

Keyboard Input is wrongly redirected to Named Pipe read

I posted an earlier question which I am yet to solve. I'll try out the answer there later. However, I am currently facing a strange problem.

I am running my reader and writer on two different ssh-ed terminals. My reader in a named pipe is reading input from the keyboard instead of the named pipe. Here is my simple reader.

reader.c

#define PIPE_ID "aa"
int Pipe_FD = 0;

int main (int argc, char **argv)
{    
  printf("Waiting on open\n");
  while(Pipe_FD = open(PIPE_ID, O_RDONLY) < 0) {
  }

  printf("waiting on read\n");
  char ch;
  while(read(Pipe_FD, &ch, 1) > 0) {
    printf("Read: %c\t", ch);
    fflush(stdout);
  }
  close(Pipe_FD);
  return 1;
}

My writer configures the pipe, writes a "Hi" to the named pipe and then sleeps for 1 second before exiting.

writer.c

#define PIPE_ID "aa"
int Pipe_FD = 0;

// This function configures named pipe
void configure_pipe() {
  if(mkfifo(PIPE_ID, 0666) != 0) {
    perror("mkfifo error\n");
  }
}

void writeInPipe() {
  Pipe_FD = open(PIPE_ID, O_WRONLY);
  int num;
  if((num = write(Pipe_FD, "Hi", sizeof("Hi"))) < 0) {
    perror("Error in writing\t");
    exit(-1);
  }  else
    printf("Wrote bytes: %d\n", num);
  close(Pipe_FD);
}

int main() {
  configure_pipe();

  writeInPipe();
  sleep(1);
  unlink(PIPE_ID);
}

The writer end correctly outputs:

Wrote bytes: 3

The reader end behaves strangely. It correctly waits for the pipe to be opened first. Then, it doesn't show any output. If I press "enter" it just reads blank. If press "ab", it outputs "a" and "b" separately. Here's an sample output:

Waiting on open
waiting on read

Read:

        Read:

        Read:
a
        Read: a Read:
ab
        Read: a Read: b Read:

I run the reader first and then it waits on open. When the writer starts, it waits on read but doesn't show any output. Only when I press any enter, then it shows something. Can anybody give any hint/idea what is happening really?

Upvotes: 0

Views: 148

Answers (1)

John Bollinger
John Bollinger

Reputation: 180058

You have an operator precedence problem here. The assignment operator (=) has lower precedence than the comparison operators such as <. Therefore, this while loop ...

while(Pipe_FD = open(PIPE_ID, O_RDONLY) < 0) {
}

is interpreted as

while (Pipe_FD = (open(PIPE_ID, O_RDONLY) < 0)) {
}

That has the semantics you intend when open() returns less than 0, for then the relational expression evaluates to 1, 1 is assigned to Pipe_FD, the value of the overall expression is 1, and the loop continues iterating.

When the open() succeeds, however, the actual file descriptor is used only for the comparison with 0. When the FD is non-negative, the comparison evaluates to 0, 0 is assigned to Pipe_FD, the value of the overall expression is 0, and the loop terminates. That leaves you afterward reading from file descriptor 0, the standard input, instead of from the FIFO you opened.

Fix the problem by appropriate use of parentheses:

while ((Pipe_FD = open(PIPE_ID, O_RDONLY)) < 0) {
}

Additionally, it would be both more robust and clearer to test in the loop body why opening failed. For example,

while ((Pipe_FD = open(PIPE_ID, O_RDONLY)) < 0) {
    if (errno != ENOENT) {
        perror("open");
        exit(1);
    }
}

I would suggest also putting a short delay in there, so as to be a little less demanding of system resources.

Upvotes: 1

Related Questions