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