Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/stdio/freopen.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1990, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Chris Torek.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include "namespace.h"
36
#include <sys/types.h>
37
#include <sys/stat.h>
38
#include <fcntl.h>
39
#include <errno.h>
40
#include <limits.h>
41
#include <unistd.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include "un-namespace.h"
45
#include "libc_private.h"
46
#include "local.h"
47
48
/*
49
* Re-direct an existing, open (probably) file to some other file.
50
* ANSI is written such that the original file gets closed if at
51
* all possible, no matter what.
52
*/
53
FILE *
54
freopen(const char * __restrict file, const char * __restrict mode,
55
FILE * __restrict fp)
56
{
57
int f;
58
int dflags, fdflags, flags, isopen, oflags, sverrno, wantfd;
59
60
if ((flags = __sflags(mode, &oflags)) == 0) {
61
sverrno = errno;
62
(void) fclose(fp);
63
errno = sverrno;
64
return (NULL);
65
}
66
67
FLOCKFILE_CANCELSAFE(fp);
68
69
if (!__sdidinit)
70
__sinit();
71
72
/*
73
* If the filename is a NULL pointer, the caller is asking us to
74
* re-open the same file with a different mode. We allow this only
75
* if the modes are compatible.
76
*/
77
if (file == NULL) {
78
/* See comment below regarding freopen() of closed files. */
79
if (fp->_flags == 0) {
80
errno = EINVAL;
81
fp = NULL;
82
goto end;
83
}
84
if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) {
85
sverrno = errno;
86
fclose(fp);
87
errno = sverrno;
88
fp = NULL;
89
goto end;
90
}
91
/* Work around incorrect O_ACCMODE. */
92
if ((dflags & O_ACCMODE) != O_RDWR &&
93
(dflags & (O_ACCMODE | O_EXEC)) != (oflags & O_ACCMODE)) {
94
fclose(fp);
95
errno = EBADF;
96
fp = NULL;
97
goto end;
98
}
99
if (fp->_flags & __SWR)
100
(void) __sflush(fp);
101
if ((oflags ^ dflags) & O_APPEND) {
102
dflags &= ~O_APPEND;
103
dflags |= oflags & O_APPEND;
104
if (_fcntl(fp->_file, F_SETFL, dflags) < 0) {
105
sverrno = errno;
106
fclose(fp);
107
errno = sverrno;
108
fp = NULL;
109
goto end;
110
}
111
}
112
if (oflags & O_TRUNC)
113
(void) ftruncate(fp->_file, (off_t)0);
114
if (!(oflags & O_APPEND))
115
(void) _sseek(fp, (fpos_t)0, SEEK_SET);
116
if ((oflags & O_CLOEXEC) != 0) {
117
fdflags = _fcntl(fp->_file, F_GETFD, 0);
118
if (fdflags != -1 && (fdflags & FD_CLOEXEC) == 0)
119
(void) _fcntl(fp->_file, F_SETFD,
120
fdflags | FD_CLOEXEC);
121
}
122
f = fp->_file;
123
isopen = 0;
124
wantfd = -1;
125
goto finish;
126
}
127
128
/*
129
* There are actually programs that depend on being able to "freopen"
130
* descriptors that weren't originally open. Keep this from breaking.
131
* Remember whether the stream was open to begin with, and which file
132
* descriptor (if any) was associated with it. If it was attached to
133
* a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
134
* should work. This is unnecessary if it was not a Unix file.
135
*/
136
if (fp->_flags == 0) {
137
fp->_flags = __SEOF; /* hold on to it */
138
isopen = 0;
139
wantfd = -1;
140
} else {
141
/* flush the stream; ANSI doesn't require this. */
142
if (fp->_flags & __SWR)
143
(void) __sflush(fp);
144
/* if close is NULL, closing is a no-op, hence pointless */
145
isopen = fp->_close != NULL;
146
if ((wantfd = fp->_file) < 0 && isopen) {
147
(void) (*fp->_close)(fp->_cookie);
148
isopen = 0;
149
}
150
}
151
152
/* Get a new descriptor to refer to the new file. */
153
f = _open(file, oflags, DEFFILEMODE);
154
/* If out of fd's close the old one and try again. */
155
if (f < 0 && isopen && wantfd > STDERR_FILENO &&
156
(errno == ENFILE || errno == EMFILE)) {
157
(void) (*fp->_close)(fp->_cookie);
158
isopen = 0;
159
wantfd = -1;
160
f = _open(file, oflags, DEFFILEMODE);
161
}
162
sverrno = errno;
163
164
finish:
165
/*
166
* Finish closing fp. Even if the open succeeded above, we cannot
167
* keep fp->_base: it may be the wrong size. This loses the effect
168
* of any setbuffer calls, but stdio has always done this before.
169
*
170
* Leave the existing file descriptor open until dup2() is called
171
* below to avoid races where a concurrent open() in another thread
172
* could claim the existing descriptor.
173
*/
174
if (fp->_flags & __SMBF)
175
free((char *)fp->_bf._base);
176
fp->_w = 0;
177
fp->_r = 0;
178
fp->_p = NULL;
179
fp->_bf._base = NULL;
180
fp->_bf._size = 0;
181
fp->_lbfsize = 0;
182
if (HASUB(fp))
183
FREEUB(fp);
184
fp->_ub._size = 0;
185
if (HASLB(fp))
186
FREELB(fp);
187
fp->_lb._size = 0;
188
fp->_orientation = 0;
189
memset(&fp->_mbstate, 0, sizeof(mbstate_t));
190
fp->_flags2 = 0;
191
192
if (f < 0) { /* did not get it after all */
193
if (isopen)
194
(void) (*fp->_close)(fp->_cookie);
195
fp->_flags = 0; /* set it free */
196
errno = sverrno; /* restore in case _close clobbered */
197
fp = NULL;
198
goto end;
199
}
200
201
/*
202
* If reopening something that was open before on a real file, try
203
* to maintain the descriptor. Various C library routines (perror)
204
* assume stderr is always fd STDERR_FILENO, even if being freopen'd.
205
*/
206
if (wantfd >= 0) {
207
if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) :
208
_dup2(f, wantfd)) >= 0) {
209
(void)_close(f);
210
f = wantfd;
211
} else
212
(void)_close(fp->_file);
213
}
214
215
/*
216
* File descriptors are a full int, but _file is only a short.
217
* If we get a valid file descriptor that is greater than
218
* SHRT_MAX, then the fd will get sign-extended into an
219
* invalid file descriptor. Handle this case by failing the
220
* open.
221
*/
222
if (f > SHRT_MAX) {
223
fp->_flags = 0; /* set it free */
224
errno = EMFILE;
225
fp = NULL;
226
goto end;
227
}
228
229
fp->_flags = flags;
230
fp->_file = f;
231
fp->_cookie = fp;
232
fp->_read = __sread;
233
fp->_write = __swrite;
234
fp->_seek = __sseek;
235
fp->_close = __sclose;
236
/*
237
* When opening in append mode, even though we use O_APPEND,
238
* we need to seek to the end so that ftell() gets the right
239
* answer. If the user then alters the seek pointer, or
240
* the file extends, this will fail, but there is not much
241
* we can do about this. (We could set __SAPP and check in
242
* fseek and ftell.)
243
*/
244
if (oflags & O_APPEND) {
245
fp->_flags2 |= __S2OAP;
246
(void) _sseek(fp, (fpos_t)0, SEEK_END);
247
}
248
end:
249
FUNLOCKFILE_CANCELSAFE();
250
return (fp);
251
}
252
253