xref: /illumos-gate/usr/src/stand/lib/sa/stdio.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
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
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
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
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
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
92 clearerr(FILE *stream)
93 {
94 	stream->_flag &= ~F_ERROR;
95 }
96 
97 int
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 *
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 *
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
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
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
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
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
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
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
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