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, 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) 117 (void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC); 118 f = fp->_file; 119 isopen = 0; 120 wantfd = -1; 121 goto finish; 122 } 123 124 /* 125 * There are actually programs that depend on being able to "freopen" 126 * descriptors that weren't originally open. Keep this from breaking. 127 * Remember whether the stream was open to begin with, and which file 128 * descriptor (if any) was associated with it. If it was attached to 129 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin) 130 * should work. This is unnecessary if it was not a Unix file. 131 */ 132 if (fp->_flags == 0) { 133 fp->_flags = __SEOF; /* hold on to it */ 134 isopen = 0; 135 wantfd = -1; 136 } else { 137 /* flush the stream; ANSI doesn't require this. */ 138 if (fp->_flags & __SWR) 139 (void) __sflush(fp); 140 /* if close is NULL, closing is a no-op, hence pointless */ 141 isopen = fp->_close != NULL; 142 if ((wantfd = fp->_file) < 0 && isopen) { 143 (void) (*fp->_close)(fp->_cookie); 144 isopen = 0; 145 } 146 } 147 148 /* Get a new descriptor to refer to the new file. */ 149 f = _open(file, oflags, DEFFILEMODE); 150 /* If out of fd's close the old one and try again. */ 151 if (f < 0 && isopen && wantfd > STDERR_FILENO && 152 (errno == ENFILE || errno == EMFILE)) { 153 (void) (*fp->_close)(fp->_cookie); 154 isopen = 0; 155 wantfd = -1; 156 f = _open(file, oflags, DEFFILEMODE); 157 } 158 sverrno = errno; 159 160 finish: 161 /* 162 * Finish closing fp. Even if the open succeeded above, we cannot 163 * keep fp->_base: it may be the wrong size. This loses the effect 164 * of any setbuffer calls, but stdio has always done this before. 165 * 166 * Leave the existing file descriptor open until dup2() is called 167 * below to avoid races where a concurrent open() in another thread 168 * could claim the existing descriptor. 169 */ 170 if (fp->_flags & __SMBF) 171 free((char *)fp->_bf._base); 172 fp->_w = 0; 173 fp->_r = 0; 174 fp->_p = NULL; 175 fp->_bf._base = NULL; 176 fp->_bf._size = 0; 177 fp->_lbfsize = 0; 178 if (HASUB(fp)) 179 FREEUB(fp); 180 fp->_ub._size = 0; 181 if (HASLB(fp)) 182 FREELB(fp); 183 fp->_lb._size = 0; 184 fp->_orientation = 0; 185 memset(&fp->_mbstate, 0, sizeof(mbstate_t)); 186 fp->_flags2 = 0; 187 188 if (f < 0) { /* did not get it after all */ 189 if (isopen) 190 (void) (*fp->_close)(fp->_cookie); 191 fp->_flags = 0; /* set it free */ 192 errno = sverrno; /* restore in case _close clobbered */ 193 fp = NULL; 194 goto end; 195 } 196 197 /* 198 * If reopening something that was open before on a real file, try 199 * to maintain the descriptor. Various C library routines (perror) 200 * assume stderr is always fd STDERR_FILENO, even if being freopen'd. 201 */ 202 if (wantfd >= 0) { 203 if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) : 204 _dup2(f, wantfd)) >= 0) { 205 (void)_close(f); 206 f = wantfd; 207 } else 208 (void)_close(fp->_file); 209 } 210 211 /* 212 * File descriptors are a full int, but _file is only a short. 213 * If we get a valid file descriptor that is greater than 214 * SHRT_MAX, then the fd will get sign-extended into an 215 * invalid file descriptor. Handle this case by failing the 216 * open. 217 */ 218 if (f > SHRT_MAX) { 219 fp->_flags = 0; /* set it free */ 220 errno = EMFILE; 221 fp = NULL; 222 goto end; 223 } 224 225 fp->_flags = flags; 226 fp->_file = f; 227 fp->_cookie = fp; 228 fp->_read = __sread; 229 fp->_write = __swrite; 230 fp->_seek = __sseek; 231 fp->_close = __sclose; 232 /* 233 * When opening in append mode, even though we use O_APPEND, 234 * we need to seek to the end so that ftell() gets the right 235 * answer. If the user then alters the seek pointer, or 236 * the file extends, this will fail, but there is not much 237 * we can do about this. (We could set __SAPP and check in 238 * fseek and ftell.) 239 */ 240 if (oflags & O_APPEND) { 241 fp->_flags2 |= __S2OAP; 242 (void) _sseek(fp, (fpos_t)0, SEEK_END); 243 } 244 end: 245 FUNLOCKFILE_CANCELSAFE(); 246 return (fp); 247 } 248