1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate *
26*0Sstevel@tonic-gate * "buffered" i/o functions for the standalone environment. (ugh).
27*0Sstevel@tonic-gate */
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gate #include <sys/types.h>
32*0Sstevel@tonic-gate #include <sys/promif.h>
33*0Sstevel@tonic-gate #include <sys/varargs.h>
34*0Sstevel@tonic-gate #include <sys/bootvfs.h>
35*0Sstevel@tonic-gate #include <sys/salib.h>
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate enum {
38*0Sstevel@tonic-gate F_OPEN = 0x01,
39*0Sstevel@tonic-gate F_ERROR = 0x02,
40*0Sstevel@tonic-gate F_SEEKABLE = 0x04
41*0Sstevel@tonic-gate };
42*0Sstevel@tonic-gate
43*0Sstevel@tonic-gate FILE __iob[_NFILE] = {
44*0Sstevel@tonic-gate { F_OPEN, 0, 0, 0, "stdin" },
45*0Sstevel@tonic-gate { F_OPEN, 1, 0, 0, "stdout" },
46*0Sstevel@tonic-gate { F_OPEN, 2, 0, 0, "stderr" }
47*0Sstevel@tonic-gate };
48*0Sstevel@tonic-gate
49*0Sstevel@tonic-gate static boolean_t
fcheck(FILE * stream,int flags)50*0Sstevel@tonic-gate fcheck(FILE *stream, int flags)
51*0Sstevel@tonic-gate {
52*0Sstevel@tonic-gate errno = 0;
53*0Sstevel@tonic-gate if ((stream->_flag & flags) != flags) {
54*0Sstevel@tonic-gate errno = EBADF;
55*0Sstevel@tonic-gate return (B_FALSE);
56*0Sstevel@tonic-gate }
57*0Sstevel@tonic-gate return (B_TRUE);
58*0Sstevel@tonic-gate }
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate int
fclose(FILE * stream)61*0Sstevel@tonic-gate fclose(FILE *stream)
62*0Sstevel@tonic-gate {
63*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
64*0Sstevel@tonic-gate return (EOF);
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gate (void) close(stream->_file);
67*0Sstevel@tonic-gate stream->_flag = 0;
68*0Sstevel@tonic-gate stream->_file = -1;
69*0Sstevel@tonic-gate stream->_name[0] = '\0';
70*0Sstevel@tonic-gate return (0);
71*0Sstevel@tonic-gate }
72*0Sstevel@tonic-gate
73*0Sstevel@tonic-gate int
feof(FILE * stream)74*0Sstevel@tonic-gate feof(FILE *stream)
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
77*0Sstevel@tonic-gate return (0);
78*0Sstevel@tonic-gate
79*0Sstevel@tonic-gate return (stream->_len == stream->_offset);
80*0Sstevel@tonic-gate }
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gate int
ferror(FILE * stream)83*0Sstevel@tonic-gate ferror(FILE *stream)
84*0Sstevel@tonic-gate {
85*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
86*0Sstevel@tonic-gate return (0);
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gate return ((stream->_flag & F_ERROR) != 0);
89*0Sstevel@tonic-gate }
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate void
clearerr(FILE * stream)92*0Sstevel@tonic-gate clearerr(FILE *stream)
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate stream->_flag &= ~F_ERROR;
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate
97*0Sstevel@tonic-gate int
fflush(FILE * stream)98*0Sstevel@tonic-gate fflush(FILE *stream)
99*0Sstevel@tonic-gate {
100*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
101*0Sstevel@tonic-gate return (EOF);
102*0Sstevel@tonic-gate
103*0Sstevel@tonic-gate /* Currently, a nop */
104*0Sstevel@tonic-gate return (0);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate char *
fgets(char * s,int n,FILE * stream)108*0Sstevel@tonic-gate fgets(char *s, int n, FILE *stream)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate int bytes;
111*0Sstevel@tonic-gate ssize_t cnt;
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
114*0Sstevel@tonic-gate return (NULL);
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate for (bytes = 0; bytes < (n - 1); ++bytes) {
117*0Sstevel@tonic-gate cnt = read(stream->_file, &s[bytes], 1);
118*0Sstevel@tonic-gate if (cnt < 0) {
119*0Sstevel@tonic-gate if (bytes != 0) {
120*0Sstevel@tonic-gate s[bytes] = '\0';
121*0Sstevel@tonic-gate return (s);
122*0Sstevel@tonic-gate } else {
123*0Sstevel@tonic-gate stream->_flag |= F_ERROR;
124*0Sstevel@tonic-gate return (NULL);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate } else if (cnt == 0) {
127*0Sstevel@tonic-gate /* EOF */
128*0Sstevel@tonic-gate if (bytes != 0) {
129*0Sstevel@tonic-gate s[bytes] = '\0';
130*0Sstevel@tonic-gate return (s);
131*0Sstevel@tonic-gate } else
132*0Sstevel@tonic-gate return (NULL);
133*0Sstevel@tonic-gate } else {
134*0Sstevel@tonic-gate stream->_offset++;
135*0Sstevel@tonic-gate if (s[bytes] == '\n') {
136*0Sstevel@tonic-gate s[bytes + 1] = '\0';
137*0Sstevel@tonic-gate return (s);
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate }
140*0Sstevel@tonic-gate }
141*0Sstevel@tonic-gate s[bytes] = '\0';
142*0Sstevel@tonic-gate return (s);
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate * We currently only support read-only ("r" mode) opens and unbuffered I/O.
147*0Sstevel@tonic-gate */
148*0Sstevel@tonic-gate FILE *
fopen(const char * filename,const char * mode)149*0Sstevel@tonic-gate fopen(const char *filename, const char *mode)
150*0Sstevel@tonic-gate {
151*0Sstevel@tonic-gate FILE *stream;
152*0Sstevel@tonic-gate const char *t;
153*0Sstevel@tonic-gate int fd, i;
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gate errno = 0;
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate /*
158*0Sstevel@tonic-gate * Make sure we have a filesystem underneath us before even trying.
159*0Sstevel@tonic-gate */
160*0Sstevel@tonic-gate if (get_default_fs() == NULL)
161*0Sstevel@tonic-gate return (NULL);
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate for (t = mode; t != NULL && *t != '\0'; t++) {
164*0Sstevel@tonic-gate switch (*t) {
165*0Sstevel@tonic-gate case 'b':
166*0Sstevel@tonic-gate /* We ignore this a'la ISO C standard conformance */
167*0Sstevel@tonic-gate break;
168*0Sstevel@tonic-gate case 'r':
169*0Sstevel@tonic-gate /* We ignore this because we always open for reading */
170*0Sstevel@tonic-gate break;
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate case 'a':
173*0Sstevel@tonic-gate case 'w':
174*0Sstevel@tonic-gate case '+':
175*0Sstevel@tonic-gate errno = EROFS;
176*0Sstevel@tonic-gate return (NULL);
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate default:
179*0Sstevel@tonic-gate errno = EINVAL;
180*0Sstevel@tonic-gate return (NULL);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate
184*0Sstevel@tonic-gate for (i = 0; i < _NFILE; i++) {
185*0Sstevel@tonic-gate stream = &__iob[i];
186*0Sstevel@tonic-gate if ((stream->_flag & F_OPEN) == 0) {
187*0Sstevel@tonic-gate fd = open(filename, O_RDONLY);
188*0Sstevel@tonic-gate if (fd < 0)
189*0Sstevel@tonic-gate return (NULL);
190*0Sstevel@tonic-gate
191*0Sstevel@tonic-gate stream->_file = fd;
192*0Sstevel@tonic-gate stream->_flag |= F_OPEN;
193*0Sstevel@tonic-gate (void) strlcpy(stream->_name, filename,
194*0Sstevel@tonic-gate sizeof (stream->_name));
195*0Sstevel@tonic-gate return (stream);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gate errno = EMFILE;
200*0Sstevel@tonic-gate return (NULL);
201*0Sstevel@tonic-gate }
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate /* PRINTFLIKE1 */
204*0Sstevel@tonic-gate void
printf(const char * fmt,...)205*0Sstevel@tonic-gate printf(const char *fmt, ...)
206*0Sstevel@tonic-gate {
207*0Sstevel@tonic-gate va_list adx;
208*0Sstevel@tonic-gate
209*0Sstevel@tonic-gate va_start(adx, fmt);
210*0Sstevel@tonic-gate prom_vprintf(fmt, adx);
211*0Sstevel@tonic-gate va_end(adx);
212*0Sstevel@tonic-gate }
213*0Sstevel@tonic-gate
214*0Sstevel@tonic-gate /*
215*0Sstevel@tonic-gate * Only writing to stderr or stdout is permitted.
216*0Sstevel@tonic-gate */
217*0Sstevel@tonic-gate /* PRINTFLIKE2 */
218*0Sstevel@tonic-gate int
fprintf(FILE * stream,const char * format,...)219*0Sstevel@tonic-gate fprintf(FILE *stream, const char *format, ...)
220*0Sstevel@tonic-gate {
221*0Sstevel@tonic-gate int nwritten;
222*0Sstevel@tonic-gate va_list va;
223*0Sstevel@tonic-gate
224*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
225*0Sstevel@tonic-gate return (-1);
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gate /*
228*0Sstevel@tonic-gate * Since fopen() doesn't return writable streams, the only valid
229*0Sstevel@tonic-gate * writable streams are stdout and stderr.
230*0Sstevel@tonic-gate */
231*0Sstevel@tonic-gate if (stream != stdout && stream != stderr) {
232*0Sstevel@tonic-gate errno = EBADF;
233*0Sstevel@tonic-gate return (-1);
234*0Sstevel@tonic-gate }
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate va_start(va, format);
237*0Sstevel@tonic-gate printf(format, va);
238*0Sstevel@tonic-gate va_end(va);
239*0Sstevel@tonic-gate
240*0Sstevel@tonic-gate va_start(va, format);
241*0Sstevel@tonic-gate nwritten = vsnprintf(NULL, 0, format, va);
242*0Sstevel@tonic-gate va_end(va);
243*0Sstevel@tonic-gate
244*0Sstevel@tonic-gate return (nwritten);
245*0Sstevel@tonic-gate }
246*0Sstevel@tonic-gate
247*0Sstevel@tonic-gate size_t
fread(void * ptr,size_t size,size_t nitems,FILE * stream)248*0Sstevel@tonic-gate fread(void *ptr, size_t size, size_t nitems, FILE *stream)
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate size_t items;
251*0Sstevel@tonic-gate ssize_t bytes, totbytes = 0;
252*0Sstevel@tonic-gate char *strp = ptr;
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
255*0Sstevel@tonic-gate return (0);
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate for (items = 0, bytes = 0; items < nitems; items++) {
258*0Sstevel@tonic-gate bytes = read(stream->_file, &strp[totbytes], size);
259*0Sstevel@tonic-gate if (bytes < 0) {
260*0Sstevel@tonic-gate stream->_flag |= F_ERROR;
261*0Sstevel@tonic-gate return (0);
262*0Sstevel@tonic-gate } else if (bytes == 0) {
263*0Sstevel@tonic-gate /* EOF */
264*0Sstevel@tonic-gate return ((totbytes == 0) ? 0 : totbytes / size);
265*0Sstevel@tonic-gate } else if (bytes == size) {
266*0Sstevel@tonic-gate stream->_offset += bytes;
267*0Sstevel@tonic-gate totbytes += bytes;
268*0Sstevel@tonic-gate } else {
269*0Sstevel@tonic-gate (void) lseek(stream->_file, stream->_offset, SEEK_SET);
270*0Sstevel@tonic-gate return (totbytes / size);
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate }
273*0Sstevel@tonic-gate
274*0Sstevel@tonic-gate return (totbytes / size);
275*0Sstevel@tonic-gate }
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate /*
278*0Sstevel@tonic-gate * We don't grow files.
279*0Sstevel@tonic-gate */
280*0Sstevel@tonic-gate int
fseek(FILE * stream,long offset,int whence)281*0Sstevel@tonic-gate fseek(FILE *stream, long offset, int whence)
282*0Sstevel@tonic-gate {
283*0Sstevel@tonic-gate off_t new_offset, result;
284*0Sstevel@tonic-gate
285*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN | F_SEEKABLE))
286*0Sstevel@tonic-gate return (-1);
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate switch (whence) {
289*0Sstevel@tonic-gate case SEEK_SET:
290*0Sstevel@tonic-gate new_offset = (off_t)offset;
291*0Sstevel@tonic-gate break;
292*0Sstevel@tonic-gate case SEEK_CUR:
293*0Sstevel@tonic-gate new_offset = stream->_offset + (off_t)offset;
294*0Sstevel@tonic-gate break;
295*0Sstevel@tonic-gate case SEEK_END:
296*0Sstevel@tonic-gate new_offset = (off_t)stream->_len + (off_t)offset;
297*0Sstevel@tonic-gate break;
298*0Sstevel@tonic-gate default:
299*0Sstevel@tonic-gate errno = EINVAL;
300*0Sstevel@tonic-gate return (-1);
301*0Sstevel@tonic-gate }
302*0Sstevel@tonic-gate
303*0Sstevel@tonic-gate if (new_offset > (off_t)stream->_len) {
304*0Sstevel@tonic-gate errno = EFBIG;
305*0Sstevel@tonic-gate } else if (new_offset < 0L) {
306*0Sstevel@tonic-gate errno = EOVERFLOW;
307*0Sstevel@tonic-gate } else {
308*0Sstevel@tonic-gate errno = 0;
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate
311*0Sstevel@tonic-gate result = lseek(stream->_file, new_offset, SEEK_SET);
312*0Sstevel@tonic-gate if (result >= 0)
313*0Sstevel@tonic-gate stream->_offset = result;
314*0Sstevel@tonic-gate else
315*0Sstevel@tonic-gate stream->_flag |= F_ERROR;
316*0Sstevel@tonic-gate
317*0Sstevel@tonic-gate return (result);
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate long
ftell(FILE * stream)321*0Sstevel@tonic-gate ftell(FILE *stream)
322*0Sstevel@tonic-gate {
323*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN | F_SEEKABLE))
324*0Sstevel@tonic-gate return (0);
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gate return ((long)stream->_offset);
327*0Sstevel@tonic-gate }
328*0Sstevel@tonic-gate
329*0Sstevel@tonic-gate size_t
fwrite(const void * ptr,size_t size,size_t nitems,FILE * stream)330*0Sstevel@tonic-gate fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)
331*0Sstevel@tonic-gate {
332*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
333*0Sstevel@tonic-gate return (0);
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate /*
336*0Sstevel@tonic-gate * Since fopen() doesn't return writable streams, the only valid
337*0Sstevel@tonic-gate * writable streams are stdout and stderr.
338*0Sstevel@tonic-gate */
339*0Sstevel@tonic-gate if (stream != stdout && stream != stderr) {
340*0Sstevel@tonic-gate errno = EBADF;
341*0Sstevel@tonic-gate return (0);
342*0Sstevel@tonic-gate }
343*0Sstevel@tonic-gate
344*0Sstevel@tonic-gate prom_writestr(ptr, size * nitems);
345*0Sstevel@tonic-gate return (nitems);
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate
348*0Sstevel@tonic-gate /*ARGSUSED*/
349*0Sstevel@tonic-gate int
setvbuf(FILE * stream,char * buf,int type,size_t size)350*0Sstevel@tonic-gate setvbuf(FILE *stream, char *buf, int type, size_t size)
351*0Sstevel@tonic-gate {
352*0Sstevel@tonic-gate if (!fcheck(stream, F_OPEN))
353*0Sstevel@tonic-gate return (-1);
354*0Sstevel@tonic-gate
355*0Sstevel@tonic-gate /* Currently a nop, probably always will be. */
356*0Sstevel@tonic-gate return (0);
357*0Sstevel@tonic-gate }
358