Check if process has a stdin handle

  • Thread starter Nikos Chantziaras
  • Start date
E

Eric Sosman

Nikos Chantziaras wrote On 08/01/07 11:03,:
I formulated it a bit "weird". It's porting work, btw, (from win32 to
"as portable as possible") so not everything is 100% clear to even me,
since I'm not the implementor of the original; I just do the porting ;)

In any event, the original is "_eof(_fileno(stdin))" which checks for
EOF on stdin without blocking. In other words, it allows for knowing
beforehand if EOF would be returned when attempting to read from stdin
without actually reading.

It's certainly not possible in portable C, and I don't
see how it could be possible at all:

int will_get_eof = _eof(_fileno(stdin));
int got_eof;

printf ("Carnac the Magnificent predicts "
"that you %s about to press ^Z\n",
will_get_eof ? "are" : "are not");

(void)getchar();
got_eof = feof(stdin);

if ( (got_eof == 0) == (will_get_eof == 0) )
printf ("Carnac was right, as always.\n");
else
printf ("May the fleas of a thousand camels "
"take refuge in your shorts.\n");
 
R

Richard Heathfield

santosh said:
Doesn't the C Standard require it to be so?

In hosted environments, yes it does. But not in freestanding
environments, of course. For example, typical Windows GUI programs will
not have these streams available to them at startup.
 
C

Chris Torek

Is this guaranteed?

Yes, it is guaranteed. However, some might consider this a bit hollow,
because:
I though a process can be started with any or all
of the standard streams closed.

It can indeed, on at least some systems. The C library on those
systems may, or may not, "paper over" this problem (e.g., by opening
/dev/null to fill in descriptors 0, 1, and 2). Let us suppose
further that we have one that does *not* do so.

In this particular case, what this means is that:

# this command closes fd 0 through 2 when starting ./foo
$ ./foo <&- >&- 2>&-

runs "foo" in something other than a "hosted environment".
What does the C standard require? (I couldn't find an answer on N1124)

It requires a "hosted environment" to provide pre-opened stdin,
stdout, and stderr. If you use a "non-hosted environment" to run
your program, by doing the above for instance, this is your fault,
not the Standards, nor the system's. :)

("Secure" programs, on the systems I alluded to above, must make
sure they do not assume that fd 0 through 2 are open. Thus, writing
setuid programs is nontrivial -- but the C standard cannot help
here since "setuid programs" is not even a Standard C concept.)
 
T

those who know me have no need of my name

in comp.lang.c i read:
Nikos Chantziaras wrote:
Is there a way to check if the current process has an stdin handle?
Crucial here is that [it] doesn't block. Is there a standard way
to do the same without resorting to OS-specific API calls?
no.

The following code does not discriminate between a stream at EOF and
other possible error conditions. (stream invalid, not-open, etc.)
int c = getc(stream); [...]
ungetc(c, stream); /* add check for errors */

the getc might block, on systems where that concept exists.
 
S

SM Ryan

# Hello.
#
# Is there a way to check if the current process has an stdin handle? In
# the win32 API, one can do:
#
# _eof(_fileno(stdin))
#
# Crucial here is that the above doesn't block. Is there a standard way
# to do the same without resorting to OS-specific API calls?

I doubt you come up with definitions of the terms you are using
which will be the same on all C implemented platforms; this
strongly suggests you will not find an ANSI C solution. The
alternative is to research each platform you are interested in
and make a separate system specific implementation of a function.

Also there are multiplatform libraries that can do much of this
for you already. They might not run on all possible platforms,
but they're likely to run on every platform you're interested in.
 
N

Nikos Chantziaras

SM said:
# Hello.
#
# Is there a way to check if the current process has an stdin handle? In
# the win32 API, one can do:
#
# _eof(_fileno(stdin))
#
# Crucial here is that the above doesn't block. Is there a standard way
# to do the same without resorting to OS-specific API calls?

I doubt you come up with definitions of the terms you are using
which will be the same on all C implemented platforms; this
strongly suggests you will not find an ANSI C solution. The
alternative is to research each platform you are interested in
and make a separate system specific implementation of a function.

Also there are multiplatform libraries that can do much of this
for you already. They might not run on all possible platforms,
but they're likely to run on every platform you're interested in.

I just went with "select(1, 0, 0, 0, &timeout) == -1", but that's
outside the realm of this newsgroup.
 
N

Nikos Chantziaras

Walter said:
I just went with "select(1, 0, 0, 0, &timeout) == -1", but that's
outside the realm of this newsgroup.

[OT]

http://www.opengroup.org/onlinepubs/007908799/xsh/select.html

The 2nd, 3rd, and 4th arguments to select() are of type fd_set
which need not be an integral type. You need to use FD_ZERO()
and FD_SET() to create an fd_set that designates stdin .

Those arguments can be NULL (i used 0 because I'm calling the function
from C++ actually, and I got into the habit of using 0 instead of NULL
in C++ since I perceive it are "more readable").

stdin is guaranteed to have a file descriptor of 0 at program start, so
the first argument is 0+1 (or just 1).
 
R

Richard Tobin

The 2nd, 3rd, and 4th arguments to select() are of type fd_set
which need not be an integral type. You need to use FD_ZERO()
and FD_SET() to create an fd_set that designates stdin .
[/QUOTE]
Those arguments can be NULL

But you still have to pass a "readfds" argument with bit zero set, to
check file descriptor zero. A null value means you're not interested
in any descriptors.

-- Richard
 
N

Nikos Chantziaras

Richard said:
Those arguments can be NULL

But you still have to pass a "readfds" argument with bit zero set, to
check file descriptor zero. A null value means you're not interested
in any descriptors.[/QUOTE]


Oops. Changed to:

FD_ZERO(&rfds);
FD_SET(0, &rfds);
return select(1, &rfds, 0, 0, &timeout) == -1;
 
E

Eric Sosman

Nikos Chantziaras wrote On 08/02/07 12:31,:
Walter said:
Nikos Chantziaras said:
SM Ryan wrote:

# Is there a way to check if the current process has an stdin handle?
I just went with "select(1, 0, 0, 0, &timeout) == -1", but that's
outside the realm of this newsgroup.

[OT]

http://www.opengroup.org/onlinepubs/007908799/xsh/select.html

The 2nd, 3rd, and 4th arguments to select() are of type fd_set
which need not be an integral type. You need to use FD_ZERO()
and FD_SET() to create an fd_set that designates stdin .


Those arguments can be NULL (i used 0 because I'm calling the function
from C++ actually, and I got into the habit of using 0 instead of NULL
in C++ since I perceive it are "more readable").

stdin is guaranteed to have a file descriptor of 0 at program start, so
the first argument is 0+1 (or just 1).

<off-topic>

Be aware that buffering can lead to a wrong answer.
You call select() and learn that there's input available,
so you call getc() to read the first byte. The library
reads everything file descriptor 0 has to offer, stuffing
all forty-two bytes in an internal buffer and returning
the first of them as the value of getc(). Now you call
select() again, and you find that there's no more input
available on FD 0 -- it has already been read and is now
sitting in the buffer waiting for you to retrieve it ...

Suggested solutions (one mildly topical):

- Use setvbuf() to put the stdin FILE* stream in
unbuffered mode. Not particularly wonderful if
there's a lot of input ...

- Use read() instead of getc() and friends. *Never*
use stdin at all; use only file descriptor 0. For
extra safety, consider dup()ing FD 0, fclose()ing
stdin, and using the dup()ed FD instead.

</off-topic>
 
P

Peter J. Holzer

Ah, presumably that is to avoid the strange behaviour I mentioned.
But none of the unixes I have to hand seem to do it.

Linux does, but only if the effective uid is different from the real
uid.

hp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top