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 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /*LINTLIBRARY*/ 30 #include <stdio.h> 31 #include <errno.h> 32 #include "../common/stdiom.h" 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <unistd.h> 36 #include <malloc.h> 37 38 extern unsigned char (*_smbuf)[_SBFSIZ]; 39 40 void _findbuf(FILE *); 41 void _bufsync(FILE *); 42 43 extern int fclose(); 44 45 /* 46 * Flush buffers on exit 47 */ 48 void 49 _cleanup(void) 50 { 51 52 _fwalk(fclose); 53 } 54 55 /* 56 * fclose() will flush (output) buffers for a buffered open 57 * FILE and then issue a system close on the _fileno. The 58 * _base field will be reset to NULL for any but stdin and 59 * stdout, the _ptr field will be set the same as the _base 60 * field. The _flags and the _cnt field will be zeroed. 61 * If buffers had been obtained via malloc(), the space will 62 * be free()'d. In case the FILE was not open, or fflush() 63 * or close() failed, an EOF will be returned, otherwise the 64 * return value is 0. 65 */ 66 int 67 fclose(FILE *iop) 68 { 69 int rtn=EOF; 70 71 if(iop == NULL) 72 return(rtn); 73 if(iop->_flag & (_IOREAD | _IOWRT | _IORW) 74 && (iop->_flag & _IOSTRG) == 0) { 75 rtn = (iop->_flag & _IONBF)? 0: fflush(iop); 76 if(close(fileno(iop)) < 0) 77 rtn = EOF; 78 } 79 if(iop->_flag & _IOMYBUF) { 80 free((char*)iop->_base); 81 iop->_base = NULL; 82 } 83 iop->_flag = 0; 84 iop->_cnt = 0; 85 iop->_ptr = iop->_base; 86 iop->_bufsiz = 0; 87 return(rtn); 88 } 89 90 /* 91 * The fflush() routine must take care because of the 92 * possibility for recursion. The calling program might 93 * do IO in an interupt catching routine that is likely 94 * to interupt the write() call within fflush() 95 */ 96 97 int 98 fflush(FILE *iop) 99 { 100 if (!(iop->_flag & _IOWRT)) { 101 if ((iop->_base != NULL) && iop->_cnt) { 102 lseek(iop->_file, -(iop->_cnt), SEEK_CUR); 103 iop->_cnt = 0; 104 } 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 /* 114 * The routine _flsbuf may or may not actually flush the output buffer. If 115 * the file is line-buffered, the fact that iop->_cnt has run below zero 116 * is meaningless: it is always kept below zero so that invocations of putc 117 * will consistently give control to _flsbuf, even if the buffer is far from 118 * full. _flsbuf, on seeing the "line-buffered" flag, determines whether the 119 * buffer is actually full by comparing iop->_ptr to the end of the buffer 120 * iop->_base + iop->_bufsiz. If it is full, or if an output line is 121 * completed (with a newline), the buffer is flushed. (Note: the character 122 * argument to _flsbuf is not flushed with the current buffer if the buffer 123 * is actually full -- it goes into the buffer after flushing.) 124 */ 125 126 int 127 _flsbuf(unsigned char c, FILE *iop) 128 { 129 unsigned char c1; 130 131 do { 132 /* check for linebuffered with write perm, but no EOF */ 133 if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) { 134 if ( iop->_ptr >= iop->_base + iop->_bufsiz ) /* if buffer full, */ 135 break; /* exit do-while, and flush buf. */ 136 if ( (*iop->_ptr++ = c) != '\n' ) 137 return(c); 138 return(_xflsbuf(iop) == EOF ? EOF : c); 139 } 140 /* write out an unbuffered file, if have write perm, but no EOF */ 141 if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) { 142 c1 = c; 143 iop->_cnt = 0; 144 if (write(fileno(iop), (char *) &c1, 1) == 1) 145 return(c); 146 iop->_flag |= _IOERR; 147 return(EOF); 148 } 149 /* The _wrtchk call is here rather than at the top of _flsbuf to re- */ 150 /* duce overhead for line-buffered I/O under normal circumstances. */ 151 152 if (_WRTCHK(iop)) /* is writing legitimate? */ 153 return(EOF); 154 } while ( (iop->_flag & (_IONBF | _IOLBF)) ); 155 156 157 (void) _xflsbuf(iop); /* full buffer: flush buffer */ 158 (void) putc((char) c, iop); /* then put "c" in newly emptied buf */ 159 /* (which, because of signals, may NOT be empty) */ 160 return( ferror(iop) ? EOF : c); 161 } 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(FILE *iop) 184 { 185 unsigned char *base; 186 int n; 187 188 n = iop->_ptr - (base = iop->_base); 189 iop->_ptr = base; 190 iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz; 191 _BUFSYNC(iop); 192 if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) ) { 193 iop->_flag |= _IOERR; 194 return(EOF); 195 } 196 return(0); 197 } 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(FILE *iop) 208 { 209 if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) { 210 if (!(iop->_flag & (_IOWRT | _IORW))) 211 return(EOF); /* bogus call--read-only file */ 212 iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */ 213 } 214 if (iop->_flag & _IOSTRG) 215 return(0); /* not our business to monkey with buffers or counts */ 216 if (iop->_base == NULL) /* this is first I/O to file--get buffer */ 217 _findbuf(iop); 218 if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) ) { 219 iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */ 220 _BUFSYNC(iop); 221 } 222 return(0); 223 } 224 225 /* 226 * _findbuf, called only when iop->_base == NULL, locates a predefined buffer 227 * or allocates a buffer using malloc. If a buffer is obtained from malloc, 228 * the _IOMYBUF flag is set in iop->_flag. 229 */ 230 231 void 232 _findbuf(FILE *iop) 233 { 234 int fno = fileno(iop); /* file number */ 235 struct stat statb; 236 int size; 237 238 /* allocate a small block for unbuffered, large for buffered */ 239 if (iop->_flag & _IONBF) { 240 iop->_base = _smbuf[fno]; 241 iop->_bufsiz = _SBFSIZ; 242 } else { 243 244 if ( isatty(fno) ) { 245 iop->_flag |= _IOLBF; 246 size = 128; 247 } else { 248 if (fstat(fno, &statb) < 0) 249 size = BUFSIZ; 250 else { 251 if ((size = statb.st_blksize) <= 0) 252 size = BUFSIZ; 253 } 254 } 255 if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) { 256 /* if we got a buffer */ 257 iop->_flag |= _IOMYBUF; 258 iop->_bufsiz = size; 259 } else { 260 /* if no room for buffer, use small buffer */ 261 iop->_base = _smbuf[fno]; 262 iop->_bufsiz = _SBFSIZ; 263 iop->_flag &= ~_IOLBF; 264 iop->_flag |= _IONBF; 265 } 266 } 267 iop->_ptr = iop->_base; 268 } 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 void 282 _bufsync(FILE *iop) 283 { 284 int spaceleft; 285 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