1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include "lint.h" 43 #include "file64.h" 44 #include <sys/types.h> 45 #include <stdio.h> 46 #include <mtlib.h> 47 #include <fcntl.h> 48 #include <unistd.h> 49 #include <limits.h> 50 #include <thread.h> 51 #include <synch.h> 52 #include <stdlib.h> 53 #include <errno.h> 54 #include "stdiom.h" 55 #include "xpg6.h" 56 57 /* Final argument to _endopen depends on build environment */ 58 #define LARGE_OPEN (_FILE_OFFSET_BITS == 64) 59 60 FILE * 61 fopen(const char *name, const char *type) /* open name, return new stream */ 62 { 63 FILE *iop; 64 FILE *rc; 65 66 iop = _findiop(); 67 /* 68 * Note that iop is not locked here, since no other thread could 69 * possibly call _endopen with the same iop at this point. 70 */ 71 rc = _endopen(name, type, iop, LARGE_OPEN); 72 73 if (rc == NULL && iop != NULL) 74 iop->_flag = 0; /* release iop */ 75 76 return (rc); 77 } 78 79 static FILE * 80 _freopen_null(const char *type, FILE *iop) 81 { 82 char plus, mode; 83 int oflag, nflag, fd, accmode; 84 mbstate_t *mb; 85 86 if (iop == NULL || iop->_flag == 0) { 87 errno = EBADF; 88 return (NULL); 89 } 90 91 if (!(iop->_flag & _IONBF) && (iop->_flag & (_IOWRT | _IOREAD | _IORW))) 92 (void) _fflush_u(iop); 93 94 if (iop->_flag & _IOMYBUF) { 95 free((char *)iop->_base - PUSHBACK); 96 } 97 iop->_base = NULL; 98 iop->_ptr = NULL; 99 /* 100 * Clear stream orientation, clear stream encoding rule, and set 101 * stream's mbstate_t object to describe an initial conversion state. 102 */ 103 mb = _getmbstate(iop); 104 if (mb != NULL) 105 (void) memset(mb, 0, sizeof (mbstate_t)); 106 iop->_cnt = 0; 107 _setorientation(iop, _NO_MODE); 108 109 fd = FILENO(iop); 110 mode = type[0]; 111 if (mode != 'r' && mode != 'w' && mode != 'a') { 112 errno = EINVAL; 113 goto errret; 114 } 115 116 if ((oflag = fcntl(fd, F_GETFL)) == -1) 117 goto errret; 118 119 if ((plus = type[1]) == 'b') 120 plus = type[2]; 121 122 /* 123 * Because the filename has not been specified, the underlying file 124 * will not be closed and reopened. The access modes of an open 125 * file descriptor can't be changed via fcntl(). When '+' is 126 * specified, the old access mode needs to be O_RDWR. When 'r' is 127 * specified, the old access mode needs to be O_RDONLY or O_RDWR. 128 * When 'a' or 'w' is specified, the old access mode needs to be 129 * O_WRONLY or O_RDWR. Otherwise, fail with EBADF, indicating that 130 * the underlying file descriptor was not opened with a mode that 131 * would allow the stream to do successful I/O with the requested mode. 132 */ 133 134 accmode = oflag & O_ACCMODE; 135 if ((accmode == O_RDONLY && (mode != 'r' || plus == '+')) || 136 (accmode == O_WRONLY && (mode == 'r' || plus == '+'))) { 137 (void) close(fd); 138 errno = EBADF; 139 goto errret_noclose; 140 } 141 142 #ifdef _LP64 143 iop->_flag &= ~0377; /* clear lower 8-bits */ 144 if (mode == 'r') { 145 iop->_flag |= _IOREAD; 146 nflag = oflag & ~O_APPEND; 147 } else if (mode == 'w') { 148 iop->_flag |= _IOWRT; 149 nflag = oflag & ~O_APPEND; 150 } else { 151 iop->_flag |= _IOWRT; 152 nflag = oflag | O_APPEND; 153 } 154 if (plus == '+') { 155 iop->_flag = (iop->_flag & ~(_IOREAD | _IOWRT)) | _IORW; 156 } 157 #else 158 if (mode == 'r') { 159 iop->_flag = _IOREAD; 160 nflag = oflag & ~O_APPEND; 161 } else if (mode == 'w') { 162 iop->_flag = _IOWRT; 163 nflag = oflag & ~O_APPEND; 164 } else { 165 iop->_flag = _IOWRT; 166 nflag = oflag | O_APPEND; 167 } 168 if (plus == '+') { 169 iop->_flag = _IORW; 170 } 171 #endif 172 /* 173 * Change mode of underlying fd as much as possible without closing 174 * and reopening it. Ignore truncate failures, eg. with stdout. 175 */ 176 if (mode == 'w') 177 (void) ftruncate64(fd, (off64_t)0); 178 179 if (fcntl(fd, F_SETFL, nflag) == -1) 180 goto errret; 181 182 /* ignore seek failures, eg. with pipes */ 183 (void) lseek64(fd, (off64_t)0, SEEK_SET); 184 185 return (iop); 186 187 errret: 188 if (errno != EBADF) 189 (void) close(fd); 190 191 errret_noclose: 192 iop->_flag = 0; /* release iop */ 193 return (NULL); 194 } 195 196 FILE * 197 freopen(const char *name, const char *type, FILE *iop) 198 { 199 FILE *rc; 200 rmutex_t *lk; 201 202 if (name == NULL && __xpg6 & _C99SUSv3_freopen_NULL_filename) { 203 /* 204 * XPG6: If name is a null pointer, freopen will attempt to 205 * change the mode of the stream to that specified by type. 206 */ 207 FLOCKFILE(lk, iop); 208 rc = _freopen_null(type, iop); 209 FUNLOCKFILE(lk); 210 return (rc); 211 } 212 /* 213 * there may be concurrent calls to reopen the same stream - need 214 * to make freopen() atomic 215 */ 216 FLOCKFILE(lk, iop); 217 /* 218 * new function to do everything that fclose() does, except 219 * to release the iop - this cannot yet be released since 220 * _endopen() is yet to be called on this iop 221 */ 222 223 (void) close_fd(iop); 224 225 rc = _endopen(name, type, iop, LARGE_OPEN); 226 227 if (rc == NULL) 228 iop->_flag = 0; /* release iop */ 229 230 FUNLOCKFILE(lk); 231 return (rc); 232 } 233