xref: /original-bsd/lib/libc/stdio/freopen.c (revision 82f2451b)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Chris Torek.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)freopen.c	8.1 (Berkeley) 06/04/93";
13 #endif /* LIBC_SCCS and not lint */
14 
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "local.h"
23 
24 /*
25  * Re-direct an existing, open (probably) file to some other file.
26  * ANSI is written such that the original file gets closed if at
27  * all possible, no matter what.
28  */
29 FILE *
freopen(file,mode,fp)30 freopen(file, mode, fp)
31 	const char *file, *mode;
32 	register FILE *fp;
33 {
34 	register int f;
35 	int flags, isopen, oflags, sverrno, wantfd;
36 
37 	if ((flags = __sflags(mode, &oflags)) == 0) {
38 		(void) fclose(fp);
39 		return (NULL);
40 	}
41 
42 	if (!__sdidinit)
43 		__sinit();
44 
45 	/*
46 	 * There are actually programs that depend on being able to "freopen"
47 	 * descriptors that weren't originally open.  Keep this from breaking.
48 	 * Remember whether the stream was open to begin with, and which file
49 	 * descriptor (if any) was associated with it.  If it was attached to
50 	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
51 	 * should work.  This is unnecessary if it was not a Unix file.
52 	 */
53 	if (fp->_flags == 0) {
54 		fp->_flags = __SEOF;	/* hold on to it */
55 		isopen = 0;
56 		wantfd = -1;
57 	} else {
58 		/* flush the stream; ANSI doesn't require this. */
59 		if (fp->_flags & __SWR)
60 			(void) __sflush(fp);
61 		/* if close is NULL, closing is a no-op, hence pointless */
62 		isopen = fp->_close != NULL;
63 		if ((wantfd = fp->_file) < 0 && isopen) {
64 			(void) (*fp->_close)(fp->_cookie);
65 			isopen = 0;
66 		}
67 	}
68 
69 	/* Get a new descriptor to refer to the new file. */
70 	f = open(file, oflags, DEFFILEMODE);
71 	if (f < 0 && isopen) {
72 		/* If out of fd's close the old one and try again. */
73 		if (errno == ENFILE || errno == EMFILE) {
74 			(void) (*fp->_close)(fp->_cookie);
75 			isopen = 0;
76 			f = open(file, oflags, DEFFILEMODE);
77 		}
78 	}
79 	sverrno = errno;
80 
81 	/*
82 	 * Finish closing fp.  Even if the open succeeded above, we cannot
83 	 * keep fp->_base: it may be the wrong size.  This loses the effect
84 	 * of any setbuffer calls, but stdio has always done this before.
85 	 */
86 	if (isopen)
87 		(void) (*fp->_close)(fp->_cookie);
88 	if (fp->_flags & __SMBF)
89 		free((char *)fp->_bf._base);
90 	fp->_w = 0;
91 	fp->_r = 0;
92 	fp->_p = NULL;
93 	fp->_bf._base = NULL;
94 	fp->_bf._size = 0;
95 	fp->_lbfsize = 0;
96 	if (HASUB(fp))
97 		FREEUB(fp);
98 	fp->_ub._size = 0;
99 	if (HASLB(fp))
100 		FREELB(fp);
101 	fp->_lb._size = 0;
102 
103 	if (f < 0) {			/* did not get it after all */
104 		fp->_flags = 0;		/* set it free */
105 		errno = sverrno;	/* restore in case _close clobbered */
106 		return (NULL);
107 	}
108 
109 	/*
110 	 * If reopening something that was open before on a real file, try
111 	 * to maintain the descriptor.  Various C library routines (perror)
112 	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
113 	 */
114 	if (wantfd >= 0 && f != wantfd) {
115 		if (dup2(f, wantfd) >= 0) {
116 			(void) close(f);
117 			f = wantfd;
118 		}
119 	}
120 
121 	fp->_flags = flags;
122 	fp->_file = f;
123 	fp->_cookie = fp;
124 	fp->_read = __sread;
125 	fp->_write = __swrite;
126 	fp->_seek = __sseek;
127 	fp->_close = __sclose;
128 	return (fp);
129 }
130