From owner-freebsd-hackers Thu May 2 21:00:44 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.3/8.7.3) id VAA21014 for hackers-outgoing; Thu, 2 May 1996 21:00:44 -0700 (PDT) Received: from cs.utah.edu (cs.utah.edu [128.110.4.21]) by freefall.freebsd.org (8.7.3/8.7.3) with SMTP id VAA21008 for ; Thu, 2 May 1996 21:00:40 -0700 (PDT) Received: from bottles.cs.utah.edu by cs.utah.edu (8.6.12/utah-2.21-cs) id WAA26978; Thu, 2 May 1996 22:00:39 -0600 Received: by bottles.cs.utah.edu (8.6.10/utah-2.15-leaf) id WAA07893; Thu, 2 May 1996 22:00:38 -0600 From: sclawson@bottles.cs.utah.edu (steve clawson) Message-Id: <199605030400.WAA07893@bottles.cs.utah.edu> Subject: Re: stdio problem To: sclawson@bottles.cs.utah.edu (sclawson) Date: Thu, 2 May 96 22:00:37 MDT Cc: jmacd@CS.Berkeley.EDU, freebsd-hackers@freebsd.org In-Reply-To: ; from "sclawson" at May 2, 96 8:02 pm X-Mailer: ELM [version 2.3 PL11] Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk sclawson uttered: > 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. What I said is more or less reasonable in regards to the test code that you sent, but isn't in regards to your original problem (ie. having fd 0 closed and then execing diff3, which then does a freopen on stdin). After the exec, it dosen't matter if you used close or fclose, any streams except the cannonical 3 are going to be toast anyway. The real problem is in stdio/findfp.c: FILE __sF[3] = { std(__SRD, STDIN_FILENO), /* stdin */ std(__SWR, STDOUT_FILENO), /* stdout */ std(__SWR|__SNBF, STDERR_FILENO) /* stderr */ }; since in stdio.h we have: #define stdin (&__sF[0]) When the new process starts up, stdin looks reasonable to stdio, but it's fd is invalid. Which brings us back to the problem with freopen, which only checks to see if anything is set in _flags. =( It seems to me that there's only really a problem in freopen if we get back from the open the same fd that the stream supposedly was using. In that case we really don't want to be trying to close the original stream, since we won't really be able to flush any buffers back through the fd. =( At least for freopen, this seems to fix the problem: *** freopen.c Thu May 2 20:42:46 1996 --- /usr/arch/FreeBSD/current/lib/libc/stdio/freopen.c Tue May 30 04:35:17 1995 *************** *** 109,115 **** * 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 && (fp->_file != f)) (void) (*fp->_close)(fp->_cookie); if (fp->_flags & __SMBF) free((char *)fp->_bf._base); --- 109,115 ---- * 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); if (fp->_flags & __SMBF) free((char *)fp->_bf._base); If fp->_close dosen't point to fclose things could screw up, but if it does, the only thing that fclose does that freopen won't do is call __sflush, which dosen't really matter if there's no fd to write to anyway. In fact, we probably don't want to try and flush out old data to the fd that we just opened anyway. steve -- // stephen clawson sclawson@cs.utah.edu // university of utah