17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate *
267c478bdstevel@tonic-gate * "buffered" i/o functions for the standalone environment. (ugh).
277c478bdstevel@tonic-gate */
287c478bdstevel@tonic-gate
297c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
307c478bdstevel@tonic-gate
317c478bdstevel@tonic-gate#include <sys/types.h>
327c478bdstevel@tonic-gate#include <sys/promif.h>
337c478bdstevel@tonic-gate#include <sys/varargs.h>
347c478bdstevel@tonic-gate#include <sys/bootvfs.h>
357c478bdstevel@tonic-gate#include <sys/salib.h>
367c478bdstevel@tonic-gate
377c478bdstevel@tonic-gateenum {
387c478bdstevel@tonic-gate	F_OPEN		= 0x01,
397c478bdstevel@tonic-gate	F_ERROR		= 0x02,
407c478bdstevel@tonic-gate	F_SEEKABLE	= 0x04
417c478bdstevel@tonic-gate};
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gateFILE	__iob[_NFILE] = {
447c478bdstevel@tonic-gate	{ F_OPEN, 0, 0, 0, "stdin"	},
457c478bdstevel@tonic-gate	{ F_OPEN, 1, 0, 0, "stdout"	},
467c478bdstevel@tonic-gate	{ F_OPEN, 2, 0, 0, "stderr"	}
477c478bdstevel@tonic-gate};
487c478bdstevel@tonic-gate
497c478bdstevel@tonic-gatestatic boolean_t
507c478bdstevel@tonic-gatefcheck(FILE *stream, int flags)
517c478bdstevel@tonic-gate{
527c478bdstevel@tonic-gate	errno = 0;
537c478bdstevel@tonic-gate	if ((stream->_flag & flags) != flags) {
547c478bdstevel@tonic-gate		errno = EBADF;
557c478bdstevel@tonic-gate		return (B_FALSE);
567c478bdstevel@tonic-gate	}
577c478bdstevel@tonic-gate	return (B_TRUE);
587c478bdstevel@tonic-gate}
597c478bdstevel@tonic-gate
607c478bdstevel@tonic-gateint
617c478bdstevel@tonic-gatefclose(FILE *stream)
627c478bdstevel@tonic-gate{
637c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
647c478bdstevel@tonic-gate		return (EOF);
657c478bdstevel@tonic-gate
667c478bdstevel@tonic-gate	(void) close(stream->_file);
677c478bdstevel@tonic-gate	stream->_flag = 0;
687c478bdstevel@tonic-gate	stream->_file = -1;
697c478bdstevel@tonic-gate	stream->_name[0] = '\0';
707c478bdstevel@tonic-gate	return (0);
717c478bdstevel@tonic-gate}
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gateint
747c478bdstevel@tonic-gatefeof(FILE *stream)
757c478bdstevel@tonic-gate{
767c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
777c478bdstevel@tonic-gate		return (0);
787c478bdstevel@tonic-gate
797c478bdstevel@tonic-gate	return (stream->_len == stream->_offset);
807c478bdstevel@tonic-gate}
817c478bdstevel@tonic-gate
827c478bdstevel@tonic-gateint
837c478bdstevel@tonic-gateferror(FILE *stream)
847c478bdstevel@tonic-gate{
857c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
867c478bdstevel@tonic-gate		return (0);
877c478bdstevel@tonic-gate
887c478bdstevel@tonic-gate	return ((stream->_flag & F_ERROR) != 0);
897c478bdstevel@tonic-gate}
907c478bdstevel@tonic-gate
917c478bdstevel@tonic-gatevoid
927c478bdstevel@tonic-gateclearerr(FILE *stream)
937c478bdstevel@tonic-gate{
947c478bdstevel@tonic-gate	stream->_flag &= ~F_ERROR;
957c478bdstevel@tonic-gate}
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gateint
987c478bdstevel@tonic-gatefflush(FILE *stream)
997c478bdstevel@tonic-gate{
1007c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
1017c478bdstevel@tonic-gate		return (EOF);
1027c478bdstevel@tonic-gate
1037c478bdstevel@tonic-gate	/* Currently, a nop */
1047c478bdstevel@tonic-gate	return (0);
1057c478bdstevel@tonic-gate}
1067c478bdstevel@tonic-gate
1077c478bdstevel@tonic-gatechar *
1087c478bdstevel@tonic-gatefgets(char *s, int n, FILE *stream)
1097c478bdstevel@tonic-gate{
1107c478bdstevel@tonic-gate	int	bytes;
1117c478bdstevel@tonic-gate	ssize_t	cnt;
1127c478bdstevel@tonic-gate
1137c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
1147c478bdstevel@tonic-gate		return (NULL);
1157c478bdstevel@tonic-gate
1167c478bdstevel@tonic-gate	for (bytes = 0; bytes < (n - 1); ++bytes) {
1177c478bdstevel@tonic-gate		cnt = read(stream->_file, &s[bytes], 1);
1187c478bdstevel@tonic-gate		if (cnt < 0) {
1197c478bdstevel@tonic-gate			if (bytes != 0) {
1207c478bdstevel@tonic-gate				s[bytes] = '\0';
1217c478bdstevel@tonic-gate				return (s);
1227c478bdstevel@tonic-gate			} else {
1237c478bdstevel@tonic-gate				stream->_flag |= F_ERROR;
1247c478bdstevel@tonic-gate				return (NULL);
1257c478bdstevel@tonic-gate			}
1267c478bdstevel@tonic-gate		} else if (cnt == 0) {
1277c478bdstevel@tonic-gate			/* EOF */
1287c478bdstevel@tonic-gate			if (bytes != 0) {
1297c478bdstevel@tonic-gate				s[bytes] = '\0';
1307c478bdstevel@tonic-gate				return (s);
1317c478bdstevel@tonic-gate			} else
1327c478bdstevel@tonic-gate				return (NULL);
1337c478bdstevel@tonic-gate		} else {
1347c478bdstevel@tonic-gate			stream->_offset++;
1357c478bdstevel@tonic-gate			if (s[bytes] == '\n') {
1367c478bdstevel@tonic-gate				s[bytes + 1] = '\0';
1377c478bdstevel@tonic-gate				return (s);
1387c478bdstevel@tonic-gate			}
1397c478bdstevel@tonic-gate		}
1407c478bdstevel@tonic-gate	}
1417c478bdstevel@tonic-gate	s[bytes] = '\0';
1427c478bdstevel@tonic-gate	return (s);
1437c478bdstevel@tonic-gate}
1447c478bdstevel@tonic-gate
1457c478bdstevel@tonic-gate/*
1467c478bdstevel@tonic-gate * We currently only support read-only ("r" mode) opens and unbuffered I/O.
1477c478bdstevel@tonic-gate */
1487c478bdstevel@tonic-gateFILE *
1497c478bdstevel@tonic-gatefopen(const char *filename, const char *mode)
1507c478bdstevel@tonic-gate{
1517c478bdstevel@tonic-gate	FILE		*stream;
1527c478bdstevel@tonic-gate	const char	*t;
1537c478bdstevel@tonic-gate	int		fd, i;
1547c478bdstevel@tonic-gate
1557c478bdstevel@tonic-gate	errno = 0;
1567c478bdstevel@tonic-gate
1577c478bdstevel@tonic-gate	/*
1587c478bdstevel@tonic-gate	 * Make sure we have a filesystem underneath us before even trying.
1597c478bdstevel@tonic-gate	 */
1607c478bdstevel@tonic-gate	if (get_default_fs() == NULL)
1617c478bdstevel@tonic-gate		return (NULL);
1627c478bdstevel@tonic-gate
1637c478bdstevel@tonic-gate	for (t = mode; t != NULL && *t != '\0'; t++) {
1647c478bdstevel@tonic-gate		switch (*t) {
1657c478bdstevel@tonic-gate		case 'b':
1667c478bdstevel@tonic-gate			/* We ignore this a'la ISO C standard conformance */
1677c478bdstevel@tonic-gate			break;
1687c478bdstevel@tonic-gate		case 'r':
1697c478bdstevel@tonic-gate			/* We ignore this because we always open for reading */
1707c478bdstevel@tonic-gate			break;
1717c478bdstevel@tonic-gate
1727c478bdstevel@tonic-gate		case 'a':
1737c478bdstevel@tonic-gate		case 'w':
1747c478bdstevel@tonic-gate		case '+':
1757c478bdstevel@tonic-gate			errno = EROFS;
1767c478bdstevel@tonic-gate			return (NULL);
1777c478bdstevel@tonic-gate
1787c478bdstevel@tonic-gate		default:
1797c478bdstevel@tonic-gate			errno = EINVAL;
1807c478bdstevel@tonic-gate			return (NULL);
1817c478bdstevel@tonic-gate		}
1827c478bdstevel@tonic-gate	}
1837c478bdstevel@tonic-gate
1847c478bdstevel@tonic-gate	for (i = 0; i < _NFILE; i++) {
1857c478bdstevel@tonic-gate		stream = &__iob[i];
1867c478bdstevel@tonic-gate		if ((stream->_flag & F_OPEN) == 0) {
1877c478bdstevel@tonic-gate			fd = open(filename, O_RDONLY);
1887c478bdstevel@tonic-gate			if (fd < 0)
1897c478bdstevel@tonic-gate				return (NULL);
1907c478bdstevel@tonic-gate
1917c478bdstevel@tonic-gate			stream->_file = fd;
1927c478bdstevel@tonic-gate			stream->_flag |= F_OPEN;
1937c478bdstevel@tonic-gate			(void) strlcpy(stream->_name, filename,
1947c478bdstevel@tonic-gate			    sizeof (stream->_name));
1957c478bdstevel@tonic-gate			return (stream);
1967c478bdstevel@tonic-gate		}
1977c478bdstevel@tonic-gate	}
1987c478bdstevel@tonic-gate
1997c478bdstevel@tonic-gate	errno = EMFILE;
2007c478bdstevel@tonic-gate	return (NULL);
2017c478bdstevel@tonic-gate}
2027c478bdstevel@tonic-gate
2037c478bdstevel@tonic-gate/* PRINTFLIKE1 */
2047c478bdstevel@tonic-gatevoid
2057c478bdstevel@tonic-gateprintf(const char *fmt, ...)
2067c478bdstevel@tonic-gate{
2077c478bdstevel@tonic-gate	va_list adx;
2087c478bdstevel@tonic-gate
2097c478bdstevel@tonic-gate	va_start(adx, fmt);
2107c478bdstevel@tonic-gate	prom_vprintf(fmt, adx);
2117c478bdstevel@tonic-gate	va_end(adx);
2127c478bdstevel@tonic-gate}
2137c478bdstevel@tonic-gate
2147c478bdstevel@tonic-gate/*
2157c478bdstevel@tonic-gate * Only writing to stderr or stdout is permitted.
2167c478bdstevel@tonic-gate */
2177c478bdstevel@tonic-gate/* PRINTFLIKE2 */
2187c478bdstevel@tonic-gateint
2197c478bdstevel@tonic-gatefprintf(FILE *stream, const char *format, ...)
2207c478bdstevel@tonic-gate{
2217c478bdstevel@tonic-gate	int	nwritten;
2227c478bdstevel@tonic-gate	va_list	va;
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
2257c478bdstevel@tonic-gate		return (-1);
2267c478bdstevel@tonic-gate
2277c478bdstevel@tonic-gate	/*
2287c478bdstevel@tonic-gate	 * Since fopen() doesn't return writable streams, the only valid
2297c478bdstevel@tonic-gate	 * writable streams are stdout and stderr.
2307c478bdstevel@tonic-gate	 */
2317c478bdstevel@tonic-gate	if (stream != stdout && stream != stderr) {
2327c478bdstevel@tonic-gate		errno = EBADF;
2337c478bdstevel@tonic-gate		return (-1);
2347c478bdstevel@tonic-gate	}
2357c478bdstevel@tonic-gate
2367c478bdstevel@tonic-gate	va_start(va, format);
2377c478bdstevel@tonic-gate	printf(format, va);
2387c478bdstevel@tonic-gate	va_end(va);
2397c478bdstevel@tonic-gate
2407c478bdstevel@tonic-gate	va_start(va, format);
2417c478bdstevel@tonic-gate	nwritten = vsnprintf(NULL, 0, format, va);
2427c478bdstevel@tonic-gate	va_end(va);
2437c478bdstevel@tonic-gate
2447c478bdstevel@tonic-gate	return (nwritten);
2457c478bdstevel@tonic-gate}
2467c478bdstevel@tonic-gate
2477c478bdstevel@tonic-gatesize_t
2487c478bdstevel@tonic-gatefread(void *ptr, size_t size, size_t nitems, FILE *stream)
2497c478bdstevel@tonic-gate{
2507c478bdstevel@tonic-gate	size_t	items;
2517c478bdstevel@tonic-gate	ssize_t	bytes, totbytes = 0;
2527c478bdstevel@tonic-gate	char	*strp = ptr;
2537c478bdstevel@tonic-gate
2547c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
2557c478bdstevel@tonic-gate		return (0);
2567c478bdstevel@tonic-gate
2577c478bdstevel@tonic-gate	for (items = 0, bytes = 0; items < nitems; items++) {
2587c478bdstevel@tonic-gate		bytes = read(stream->_file, &strp[totbytes], size);
2597c478bdstevel@tonic-gate		if (bytes < 0) {
2607c478bdstevel@tonic-gate			stream->_flag |= F_ERROR;
2617c478bdstevel@tonic-gate			return (0);
2627c478bdstevel@tonic-gate		} else if (bytes == 0) {
2637c478bdstevel@tonic-gate			/* EOF */
2647c478bdstevel@tonic-gate			return ((totbytes == 0) ? 0 : totbytes / size);
2657c478bdstevel@tonic-gate		} else if (bytes == size) {
2667c478bdstevel@tonic-gate			stream->_offset += bytes;
2677c478bdstevel@tonic-gate			totbytes += bytes;
2687c478bdstevel@tonic-gate		} else {
2697c478bdstevel@tonic-gate			(void) lseek(stream->_file, stream->_offset, SEEK_SET);
2707c478bdstevel@tonic-gate			return (totbytes / size);
2717c478bdstevel@tonic-gate		}
2727c478bdstevel@tonic-gate	}
2737c478bdstevel@tonic-gate
2747c478bdstevel@tonic-gate	return (totbytes / size);
2757c478bdstevel@tonic-gate}
2767c478bdstevel@tonic-gate
2777c478bdstevel@tonic-gate/*
2787c478bdstevel@tonic-gate * We don't grow files.
2797c478bdstevel@tonic-gate */
2807c478bdstevel@tonic-gateint
2817c478bdstevel@tonic-gatefseek(FILE *stream, long offset, int whence)
2827c478bdstevel@tonic-gate{
2837c478bdstevel@tonic-gate	off_t	new_offset, result;
2847c478bdstevel@tonic-gate
2857c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN | F_SEEKABLE))
2867c478bdstevel@tonic-gate		return (-1);
2877c478bdstevel@tonic-gate
2887c478bdstevel@tonic-gate	switch (whence) {
2897c478bdstevel@tonic-gate	case SEEK_SET:
2907c478bdstevel@tonic-gate		new_offset = (off_t)offset;
2917c478bdstevel@tonic-gate		break;
2927c478bdstevel@tonic-gate	case SEEK_CUR:
2937c478bdstevel@tonic-gate		new_offset = stream->_offset + (off_t)offset;
2947c478bdstevel@tonic-gate		break;
2957c478bdstevel@tonic-gate	case SEEK_END:
2967c478bdstevel@tonic-gate		new_offset = (off_t)stream->_len + (off_t)offset;
2977c478bdstevel@tonic-gate		break;
2987c478bdstevel@tonic-gate	default:
2997c478bdstevel@tonic-gate		errno = EINVAL;
3007c478bdstevel@tonic-gate		return (-1);
3017c478bdstevel@tonic-gate	}
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate	if (new_offset > (off_t)stream->_len) {
3047c478bdstevel@tonic-gate		errno = EFBIG;
3057c478bdstevel@tonic-gate	} else if (new_offset < 0L) {
3067c478bdstevel@tonic-gate		errno = EOVERFLOW;
3077c478bdstevel@tonic-gate	} else {
3087c478bdstevel@tonic-gate		errno = 0;
3097c478bdstevel@tonic-gate	}
3107c478bdstevel@tonic-gate
3117c478bdstevel@tonic-gate	result = lseek(stream->_file, new_offset, SEEK_SET);
3127c478bdstevel@tonic-gate	if (result >= 0)
3137c478bdstevel@tonic-gate		stream->_offset = result;
3147c478bdstevel@tonic-gate	else
3157c478bdstevel@tonic-gate		stream->_flag |= F_ERROR;
3167c478bdstevel@tonic-gate
3177c478bdstevel@tonic-gate	return (result);
3187c478bdstevel@tonic-gate}
3197c478bdstevel@tonic-gate
3207c478bdstevel@tonic-gatelong
3217c478bdstevel@tonic-gateftell(FILE *stream)
3227c478bdstevel@tonic-gate{
3237c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN | F_SEEKABLE))
3247c478bdstevel@tonic-gate		return (0);
3257c478bdstevel@tonic-gate
3267c478bdstevel@tonic-gate	return ((long)stream->_offset);
3277c478bdstevel@tonic-gate}
3287c478bdstevel@tonic-gate
3297c478bdstevel@tonic-gatesize_t
3307c478bdstevel@tonic-gatefwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)
3317c478bdstevel@tonic-gate{
3327c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
3337c478bdstevel@tonic-gate		return (0);
3347c478bdstevel@tonic-gate
3357c478bdstevel@tonic-gate	/*
3367c478bdstevel@tonic-gate	 * Since fopen() doesn't return writable streams, the only valid
3377c478bdstevel@tonic-gate	 * writable streams are stdout and stderr.
3387c478bdstevel@tonic-gate	 */
3397c478bdstevel@tonic-gate	if (stream != stdout && stream != stderr) {
3407c478bdstevel@tonic-gate		errno = EBADF;
3417c478bdstevel@tonic-gate		return (0);
3427c478bdstevel@tonic-gate	}
3437c478bdstevel@tonic-gate
3447c478bdstevel@tonic-gate	prom_writestr(ptr, size * nitems);
3457c478bdstevel@tonic-gate	return (nitems);
3467c478bdstevel@tonic-gate}
3477c478bdstevel@tonic-gate
3487c478bdstevel@tonic-gate/*ARGSUSED*/
3497c478bdstevel@tonic-gateint
3507c478bdstevel@tonic-gatesetvbuf(FILE *stream, char *buf, int type, size_t size)
3517c478bdstevel@tonic-gate{
3527c478bdstevel@tonic-gate	if (!fcheck(stream, F_OPEN))
3537c478bdstevel@tonic-gate		return (-1);
3547c478bdstevel@tonic-gate
3557c478bdstevel@tonic-gate	/* Currently a nop, probably always will be. */
3567c478bdstevel@tonic-gate	return (0);
3577c478bdstevel@tonic-gate}
358