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 1989 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* Copyright (c) 1984 AT&T */ 27 /* All Rights Reserved */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 /*LINTLIBRARY*/ 32 #include <stdio.h> 33 #include "../common/stdiom.h" 34 #include <errno.h> 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <malloc.h> 38 #include <unistd.h> 39 40 extern int fclose(); 41 extern unsigned char (*_smbuf)[_SBFSIZ]; 42 43 void _findbuf(FILE *); 44 void _bufsync(FILE *); 45 46 /* 47 * Flush buffers on exit 48 */ 49 50 void 51 _cleanup(void) 52 { 53 54 _fwalk(fclose); 55 } 56 /* 57 * fclose() will flush (output) buffers for a buffered open 58 * FILE and then issue a system close on the _fileno. The 59 * _base field will be reset to NULL for any but stdin and 60 * stdout, the _ptr field will be set the same as the _base 61 * field. The _flags and the _cnt field will be zeroed. 62 * If buffers had been obtained via malloc(), the space will 63 * be free()'d. In case the FILE was not open, or fflush() 64 * or close() failed, an EOF will be returned, otherwise the 65 * return value is 0. 66 */ 67 68 int 69 fclose(FILE *iop) 70 { 71 int rtn=EOF; 72 73 if(iop == NULL) 74 return(rtn); 75 if(iop->_flag & (_IOREAD | _IOWRT | _IORW) 76 && (iop->_flag & _IOSTRG) == 0) { 77 rtn = (iop->_flag & _IONBF)? 0: fflush(iop); 78 if(close(fileno(iop)) < 0) 79 rtn = EOF; 80 } 81 if(iop->_flag & _IOMYBUF) { 82 free((char*)iop->_base); 83 iop->_base = NULL; 84 } 85 iop->_flag = 0; 86 iop->_cnt = 0; 87 iop->_ptr = iop->_base; 88 iop->_bufsiz = 0; 89 return(rtn); 90 } 91 92 /* 93 * The fflush() routine must take care because of the 94 * possibility for recursion. The calling program might 95 * do IO in an interupt catching routine that is likely 96 * to interupt the write() call within fflush() 97 */ 98 99 int 100 fflush(FILE *iop) 101 { 102 if (!(iop->_flag & _IOWRT)) { 103 return(0); 104 } 105 while(!(iop->_flag & _IONBF) && (iop->_flag & _IOWRT) && 106 (iop->_base != NULL) && (iop->_ptr > iop->_base) ) 107 (void) _xflsbuf(iop); 108 return(ferror(iop) ? EOF : 0); 109 } 110 111 /* The routine _flsbuf may or may not actually flush the output buffer. If 112 * the file is line-buffered, the fact that iop->_cnt has run below zero 113 * is meaningless: it is always kept below zero so that invocations of putc 114 * will consistently give control to _flsbuf, even if the buffer is far from 115 * full. _flsbuf, on seeing the "line-buffered" flag, determines whether the 116 * buffer is actually full by comparing iop->_ptr to the end of the buffer 117 * iop->_base + iop->_bufsiz. If it is full, or if an output line is 118 * completed (with a newline), the buffer is flushed. (Note: the character 119 * argument to _flsbuf is not flushed with the current buffer if the buffer 120 * is actually full -- it goes into the buffer after flushing.) 121 */ 122 123 int 124 _flsbuf(unsigned char c, FILE *iop) 125 { 126 unsigned char c1; 127 128 do { 129 /* check for linebuffered with write perm, but no EOF */ 130 if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) { 131 if ( iop->_ptr >= iop->_base + iop->_bufsiz ) /* if buffer full, */ 132 break; /* exit do-while, and flush buf. */ 133 if ( (*iop->_ptr++ = c) != '\n' ) 134 return(c); 135 return(_xflsbuf(iop) == EOF ? EOF : c); 136 } 137 /* write out an unbuffered file, if have write perm, but no EOF */ 138 if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) { 139 c1 = c; 140 iop->_cnt = 0; 141 if (write(fileno(iop), (char *) &c1, 1) == 1) 142 return(c); 143 iop->_flag |= _IOERR; 144 return(EOF); 145 } 146 /* The _wrtchk call is here rather than at the top of _flsbuf to re- */ 147 /* duce overhead for line-buffered I/O under normal circumstances. */ 148 149 if (_WRTCHK(iop)) /* is writing legitimate? */ 150 return(EOF); 151 } while ( (iop->_flag & (_IONBF | _IOLBF)) ); 152 153 154 (void) _xflsbuf(iop); /* full buffer: flush buffer */ 155 (void) putc((char) c, iop); /* then put "c" in newly emptied buf */ 156 /* (which, because of signals, may NOT be empty) */ 157 return( ferror(iop) ? EOF : c); 158 } 159 160 /* The function _xflsbuf writes out the current contents of the output 161 * buffer delimited by iop->_base and iop->_ptr. 162 * iop->_cnt is reset appropriately, but its value on entry to _xflsbuf 163 * is ignored. 164 * 165 * The following code is not strictly correct. If a signal is raised, 166 * invoking a signal-handler which generates output into the same buffer 167 * being flushed, a peculiar output sequence may result (for example, 168 * the output generated by the signal-handler may appear twice). At 169 * present no means has been found to guarantee correct behavior without 170 * resorting to the disabling of signals, a means considered too expensive. 171 * For now the code has been written with the intent of reducing the 172 * probability of strange effects and, when they do occur, of confining 173 * the damage. Except under extremely pathological circumstances, this 174 * code should be expected to respect buffer boundaries even in the face 175 * of interrupts and other signals. 176 */ 177 178 int 179 _xflsbuf(FILE *iop) 180 { 181 unsigned char *base; 182 int n; 183 184 n = iop->_ptr - (base = iop->_base); 185 iop->_ptr = base; 186 iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz; 187 _BUFSYNC(iop); 188 if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) ) { 189 iop->_flag |= _IOERR; 190 return(EOF); 191 } 192 return(0); 193 } 194 195 /* The function _wrtchk checks to see whether it is legitimate to write 196 * to the specified device. If it is, _wrtchk sets flags in iop->_flag for 197 * writing, assures presence of a buffer, and returns 0. If writing is not 198 * legitimate, EOF is returned. 199 */ 200 201 int 202 _wrtchk(FILE *iop) 203 { 204 if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) { 205 if (!(iop->_flag & (_IOWRT | _IORW))) 206 return(EOF); /* bogus call--read-only file */ 207 iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */ 208 } 209 if (iop->_flag & _IOSTRG) 210 return(0); /* not our business to monkey with buffers or counts */ 211 if (iop->_base == NULL) /* this is first I/O to file--get buffer */ 212 _findbuf(iop); 213 if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) ) { 214 iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */ 215 _BUFSYNC(iop); 216 } 217 return(0); 218 } 219 220 /* 221 * _findbuf, called only when iop->_base == NULL, locates a predefined buffer 222 * or allocates a buffer using malloc. If a buffer is obtained from malloc, 223 * the _IOMYBUF flag is set in iop->_flag. 224 */ 225 226 void 227 _findbuf(FILE *iop) 228 { 229 int fno = fileno(iop); /* file number */ 230 struct stat statb; 231 int size; 232 233 /* allocate a small block for unbuffered, large for buffered */ 234 if (iop->_flag & _IONBF) { 235 iop->_base = _smbuf[fno]; 236 iop->_bufsiz = _SBFSIZ; 237 } else { 238 239 if ( isatty(fno) ) { 240 iop->_flag |= _IOLBF; 241 size = 128; 242 } else { 243 if (fstat(fno, &statb) < 0) 244 size = BUFSIZ; 245 else { 246 if ((size = statb.st_blksize) <= 0) 247 size = BUFSIZ; 248 } 249 } 250 if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) { 251 /* if we got a buffer */ 252 iop->_flag |= _IOMYBUF; 253 iop->_bufsiz = size; 254 } else { 255 /* if no room for buffer, use small buffer */ 256 iop->_base = _smbuf[fno]; 257 iop->_bufsiz = _SBFSIZ; 258 iop->_flag &= ~_IOLBF; 259 iop->_flag |= _IONBF; 260 } 261 } 262 iop->_ptr = iop->_base; 263 } 264 265 /* 266 * The function _bufsync is called because interrupts and other signals 267 * which occur in between the decrementing of iop->_cnt and the incrementing 268 * of iop->_ptr, or in other contexts as well, may upset the synchronization 269 * of iop->_cnt and iop->ptr. If this happens, calling _bufsync should 270 * resynchronize the two quantities (this is not always possible). Resyn- 271 * chronization guarantees that putc invocations will not write beyond 272 * the end of the buffer. Note that signals during _bufsync can cause 273 * _bufsync to do the wrong thing, but usually with benign effects. 274 */ 275 276 void 277 _bufsync(FILE *iop) 278 { 279 int spaceleft; 280 unsigned char *bufend = iop->_base + iop->_bufsiz; 281 282 if ((spaceleft = bufend - iop->_ptr) < 0) 283 iop->_ptr = bufend; 284 else if (spaceleft < iop->_cnt) 285 iop->_cnt = spaceleft; 286 } 287