I have met a problem when acting function fcntl
on stdin
, when I set the stdin
FD status flag to O_NONBLOCK
, It works well but within a side effect. The status flag of stdout and stderr has also changed to O_NONBLOCK
.
I investigated the source code of function fcntl
, SYSCALL_DEFINE3
and do_fcntl
, but got nothing helps. Also stackoverflow or google. I consider that it may related to kernel or glibc implementation.
My computer is Ubuntu 12.04 on x86_64, within gcc 4.6.3 installed.
int flag = 0;
int value = O_NONBLOCK;
int fd = open("./tmp", O_RDONLY);
if(-1 == (flag = fcntl(fd, F_GETFL)))
fprintf(stdout, "%d:%s\n", errno, strerror(errno));
flag = fcntl(stdin->_fileno, F_GETFL);
flag = fcntl(stderr->_fileno, F_GETFL);
if(-1 == (flag = fcntl(stdout->_fileno, F_GETFL)))
fprintf(stdout, "%d:%s\n", errno, strerror(errno));
flag = fcntl(stdout->_fileno, F_SETFL, flag | O_NONBLOCK);
flag = fcntl(fd, F_GETFL);
flag = fcntl(stdin->_fileno, F_GETFL);
flag = fcntl(stdout->_fileno, F_GETFL);
flag = fcntl(stderr->_fileno, F_GETFL);
flag = fcntl(stdin->_fileno, F_SETFL, flag | O_APPEND);
flag = fcntl(fd, F_GETFL);
flag = fcntl(stdin->_fileno, F_GETFL);
flag = fcntl(stdout->_fileno, F_GETFL);
flag = fcntl(stderr->_fileno, F_GETFL);
close(fd);
This is my code for this problem.
One of the 'tricks' traditionally used by the login process (or terminal opening process) is to open the terminal in read-write mode for file descriptor 0 (standard input), and then duplicate that for file descriptors 1 and 2 (standard output and standard error). This means that:
The F_GETFL and F_SETFL options to fcntl()
are related to the open file description.
The F_GETFD and F_SETFD options to fcntl()
are related to the file descriptor.
A given open file description may have several file descriptors associated with, either within a single process (after dup()
or dup2()
) or across processes (because of fork()
).
Following from Jonathan's answer, here's some saner code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
void show_nonblock_status(void) {
char streams[3][7] = {"stdin", "stdout", "stderr"};
for ( int i = 0; i < 3; ++i ) {
int flag = fcntl(i, F_GETFL);
if ( flag == -1 ) {
perror("error getting flags");
exit(EXIT_FAILURE);
}
if ( flag & O_NONBLOCK ) {
printf("O_NONBLOCK is set for %s\n", streams[i]);
} else {
printf("O_NONBLOCK is not set for %s\n", streams[i]);
}
}
}
int main(void) {
show_nonblock_status();
int flag = fcntl(1, F_GETFL);
if ( flag == -1 ) {
perror("error getting flags");
exit(EXIT_FAILURE);
}
flag = fcntl(1, F_SETFL, flag | O_NONBLOCK);
if ( flag == -1 ) {
perror("error getting flags");
exit(EXIT_FAILURE);
}
show_nonblock_status();
return 0;
}
which gives the following output under various uses:
paul@local:~/src/c/scratch$ ./fct
O_NONBLOCK is not set for stdin
O_NONBLOCK is not set for stdout
O_NONBLOCK is not set for stderr
O_NONBLOCK is set for stdin
O_NONBLOCK is set for stdout
O_NONBLOCK is set for stderr
paul@local:~/src/c/scratch$ cat testfile | ./fct
O_NONBLOCK is not set for stdin
O_NONBLOCK is not set for stdout
O_NONBLOCK is not set for stderr
O_NONBLOCK is not set for stdin
O_NONBLOCK is set for stdout
O_NONBLOCK is set for stderr
paul@local:~/src/c/scratch$ cat testfile | ./fct 2>/dev/null
O_NONBLOCK is not set for stdin
O_NONBLOCK is not set for stdout
O_NONBLOCK is not set for stderr
O_NONBLOCK is not set for stdin
O_NONBLOCK is set for stdout
O_NONBLOCK is not set for stderr
paul@local:~/src/c/scratch$
In the first case, the file description is the same, so O_NONBLOCK
is set for all three.
In the second case, a file is piped to stdin
, so that has a different file description to stdout
and stderr
, both of which have O_NONBLOCK
set.
In the third case, a file is piped to stdin
, and stderr
is redirected to /dev/null
, so all 3 file descriptions are different, and O_NONBLOCK
is only set for stdout
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With