xref: /csrg-svn/lib/libc/stdio/freopen.c (revision 61180)
146085Sbostic /*-
2*61180Sbostic  * Copyright (c) 1990, 1993
3*61180Sbostic  *	The Regents of the University of California.  All rights reserved.
446085Sbostic  *
546085Sbostic  * This code is derived from software contributed to Berkeley by
646085Sbostic  * Chris Torek.
746085Sbostic  *
846085Sbostic  * %sccs.include.redist.c%
921407Sdist  */
1021407Sdist 
1126652Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*61180Sbostic static char sccsid[] = "@(#)freopen.c	8.1 (Berkeley) 06/04/93";
1346085Sbostic #endif /* LIBC_SCCS and not lint */
1421407Sdist 
1517951Sserge #include <sys/types.h>
1646085Sbostic #include <sys/stat.h>
1746611Sbostic #include <fcntl.h>
1846085Sbostic #include <errno.h>
1946611Sbostic #include <unistd.h>
2017951Sserge #include <stdio.h>
2146085Sbostic #include <stdlib.h>
2246085Sbostic #include "local.h"
232008Swnj 
2446085Sbostic /*
2546085Sbostic  * Re-direct an existing, open (probably) file to some other file.
2646085Sbostic  * ANSI is written such that the original file gets closed if at
2746085Sbostic  * all possible, no matter what.
2846085Sbostic  */
292008Swnj FILE *
freopen(file,mode,fp)3046085Sbostic freopen(file, mode, fp)
3146271Storek 	const char *file, *mode;
3246085Sbostic 	register FILE *fp;
332008Swnj {
3446085Sbostic 	register int f;
3546085Sbostic 	int flags, isopen, oflags, sverrno, wantfd;
362008Swnj 
3746085Sbostic 	if ((flags = __sflags(mode, &oflags)) == 0) {
3846085Sbostic 		(void) fclose(fp);
3946085Sbostic 		return (NULL);
4046085Sbostic 	}
413163Stoy 
4246085Sbostic 	if (!__sdidinit)
4346085Sbostic 		__sinit();
4417951Sserge 
4546085Sbostic 	/*
4646085Sbostic 	 * There are actually programs that depend on being able to "freopen"
4746085Sbostic 	 * descriptors that weren't originally open.  Keep this from breaking.
4846085Sbostic 	 * Remember whether the stream was open to begin with, and which file
4946085Sbostic 	 * descriptor (if any) was associated with it.  If it was attached to
5046085Sbostic 	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
5146085Sbostic 	 * should work.  This is unnecessary if it was not a Unix file.
5246085Sbostic 	 */
5346085Sbostic 	if (fp->_flags == 0) {
5446085Sbostic 		fp->_flags = __SEOF;	/* hold on to it */
5546085Sbostic 		isopen = 0;
5646085Sbostic 		wantfd = -1;
5746085Sbostic 	} else {
5846085Sbostic 		/* flush the stream; ANSI doesn't require this. */
5946085Sbostic 		if (fp->_flags & __SWR)
6046213Sbostic 			(void) __sflush(fp);
6146085Sbostic 		/* if close is NULL, closing is a no-op, hence pointless */
6246085Sbostic 		isopen = fp->_close != NULL;
6346085Sbostic 		if ((wantfd = fp->_file) < 0 && isopen) {
6446085Sbostic 			(void) (*fp->_close)(fp->_cookie);
6546085Sbostic 			isopen = 0;
6646085Sbostic 		}
6717951Sserge 	}
6817951Sserge 
6946085Sbostic 	/* Get a new descriptor to refer to the new file. */
7046085Sbostic 	f = open(file, oflags, DEFFILEMODE);
7146085Sbostic 	if (f < 0 && isopen) {
7246085Sbostic 		/* If out of fd's close the old one and try again. */
7346085Sbostic 		if (errno == ENFILE || errno == EMFILE) {
7446085Sbostic 			(void) (*fp->_close)(fp->_cookie);
7546085Sbostic 			isopen = 0;
7646085Sbostic 			f = open(file, oflags, DEFFILEMODE);
7746085Sbostic 		}
7846085Sbostic 	}
7946085Sbostic 	sverrno = errno;
8046085Sbostic 
8146085Sbostic 	/*
8246085Sbostic 	 * Finish closing fp.  Even if the open succeeded above, we cannot
8346085Sbostic 	 * keep fp->_base: it may be the wrong size.  This loses the effect
8446085Sbostic 	 * of any setbuffer calls, but stdio has always done this before.
8546085Sbostic 	 */
8646085Sbostic 	if (isopen)
8746085Sbostic 		(void) (*fp->_close)(fp->_cookie);
8846085Sbostic 	if (fp->_flags & __SMBF)
8946085Sbostic 		free((char *)fp->_bf._base);
9046085Sbostic 	fp->_w = 0;
9146085Sbostic 	fp->_r = 0;
9246085Sbostic 	fp->_p = NULL;
9346085Sbostic 	fp->_bf._base = NULL;
9446085Sbostic 	fp->_bf._size = 0;
9546085Sbostic 	fp->_lbfsize = 0;
9646085Sbostic 	if (HASUB(fp))
9746085Sbostic 		FREEUB(fp);
9846085Sbostic 	fp->_ub._size = 0;
9946085Sbostic 	if (HASLB(fp))
10046085Sbostic 		FREELB(fp);
10146085Sbostic 	fp->_lb._size = 0;
10246085Sbostic 
10346085Sbostic 	if (f < 0) {			/* did not get it after all */
10446085Sbostic 		fp->_flags = 0;		/* set it free */
10546085Sbostic 		errno = sverrno;	/* restore in case _close clobbered */
10617951Sserge 		return (NULL);
10746085Sbostic 	}
10817951Sserge 
10946085Sbostic 	/*
11046085Sbostic 	 * If reopening something that was open before on a real file, try
11146085Sbostic 	 * to maintain the descriptor.  Various C library routines (perror)
11246085Sbostic 	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
11346085Sbostic 	 */
11446085Sbostic 	if (wantfd >= 0 && f != wantfd) {
11546085Sbostic 		if (dup2(f, wantfd) >= 0) {
11646085Sbostic 			(void) close(f);
11746085Sbostic 			f = wantfd;
11846085Sbostic 		}
11946085Sbostic 	}
12017951Sserge 
12146085Sbostic 	fp->_flags = flags;
12246085Sbostic 	fp->_file = f;
12346085Sbostic 	fp->_cookie = fp;
12446085Sbostic 	fp->_read = __sread;
12546085Sbostic 	fp->_write = __swrite;
12646085Sbostic 	fp->_seek = __sseek;
12746085Sbostic 	fp->_close = __sclose;
12846085Sbostic 	return (fp);
1292008Swnj }
130