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