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