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
_cleanup(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
fclose(FILE * iop)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
fflush(FILE * iop)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
_flsbuf(unsigned char c,FILE * iop)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
_xflsbuf(FILE * iop)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
_wrtchk(FILE * iop)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
_findbuf(FILE * iop)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
_bufsync(FILE * iop)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