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