Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 May 96 20:02:27 MDT
From:      sclawson@bottles.cs.utah.edu (steve clawson)
To:        jmacd@CS.Berkeley.EDU (Josh MacDonald)
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: stdio problem
Message-ID:  <199605030202.UAA07379@bottles.cs.utah.edu>
In-Reply-To: <199605022220.PAA17967@paris.CS.Berkeley.EDU>; from "Josh MacDonald" at May 2, 96 3:20 pm

next in thread | previous in thread | raw e-mail | index | archive | help
Josh MacDonald uttered:
> Unfortunatly, I don't have control over this condition.  I am closing
> the standard input and exec-ing GNU diff3.  Diff3 calls freopen. 
> The comments in stdio/freopen.c say this should work.  It works everywhere
> else.
>
> Your answers are not very helpful.

     Perhaps the answers weren't very explanatory, but they were
correct.  Basically, your program is at the very least non-portable,
and IMHO buggy.  Calling close(0) is _not_ the proper way to `close'
stdin.  This just closes file descriptior 0, but dosen't do anything
to close the stream stdin, which has user-level state.  You should use
fclose() to close it if you really need to.  close() isn't even in
ANSI C.  

> Why couldn't you all just answer my questions instead of telling me
> it is wrong.  Obviously, I already know that
> it doesn't work on FreeBSD or NetBSD, and that it works on every other
> operating system I've tried it on.

     It dosen't work on any BSD system that I've got around here (HP
BSD 4.3+, running on hp[378]00's).  Of course this mostly just implies
that their stdio implementations are related. =)  

> a)  Why does freopen fail *even though the comments in freopen.c say
>     it should not*?

     freopen fails because you've violated the stdio abstraction.
Perhaps POSIX has something to say about freopen, but according to
ANSI C this behavior is reasonable.

     The problem is that freopen tries to wait before closing the old
file descriptor.  freopen assumes that if there is a flag set in
_flags that the stream is open and sets isopen.  Since you didn't
fclose stdin, it's _flags field is still set.  The problem comes a
little later:

	 /* Get a new descriptor to refer to the new file. */
        f = open(file, oflags, DEFFILEMODE);

	[various other things that don't happen elided]	

        /*
         * Finish closing fp.  Even if the open succeeded above, we cannot
         * keep fp->_base: it may be the wrong size.  This loses the effect
         * of any setbuffer calls, but stdio has always done this before.
         */
        if (isopen)
                (void) (*fp->_close)(fp->_cookie);

     Since you already closed fd 0, the open call at the top will
return 0, since that's the lowest non-allocated fd.  Because isopen is
true, the close function is called on the original stream, but it's
_file pointer is 0 also and it gets closed again. =)

     So, when you try to do an fgetc() later on, it notices that the
file descriptor isn't valid and returns EBADF.

> b)  Should GNU diff3 be responsible for checking that stdin is open
>     before tring to freopen?

     No.  The problem is that you're not setting up stdin correctly.

> c)  Should I not exec a program without an opened stdin?  Programs
>     which assume they have an open stdin are bad, I think.  

     I don't see any reason why a UNIX (or in general, an ANSI C)
program shouldn't assume this, since it's guaranteed for you.  If you
have to do something with stdin and it's screwed up then you've got
problems. =)


steve

-- 
// stephen clawson				sclawson@cs.utah.edu
// university of utah			        




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199605030202.UAA07379>