]> git.saurik.com Git - apple/boot.git/blame - gen/libsaio/sys.c
boot-132.tar.gz
[apple/boot.git] / gen / libsaio / sys.c
CommitLineData
14c7c974
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
4f6e3300
A
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
14c7c974
A
13 *
14 * The Original Code and all software distributed under the License are
4f6e3300 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14c7c974
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
4f6e3300
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
14c7c974
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Mach Operating System
26 * Copyright (c) 1990 Carnegie-Mellon University
27 * Copyright (c) 1989 Carnegie-Mellon University
28 * Copyright (c) 1988 Carnegie-Mellon University
29 * Copyright (c) 1987 Carnegie-Mellon University
30 * All rights reserved. The CMU software License Agreement specifies
31 * the terms and conditions for use and redistribution.
32 *
33 */
34/*
35 * HISTORY
36 * Revision 2.3 88/08/08 13:47:07 rvb
37 * Allocate buffers dynamically vs statically.
38 * Now b[i] and i_fs and i_buf, are allocated dynamically.
39 * boot_calloc(size) allocates and zeros a buffer rounded to a NPG
40 * boundary.
41 * Generalize boot spec to allow, xx()/mach, xx(n,[a..h])/mach,
42 * xx([a..h])/mach, ...
43 * Also default "xx" if unspecified and alloc just "/mach",
44 * where everything is defaulted
45 * Add routine, ptol(), to parse partition letters.
46 *
47 */
48
49/*
50 * Copyright (c) 1982, 1986 Regents of the University of California.
51 * All rights reserved. The Berkeley software License Agreement
52 * specifies the terms and conditions for redistribution.
53 *
54 * @(#)sys.c 7.1 (Berkeley) 6/5/86
55 */
56
57#import <sys/param.h>
58#import <ufs/fs.h>
59#import <ufs/fsdir.h>
60#import <sys/reboot.h>
f083c6c3 61#import <libkern/OSByteOrder.h>
14c7c974
A
62#import "libsaio.h"
63#import "cache.h"
64#import "kernBootStruct.h"
65
66char *gFilename;
67
68static ino_t dlook(char *s, struct iob *io);
69static char * xx(char *str, struct iob *file);
70volatile void stop(char *s);
71static int ffs(register long mask);
72
73extern int label_secsize;
74
75#define DCACHE 1
76#define ICACHE 1
77#define SYS_MESSAGES 1
78#define CHECK_CAREFULLY 0
79
80#if ICACHE
81#define ICACHE_SIZE 8
82static cache_t *icache;
83#endif ICACHE
84
85#define DEV_BSIZE label_secsize
86
87static struct iob *iob_from_fdesc(int fdesc)
88{
89 register struct iob *file;
90
91 if (fdesc < 0 || fdesc >= NFILES ||
92 ((file = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
93 return NULL;
94 else
95 return file;
96}
97
98static int
99openi(int n, struct iob *io)
100{
101 struct dinode *dp;
102 int cc;
103#if ICACHE
104 struct icommon *ip;
105
106 if (icache == 0) {
107 icache = cacheInit(ICACHE_SIZE, sizeof(struct icommon));
108 }
109#endif ICACHE
110 io->i_offset = 0;
111 io->i_bn = fsbtodb(io->i_fs, itod(io->i_fs, n)) + io->i_boff;
112 io->i_cc = io->i_fs->fs_bsize;
113 io->i_ma = io->i_buf;
114
115#if ICACHE
116 if (cacheFind(icache, n, 0, (char **)&ip) == 1) {
117 io->i_ino.i_ic = *ip;
118 cc = 0;
119 } else {
120#endif ICACHE
121 cc = devread(io);
122 dp = (struct dinode *)io->i_buf;
123#if BIG_ENDIAN_FS
124 byte_swap_inode_in(&dp[itoo(io->i_fs, n)].di_ic, &io->i_ino.i_ic);
125#else
126 io->i_ino.i_ic = dp[itoo(io->i_fs, n)].di_ic;
127#endif BIG_ENDIAN_FS
128#if ICACHE
129 *ip = io->i_ino.i_ic;
130 }
131#endif ICACHE
132 io->i_ino.i_number = n;
133 return (cc);
134}
135
136static int
137find(char *path, struct iob *file)
138{
139 char *q;
140 char c;
141 int n = 0;
142
143#if CHECK_CAREFULLY
144 if (path==NULL || *path=='\0') {
145 printf("null path\n");
146 return (0);
147 }
148#endif CHECK_CAREFULLY
149 if (openi((ino_t) ROOTINO, file) < 0)
150 {
151#if SYS_MESSAGES
152 error("bad root inode\n");
153#endif
154 return (0);
155 }
156 while (*path)
157 {
158 while (*path == '/')
159 path++;
160 q = path;
161 while(*q != '/' && *q != '\0')
162 q++;
163 c = *q;
164 *q = '\0';
165 if (q == path) path = "." ; /* "/" means "/." */
166
167 if ((n = dlook(path, file)) != 0)
168 {
169 if (c == '\0')
170 break;
171 if (openi(n, file) < 0)
172 {
173 *q = c;
174 return (0);
175 }
176 *q = c;
177 path = q;
178 continue;
179 }
180 else
181 {
182 *q = c;
183 return (0);
184 }
185 }
186 return (n);
187}
188
189static daddr_t
190sbmap(struct iob *io, daddr_t bn)
191{
192 register struct inode *ip;
193 int i, j, sh;
194 daddr_t nb, *bap;
195
196 ip = &io->i_ino;
197
198 if (ip->i_icflags & IC_FASTLINK)
199 {
200 error("fast symlinks unimplemented\n");
201 return ((daddr_t)0);
202 }
203
204 if (bn < 0) {
205#if SYS_MESSAGES
206 error("bn negative\n");
207#endif
208 return ((daddr_t)0);
209 }
210
211 /*
212 * blocks 0..NDADDR are direct blocks
213 */
214 if(bn < NDADDR)
215 {
216 nb = ip->i_db[bn];
217 return (nb);
218 }
219
220 /*
221 * addresses NIADDR have single and double indirect blocks.
222 * the first step is to determine how many levels of indirection.
223 */
224 sh = 1;
225 bn -= NDADDR;
226 for (j = NIADDR; j > 0; j--) {
227 sh *= NINDIR(io->i_fs);
228 if (bn < sh)
229 break;
230 bn -= sh;
231 }
232 if (j == 0) {
233#if SYS_MESSAGES
234 error("bn ovf %d\n", bn);
235#endif
236 return ((daddr_t)0);
237 }
238
239 /*
240 * fetch the first indirect block address from the inode
241 */
242 nb = ip->i_ib[NIADDR - j];
243 if (nb == 0) {
244#if SYS_MESSAGES
245 error("bn void %d\n",bn);
246#endif
247 return ((daddr_t)0);
248 }
249
250 /*
251 * fetch through the indirect blocks
252 */
253 for (; j <= NIADDR; j++) {
254 if (blknos[j] != nb) {
255 io->i_bn = fsbtodb(io->i_fs, nb) + io->i_boff;
256 if (b[j] == (char *)0)
257 b[j] = malloc(MAXBSIZE);
258 io->i_ma = b[j];
259 io->i_cc = io->i_fs->fs_bsize;
260 if (devread(io) != io->i_fs->fs_bsize) {
261#if SYS_MESSAGES
262 error("bn %d: read error\n", io->i_bn);
263#endif
264 return ((daddr_t)0);
265 }
266 blknos[j] = nb;
267 }
268 bap = (daddr_t *)b[j];
269 sh /= NINDIR(io->i_fs);
270 i = (bn / sh) % NINDIR(io->i_fs);
271#if BIG_ENDIAN_FS
272#if 1
273 // for now it is little endian FS for intel
274 nb = bap[i];
275#else
f083c6c3 276 nb = OSSwapBigToHostInt32(bap[i]);
14c7c974
A
277#endif 1
278#else BIG_ENDIAN_FS
279 nb = bap[i];
280#endif BIG_ENDIAN_FS
281 if(nb == 0) {
282#if SYS_MESSAGES
283 error("bn void %d\n",bn);
284#endif
285 return ((daddr_t)0);
286 }
287 }
288
289 return (nb);
290}
291
292static ino_t
293dlook(
294 char *s,
295 struct iob *io
296)
297{
298 struct direct *dp;
299 register struct inode *ip;
300 struct dirstuff dirp;
301 int len;
302
303 if (s == NULL || *s == '\0')
304 return (0);
305 ip = &io->i_ino;
306 if ((ip->i_mode & IFMT) != IFDIR) {
307#if SYS_MESSAGES
308 error(". before %s not a dir\n", s);
309#endif
310 return (0);
311 }
312 if (ip->i_size == 0) {
313#if SYS_MESSAGES
314 error("%s: 0 length dir\n", s);
315#endif
316 return (0);
317 }
318 len = strlen(s);
319 dirp.loc = 0;
320 dirp.io = io;
321 io->dirbuf_blkno = -1;
322
323 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
324#if DEBUG1
325 printf("checking name %s\n", dp->d_name);
326#endif DEBUG1
327 if(dp->d_ino == 0)
328 continue;
329 if (dp->d_namlen == len && !strcmp(s, dp->d_name))
330 return (dp->d_ino);
331 }
332 return (0);
333}
334
335struct dirstuff *
336opendir(char *path)
337{
338 register struct dirstuff *dirp;
339 register int fd;
340
341 dirp = (struct dirstuff *)malloc(sizeof(struct dirstuff));
342 if (dirp == (struct dirstuff *)-1)
343 return 0;
344 fd = open(path,0);
345 if (fd == -1) {
346 free((void *)dirp);
347 return 0;
348 }
349 dirp->io = &iob[fd];
350 dirp->loc = 0;
351 iob[fd].dirbuf_blkno = -1;
352 return dirp;
353}
354
355int
356closedir(struct dirstuff *dirp)
357{
358 close(iob - dirp->io);
359 free((void *)dirp);
360 return 0;
361}
362
363#if DCACHE
364static cache_t *dcache;
365#define DCACHE_SIZE 6
366#endif
367
368/*
369 * get next entry in a directory.
370 */
371struct direct *
372readdir(struct dirstuff *dirp)
373{
374 struct direct *dp;
375 register struct iob *io;
376 daddr_t lbn, d;
377 int off;
378#if DCACHE
379 char *bp;
380 int dirblkno;
381
382 if (dcache == 0)
383 dcache = cacheInit(DCACHE_SIZE, DIRBLKSIZ);
384#endif DCACHE
385 io = dirp->io;
386 for(;;)
387 {
388 if (dirp->loc >= io->i_ino.i_size)
389 return (NULL);
390 off = blkoff(io->i_fs, dirp->loc);
391 lbn = lblkno(io->i_fs, dirp->loc);
392
393#if DCACHE
394 dirblkno = dirp->loc / DIRBLKSIZ;
395 if (cacheFind(dcache, io->i_ino.i_number, dirblkno, &bp)) {
396 dp = (struct direct *)(bp + (dirp->loc % DIRBLKSIZ));
397 } else
398#else DCACHE
399 if (io->dirbuf_blkno != lbn)
400#endif DCACHE
401 {
402 if((d = sbmap(io, lbn)) == 0)
403 return NULL;
404 io->i_bn = fsbtodb(io->i_fs, d) + io->i_boff;
405 io->i_ma = io->i_buf;
406 io->i_cc = blksize(io->i_fs, &io->i_ino, lbn);
407
408 if (devread(io) < 0)
409 {
410#if SYS_MESSAGES
411 error("bn %d: directory read error\n",
412 io->i_bn);
413#endif
414 return (NULL);
415 }
416#if BIG_ENDIAN_FS
417 byte_swap_dir_block_in(io->i_buf, io->i_cc);
418#endif BIG_ENDIAN_FS
419#if DCACHE
420 bcopy(io->i_buf + dirblkno * DIRBLKSIZ, bp, DIRBLKSIZ);
421 dp = (struct direct *)(io->i_buf + off);
422#endif
423 }
424#if !DCACHE
425 dp = (struct direct *)(io->i_buf + off);
426#endif
427 dirp->loc += dp->d_reclen;
428
429 if (dp->d_ino != 0) return (dp);
430 }
431}
432
433int
434b_lseek(int fdesc, unsigned int addr, int ptr)
435{
436 register struct iob *io;
437
438#if CHECK_CAREFULLY
439 if (ptr != 0) {
440 error("Seek not from beginning of file\n");
441 return (-1);
442 }
443#endif CHECK_CAREFULLY
444 if ((io = iob_from_fdesc(fdesc)) == 0) {
445 return (-1);
446 }
447 io->i_offset = addr;
448 io->i_bn = addr / DEV_BSIZE;
449 io->i_cc = 0;
450 return (0);
451}
452
453int
454tell(int fdesc)
455{
456 return iob[fdesc].i_offset;
457}
458
459static int getch(int fdesc)
460{
461 register struct iob *io;
462 struct fs *fs;
463 char *p;
464 int c, lbn, off, size, diff;
465
466 if ((io = iob_from_fdesc(fdesc)) == 0) {
467 return (-1);
468 }
469 p = io->i_ma;
470 if (io->i_cc <= 0) {
471 if ((io->i_flgs & F_FILE) != 0) {
472 diff = io->i_ino.i_size - io->i_offset;
473 if (diff <= 0)
474 return (-1);
475 fs = io->i_fs;
476 lbn = lblkno(fs, io->i_offset);
477 io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
478 off = blkoff(fs, io->i_offset);
479 size = blksize(fs, &io->i_ino, lbn);
480 } else {
481 diff = 0;
482#ifndef SMALL
483 io->i_bn = io->i_offset / DEV_BSIZE;
484 off = 0;
485 size = DEV_BSIZE;
486#endif SMALL
487 }
488 io->i_ma = io->i_buf;
489 io->i_cc = size;
490 if (devread(io) < 0) {
491 return (-1);
492 }
493 if ((io->i_flgs & F_FILE) != 0) {
494 if (io->i_offset - off + size >= io->i_ino.i_size)
495 io->i_cc = diff + off;
496 io->i_cc -= off;
497 }
498 p = &io->i_buf[off];
499 }
500 io->i_cc--;
501 io->i_offset++;
502 c = (unsigned)*p++;
503 io->i_ma = p;
504 return (c);
505}
506
507int
508read(int fdesc, char *buf, int count)
509{
510 int i, size;
511 register struct iob *file;
512 struct fs *fs;
513 int lbn, off;
514
515 if ((file = iob_from_fdesc(fdesc)) == 0) {
516 return (-1);
517 }
518 if ((file->i_flgs&F_READ) == 0) {
519 return (-1);
520 }
521#ifndef SMALL
522 if ((file->i_flgs & F_FILE) == 0) {
523 file->i_cc = count;
524 file->i_ma = buf;
525 file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
526 i = devread(file);
527 file->i_offset += count;
528 return (i);
529 }
530#endif SMALL
531 if (file->i_offset+count > file->i_ino.i_size)
532 count = file->i_ino.i_size - file->i_offset;
533 if ((i = count) <= 0)
534 return (0);
535 /*
536 * While reading full blocks, do I/O into user buffer.
537 * Anything else uses getc().
538 */
539 fs = file->i_fs;
540 while (i) {
541 off = blkoff(fs, file->i_offset);
542 lbn = lblkno(fs, file->i_offset);
543 size = blksize(fs, &file->i_ino, lbn);
544 if (off == 0 && size <= i) {
545 file->i_bn = fsbtodb(fs, sbmap(file, lbn)) +
546 file->i_boff;
547 file->i_cc = size;
548 file->i_ma = buf;
549 if (devread(file) < 0) {
550 return (-1);
551 }
552 file->i_offset += size;
553 file->i_cc = 0;
554 buf += size;
555 i -= size;
556 } else {
557 size -= off;
558 if (size > i)
559 size = i;
560 i -= size;
561 do {
562 *buf++ = getch(fdesc);
563 } while (--size);
564 }
565 }
566 return (count);
567}
568
569#if CHECK_CAREFULLY
570static int open_init;
571#endif CHECK_CAREFULLY
572static struct fs *fs_block;
573static int fs_block_valid;
574
575#define SUPERBLOCK_ERROR "Bad superblock: error %d\n"
576
577int
578open(char *str, int how)
579{
580 register char *cp;
581 register struct iob *file;
582 int i, fdesc;
583
584#if CHECK_CAREFULLY /* iob[] is in BSS, so it is guaranteed to be zero. */
585 if (open_init == 0) {
586 for (i = 0; i < NFILES; i++)
587 iob[i].i_flgs = 0;
588 open_init = 1;
589 }
590#endif
591
592 for (fdesc = 0; fdesc < NFILES; fdesc++)
593 if (iob[fdesc].i_flgs == 0)
594 goto gotfile;
595 stop("Out of file descriptor slots");
596
597gotfile:
598 (file = &iob[fdesc])->i_flgs |= F_ALLOC;
599
600 if ((cp = xx(str, file)) == (char *) -1)
601 {
602 close(fdesc);
603 return -1;
604 }
605
606 if (*cp == '\0') {
607 file->i_flgs |= how+1;
608 file->i_cc = 0;
609 file->i_offset = 0;
610 return (fdesc);
611 }
612 file->i_cc = SBSIZE;
613 file->i_bn = (SBLOCK / DEV_BSIZE) + file->i_boff;
614 file->i_offset = 0;
615
616 if (file->i_fs == 0) {
617 if (fs_block == 0) {
618 fs_block = (struct fs *)malloc(SBSIZE);
619 }
620 if (fs_block_valid == 0) {
621 file->i_ma = (char *)fs_block;
622 if (devread(file) < 0) {
623#ifndef SMALL
624 error(SUPERBLOCK_ERROR, 1);
625#endif
626 close(fdesc);
627 return (-1);
628 }
629 byte_swap_superblock(fs_block);
630 fs_block_valid = 1;
631 }
632 file->i_fs = fs_block;
633 file->i_buf = malloc(MAXBSIZE);
634 }
635#if BIG_ENDIAN_FS
636
637 if (file->i_fs->fs_magic != FS_MAGIC) {
638 error(SUPERBLOCK_ERROR, 2);
639 close(fdesc);
640 return (-1);
641 }
642 /*
643 * The following is a gross hack to boot disks that have an actual
644 * blocksize of 512 bytes but were written with a theoretical 1024
645 * byte blocksize (fsbtodb == 0).
646 *
647 * We can make this assumption because we can only boot disks with
648 * a 512 byte sector size.
649 */
650 if (file->i_fs->fs_fsize == 0) {
651 error(SUPERBLOCK_ERROR,3);
652 close(fdesc);
653 return (-1);
654 }
655 file->i_fs->fs_fsbtodb = ffs(file->i_fs->fs_fsize / DEV_BSIZE) - 1;
656#endif BIG_ENDIAN_FS
657
658 if ((i = find(cp, file)) == 0) {
659 close(fdesc);
660 return (-1);
661 }
662#if CHECK_CAREFULLY
663 if (how != 0) {
664 error("Can't write files\n");
665 close(fdesc);
666 return (-1);
667 }
668#endif CHECK_CAREFULLY
669
670 if (openi(i, file) < 0) {
671 close(fdesc);
672 return (-1);
673 }
674 file->i_offset = 0;
675 file->i_cc = 0;
676 file->i_flgs |= F_FILE | (how+1);
677
678 return (fdesc);
679}
680
681#define LP '('
682#define RP ')'
683
684static char * xx(char *str, struct iob *file)
685{
686 register char *cp = str, *xp;
687 char **dp;
688 int old_dev = kernBootStruct->kernDev;
689 int dev = (kernBootStruct->kernDev >> B_TYPESHIFT) & B_TYPEMASK;
690 int unit = (kernBootStruct->kernDev >> B_UNITSHIFT) & B_UNITMASK;
691 int part = (kernBootStruct->kernDev >> B_PARTITIONSHIFT) &
692 B_PARTITIONMASK;
693 int i;
694 int no_dev;
695 int biosOffset;
696
697 biosOffset = unit; // set the device
698
699 for (; *cp && *cp != LP; cp++) ;
700 if (no_dev = !*cp) { // no paren found
701 cp = str;
702 xp = devsw[dev];
703 } else if (cp == str) { // paren but no device
704 cp++;
705 xp = devsw[dev];
706 } else {
707 xp = str;
708 cp++;
709 }
710
711 for (dp = devsw; *dp; dp++)
712 {
713 if ((xp[0] == *dp[0]) && (xp[1] == *(dp[0] + 1)))
714 goto gotdev;
715 }
716
717 error("Unknown device '%c%c'\n",xp[0],xp[1]);
718 return ((char *)-1);
719
720gotdev:
721 if (no_dev)
722 goto none;
723 i = 0;
724 while (*cp >= '0' && *cp <= '9')
725 {
726 i = i * 10 + *cp++ - '0';
727 unit = i;
728 }
729
730 biosOffset = unit; // set the device
731
732 if (*cp == RP || no_dev)
733 /* do nothing since ptol(")") returns 0 */ ;
734 else if (*cp == ',' )
735 part = ptol(++cp);
736 else if (cp[-1] == LP)
737 part = ptol(cp);
738 else {
739badoff:
740 error("Missing offset specification\n");
741 return ((char *)-1);
742 }
743
744 for ( ;!no_dev ;) {
745 if (*cp == RP)
746 break;
747 if (*cp++)
748 continue;
749 goto badoff;
750 }
751
752none:
753 file->i_ino.i_dev = dev = dp-devsw;
754 file->partition = part;
755 file->biosdev = (BIOSDEV(dev)) + biosOffset;
756 if (dev == DEV_SD) {
757 file->biosdev += kernBootStruct->numIDEs;
758 } else if (dev == DEV_HD && kernBootStruct->numIDEs == 0) {
759 error("No IDE drives detected\n");
760 return ((char *)-1);
761 }
762
763 kernBootStruct->kernDev = (dev << B_TYPESHIFT) |
764 (unit << B_UNITSHIFT) |
765 (part << B_PARTITIONSHIFT);
766
767 if (kernBootStruct->kernDev != old_dev)
768 flushdev();
769
770 devopen(str, file);
771
772 if (file->i_error)
773 return (char *)-1;
774 if (!no_dev && *cp) cp++;
775
776 gFilename = cp;
777
778 return cp;
779}
780
781int
782close(int fdesc)
783{
784 register struct iob *file;
785 register int i;
786
787 if ((file = iob_from_fdesc(fdesc)) == 0) {
788 return (-1);
789 }
790// free((char *)file->i_fs);
791 file->i_fs = NULL;
792 free(file->i_buf); file->i_buf = NULL;
793 for (i=0;i<NBUFS;i++)
794 {
795 if (b[i])
796 { free(b[i]);
797 b[i] = NULL;
798 }
799 blknos[i] = 0;
800 }
801
802 file->i_flgs = 0;
803 return (0);
804}
805
806volatile void stop(char *s)
807{
808#if CHECK_CAREFULLY
809 register int i;
810
811 for (i = 0; i < NFILES; i++)
812 if (iob[i].i_flgs != 0)
813 close(i);
814#endif CHECK_CAREFULLY
815/* textMode();*/ // can't call this function from here
816 printf("\n%s\n", s);
817 sleep(4); // about to halt
818 halt();
819}
820
821static int ffs(register long mask)
822{
823 register int cnt;
824
825 if (mask == 0) return(0);
826 for (cnt = 1; !(mask & 1); cnt++)
827 mask >>= 1;
828 return(cnt);
829}
830
831int file_size(int fdesc)
832{
833 register struct iob *io;
834
835 if ((io = iob_from_fdesc(fdesc)) == 0) {
836 return (-1);
837 }
838 return io->i_ino.i_size;
839}
840
841/* ensure that all device caches are flushed,
842 * because we are about to change the device media
843 */
844
845void flushdev(void)
846{
847 register int i;
848
849 devflush();
850 for (i = 0; i < NFILES; i++)
851 if (iob[i].i_flgs & (F_READ | F_WRITE))
852 printf("flushdev: fd %d is open\n",i);
853 fs_block_valid = 0;
854#if ICACHE
855 cacheFlush(icache);
856#endif
857#if DCACHE
858 cacheFlush(dcache);
859#endif
860}
861