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