17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 1989 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 307c478bd9Sstevel@tonic-gate #include <stdio.h> 31*5d54f3d8Smuffin #include <errno.h> 327c478bd9Sstevel@tonic-gate #include "../common/stdiom.h" 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/stat.h> 357c478bd9Sstevel@tonic-gate #include <unistd.h> 36*5d54f3d8Smuffin #include <malloc.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate extern unsigned char (*_smbuf)[_SBFSIZ]; 397c478bd9Sstevel@tonic-gate 40*5d54f3d8Smuffin void _findbuf(FILE *); 41*5d54f3d8Smuffin void _bufsync(FILE *); 42*5d54f3d8Smuffin 43*5d54f3d8Smuffin extern int fclose(); 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * Flush buffers on exit 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate void 49*5d54f3d8Smuffin _cleanup(void) 507c478bd9Sstevel@tonic-gate { 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate _fwalk(fclose); 537c478bd9Sstevel@tonic-gate } 547c478bd9Sstevel@tonic-gate 55*5d54f3d8Smuffin /* 56*5d54f3d8Smuffin * fclose() will flush (output) buffers for a buffered open 57*5d54f3d8Smuffin * FILE and then issue a system close on the _fileno. The 58*5d54f3d8Smuffin * _base field will be reset to NULL for any but stdin and 59*5d54f3d8Smuffin * stdout, the _ptr field will be set the same as the _base 60*5d54f3d8Smuffin * field. The _flags and the _cnt field will be zeroed. 61*5d54f3d8Smuffin * If buffers had been obtained via malloc(), the space will 62*5d54f3d8Smuffin * be free()'d. In case the FILE was not open, or fflush() 63*5d54f3d8Smuffin * or close() failed, an EOF will be returned, otherwise the 64*5d54f3d8Smuffin * return value is 0. 65*5d54f3d8Smuffin */ 667c478bd9Sstevel@tonic-gate int 67*5d54f3d8Smuffin fclose(FILE *iop) 687c478bd9Sstevel@tonic-gate { 69*5d54f3d8Smuffin int rtn=EOF; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate if(iop == NULL) 727c478bd9Sstevel@tonic-gate return(rtn); 737c478bd9Sstevel@tonic-gate if(iop->_flag & (_IOREAD | _IOWRT | _IORW) 747c478bd9Sstevel@tonic-gate && (iop->_flag & _IOSTRG) == 0) { 757c478bd9Sstevel@tonic-gate rtn = (iop->_flag & _IONBF)? 0: fflush(iop); 767c478bd9Sstevel@tonic-gate if(close(fileno(iop)) < 0) 777c478bd9Sstevel@tonic-gate rtn = EOF; 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate if(iop->_flag & _IOMYBUF) { 807c478bd9Sstevel@tonic-gate free((char*)iop->_base); 817c478bd9Sstevel@tonic-gate iop->_base = NULL; 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate iop->_flag = 0; 847c478bd9Sstevel@tonic-gate iop->_cnt = 0; 857c478bd9Sstevel@tonic-gate iop->_ptr = iop->_base; 867c478bd9Sstevel@tonic-gate iop->_bufsiz = 0; 877c478bd9Sstevel@tonic-gate return(rtn); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 91*5d54f3d8Smuffin * The fflush() routine must take care because of the 92*5d54f3d8Smuffin * possibility for recursion. The calling program might 93*5d54f3d8Smuffin * do IO in an interupt catching routine that is likely 94*5d54f3d8Smuffin * to interupt the write() call within fflush() 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate int 98*5d54f3d8Smuffin fflush(FILE *iop) 997c478bd9Sstevel@tonic-gate { 1007c478bd9Sstevel@tonic-gate if (!(iop->_flag & _IOWRT)) { 1017c478bd9Sstevel@tonic-gate if ((iop->_base != NULL) && iop->_cnt) { 1027c478bd9Sstevel@tonic-gate lseek(iop->_file, -(iop->_cnt), SEEK_CUR); 1037c478bd9Sstevel@tonic-gate iop->_cnt = 0; 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate return(0); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate while(!(iop->_flag & _IONBF) && (iop->_flag & _IOWRT) && 1087c478bd9Sstevel@tonic-gate (iop->_base != NULL) && (iop->_ptr > iop->_base) ) 1097c478bd9Sstevel@tonic-gate (void) _xflsbuf(iop); 1107c478bd9Sstevel@tonic-gate return(ferror(iop) ? EOF : 0); 1117c478bd9Sstevel@tonic-gate } 1127c478bd9Sstevel@tonic-gate 113*5d54f3d8Smuffin /* 114*5d54f3d8Smuffin * The routine _flsbuf may or may not actually flush the output buffer. If 1157c478bd9Sstevel@tonic-gate * the file is line-buffered, the fact that iop->_cnt has run below zero 1167c478bd9Sstevel@tonic-gate * is meaningless: it is always kept below zero so that invocations of putc 1177c478bd9Sstevel@tonic-gate * will consistently give control to _flsbuf, even if the buffer is far from 1187c478bd9Sstevel@tonic-gate * full. _flsbuf, on seeing the "line-buffered" flag, determines whether the 1197c478bd9Sstevel@tonic-gate * buffer is actually full by comparing iop->_ptr to the end of the buffer 1207c478bd9Sstevel@tonic-gate * iop->_base + iop->_bufsiz. If it is full, or if an output line is 1217c478bd9Sstevel@tonic-gate * completed (with a newline), the buffer is flushed. (Note: the character 1227c478bd9Sstevel@tonic-gate * argument to _flsbuf is not flushed with the current buffer if the buffer 1237c478bd9Sstevel@tonic-gate * is actually full -- it goes into the buffer after flushing.) 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate int 127*5d54f3d8Smuffin _flsbuf(unsigned char c, FILE *iop) 1287c478bd9Sstevel@tonic-gate { 1297c478bd9Sstevel@tonic-gate unsigned char c1; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate do { 1327c478bd9Sstevel@tonic-gate /* check for linebuffered with write perm, but no EOF */ 1337c478bd9Sstevel@tonic-gate if ( (iop->_flag & (_IOLBF | _IOWRT | _IOEOF)) == (_IOLBF | _IOWRT) ) { 1347c478bd9Sstevel@tonic-gate if ( iop->_ptr >= iop->_base + iop->_bufsiz ) /* if buffer full, */ 1357c478bd9Sstevel@tonic-gate break; /* exit do-while, and flush buf. */ 1367c478bd9Sstevel@tonic-gate if ( (*iop->_ptr++ = c) != '\n' ) 1377c478bd9Sstevel@tonic-gate return(c); 1387c478bd9Sstevel@tonic-gate return(_xflsbuf(iop) == EOF ? EOF : c); 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate /* write out an unbuffered file, if have write perm, but no EOF */ 1417c478bd9Sstevel@tonic-gate if ( (iop->_flag & (_IONBF | _IOWRT | _IOEOF)) == (_IONBF | _IOWRT) ) { 1427c478bd9Sstevel@tonic-gate c1 = c; 1437c478bd9Sstevel@tonic-gate iop->_cnt = 0; 1447c478bd9Sstevel@tonic-gate if (write(fileno(iop), (char *) &c1, 1) == 1) 1457c478bd9Sstevel@tonic-gate return(c); 1467c478bd9Sstevel@tonic-gate iop->_flag |= _IOERR; 1477c478bd9Sstevel@tonic-gate return(EOF); 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate /* The _wrtchk call is here rather than at the top of _flsbuf to re- */ 1507c478bd9Sstevel@tonic-gate /* duce overhead for line-buffered I/O under normal circumstances. */ 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (_WRTCHK(iop)) /* is writing legitimate? */ 1537c478bd9Sstevel@tonic-gate return(EOF); 1547c478bd9Sstevel@tonic-gate } while ( (iop->_flag & (_IONBF | _IOLBF)) ); 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate (void) _xflsbuf(iop); /* full buffer: flush buffer */ 1587c478bd9Sstevel@tonic-gate (void) putc((char) c, iop); /* then put "c" in newly emptied buf */ 1597c478bd9Sstevel@tonic-gate /* (which, because of signals, may NOT be empty) */ 1607c478bd9Sstevel@tonic-gate return( ferror(iop) ? EOF : c); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 163*5d54f3d8Smuffin /* 164*5d54f3d8Smuffin * The function _xflsbuf writes out the current contents of the output 1657c478bd9Sstevel@tonic-gate * buffer delimited by iop->_base and iop->_ptr. 1667c478bd9Sstevel@tonic-gate * iop->_cnt is reset appropriately, but its value on entry to _xflsbuf 1677c478bd9Sstevel@tonic-gate * is ignored. 1687c478bd9Sstevel@tonic-gate * 1697c478bd9Sstevel@tonic-gate * The following code is not strictly correct. If a signal is raised, 1707c478bd9Sstevel@tonic-gate * invoking a signal-handler which generates output into the same buffer 1717c478bd9Sstevel@tonic-gate * being flushed, a peculiar output sequence may result (for example, 1727c478bd9Sstevel@tonic-gate * the output generated by the signal-handler may appear twice). At 1737c478bd9Sstevel@tonic-gate * present no means has been found to guarantee correct behavior without 1747c478bd9Sstevel@tonic-gate * resorting to the disabling of signals, a means considered too expensive. 1757c478bd9Sstevel@tonic-gate * For now the code has been written with the intent of reducing the 1767c478bd9Sstevel@tonic-gate * probability of strange effects and, when they do occur, of confining 1777c478bd9Sstevel@tonic-gate * the damage. Except under extremely pathological circumstances, this 1787c478bd9Sstevel@tonic-gate * code should be expected to respect buffer boundaries even in the face 1797c478bd9Sstevel@tonic-gate * of interrupts and other signals. 1807c478bd9Sstevel@tonic-gate */ 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate int 183*5d54f3d8Smuffin _xflsbuf(FILE *iop) 1847c478bd9Sstevel@tonic-gate { 185*5d54f3d8Smuffin unsigned char *base; 186*5d54f3d8Smuffin int n; 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate n = iop->_ptr - (base = iop->_base); 1897c478bd9Sstevel@tonic-gate iop->_ptr = base; 1907c478bd9Sstevel@tonic-gate iop->_cnt = (iop->_flag &(_IONBF | _IOLBF)) ? 0 : iop->_bufsiz; 1917c478bd9Sstevel@tonic-gate _BUFSYNC(iop); 1927c478bd9Sstevel@tonic-gate if (n > 0 && n != write(fileno(iop),(char*)base,(unsigned)n) ) { 1937c478bd9Sstevel@tonic-gate iop->_flag |= _IOERR; 1947c478bd9Sstevel@tonic-gate return(EOF); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate return(0); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 199*5d54f3d8Smuffin /* 200*5d54f3d8Smuffin * The function _wrtchk checks to see whether it is legitimate to write 2017c478bd9Sstevel@tonic-gate * to the specified device. If it is, _wrtchk sets flags in iop->_flag for 2027c478bd9Sstevel@tonic-gate * writing, assures presence of a buffer, and returns 0. If writing is not 2037c478bd9Sstevel@tonic-gate * legitimate, EOF is returned. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate int 207*5d54f3d8Smuffin _wrtchk(FILE *iop) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate if ( (iop->_flag & (_IOWRT | _IOEOF)) != _IOWRT ) { 2107c478bd9Sstevel@tonic-gate if (!(iop->_flag & (_IOWRT | _IORW))) 2117c478bd9Sstevel@tonic-gate return(EOF); /* bogus call--read-only file */ 2127c478bd9Sstevel@tonic-gate iop->_flag = iop->_flag & ~_IOEOF | _IOWRT; /* fix flags */ 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate if (iop->_flag & _IOSTRG) 2157c478bd9Sstevel@tonic-gate return(0); /* not our business to monkey with buffers or counts */ 2167c478bd9Sstevel@tonic-gate if (iop->_base == NULL) /* this is first I/O to file--get buffer */ 2177c478bd9Sstevel@tonic-gate _findbuf(iop); 2187c478bd9Sstevel@tonic-gate if (iop->_ptr == iop->_base && !(iop->_flag & (_IONBF | _IOLBF)) ) { 2197c478bd9Sstevel@tonic-gate iop->_cnt = iop->_bufsiz; /* first write since seek--set cnt */ 2207c478bd9Sstevel@tonic-gate _BUFSYNC(iop); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate return(0); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 2267c478bd9Sstevel@tonic-gate * _findbuf, called only when iop->_base == NULL, locates a predefined buffer 2277c478bd9Sstevel@tonic-gate * or allocates a buffer using malloc. If a buffer is obtained from malloc, 2287c478bd9Sstevel@tonic-gate * the _IOMYBUF flag is set in iop->_flag. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate 231*5d54f3d8Smuffin void 232*5d54f3d8Smuffin _findbuf(FILE *iop) 2337c478bd9Sstevel@tonic-gate { 234*5d54f3d8Smuffin int fno = fileno(iop); /* file number */ 2357c478bd9Sstevel@tonic-gate struct stat statb; 236*5d54f3d8Smuffin int size; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* allocate a small block for unbuffered, large for buffered */ 2397c478bd9Sstevel@tonic-gate if (iop->_flag & _IONBF) { 2407c478bd9Sstevel@tonic-gate iop->_base = _smbuf[fno]; 2417c478bd9Sstevel@tonic-gate iop->_bufsiz = _SBFSIZ; 2427c478bd9Sstevel@tonic-gate } else { 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if ( isatty(fno) ) { 2457c478bd9Sstevel@tonic-gate iop->_flag |= _IOLBF; 2467c478bd9Sstevel@tonic-gate size = 128; 2477c478bd9Sstevel@tonic-gate } else { 2487c478bd9Sstevel@tonic-gate if (fstat(fno, &statb) < 0) 2497c478bd9Sstevel@tonic-gate size = BUFSIZ; 2507c478bd9Sstevel@tonic-gate else { 2517c478bd9Sstevel@tonic-gate if ((size = statb.st_blksize) <= 0) 2527c478bd9Sstevel@tonic-gate size = BUFSIZ; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate if ((iop->_base = (unsigned char *) malloc(size+8)) != NULL) { 2567c478bd9Sstevel@tonic-gate /* if we got a buffer */ 2577c478bd9Sstevel@tonic-gate iop->_flag |= _IOMYBUF; 2587c478bd9Sstevel@tonic-gate iop->_bufsiz = size; 2597c478bd9Sstevel@tonic-gate } else { 2607c478bd9Sstevel@tonic-gate /* if no room for buffer, use small buffer */ 2617c478bd9Sstevel@tonic-gate iop->_base = _smbuf[fno]; 2627c478bd9Sstevel@tonic-gate iop->_bufsiz = _SBFSIZ; 2637c478bd9Sstevel@tonic-gate iop->_flag &= ~_IOLBF; 2647c478bd9Sstevel@tonic-gate iop->_flag |= _IONBF; 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate } 2677c478bd9Sstevel@tonic-gate iop->_ptr = iop->_base; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 270*5d54f3d8Smuffin /* 271*5d54f3d8Smuffin * The function _bufsync is called because interrupts and other signals 2727c478bd9Sstevel@tonic-gate * which occur in between the decrementing of iop->_cnt and the incrementing 2737c478bd9Sstevel@tonic-gate * of iop->_ptr, or in other contexts as well, may upset the synchronization 2747c478bd9Sstevel@tonic-gate * of iop->_cnt and iop->ptr. If this happens, calling _bufsync should 2757c478bd9Sstevel@tonic-gate * resynchronize the two quantities (this is not always possible). Resyn- 2767c478bd9Sstevel@tonic-gate * chronization guarantees that putc invocations will not write beyond 2777c478bd9Sstevel@tonic-gate * the end of the buffer. Note that signals during _bufsync can cause 2787c478bd9Sstevel@tonic-gate * _bufsync to do the wrong thing, but usually with benign effects. 2797c478bd9Sstevel@tonic-gate */ 2807c478bd9Sstevel@tonic-gate 281*5d54f3d8Smuffin void 282*5d54f3d8Smuffin _bufsync(FILE *iop) 2837c478bd9Sstevel@tonic-gate { 284*5d54f3d8Smuffin int spaceleft; 285*5d54f3d8Smuffin unsigned char *bufend = iop->_base + iop->_bufsiz; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate if ((spaceleft = bufend - iop->_ptr) < 0) 2887c478bd9Sstevel@tonic-gate iop->_ptr = bufend; 2897c478bd9Sstevel@tonic-gate else if (spaceleft < iop->_cnt) 2907c478bd9Sstevel@tonic-gate iop->_cnt = spaceleft; 2917c478bd9Sstevel@tonic-gate } 292