Chameleon

Chameleon Svn Source Tree

Root/branches/JrCs/i386/libsaio/sys.c

1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 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 2.0 (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.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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.c7.1 (Berkeley) 6/5/86
55 */
56
57/* Copyright 2007 VMware Inc.
58 "Preboot" ramdisk support added by David Elliott
59 */
60
61#include <AvailabilityMacros.h>
62
63#include "libsaio.h"
64#include "bootstruct.h"
65#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
66# include <Kernel/libkern/crypto/md5.h>
67#else
68# include <sys/md5.h>
69#endif
70#include <uuid/uuid.h>
71#if 0 /* No OS X release has ever included this. */
72#include <Kernel/uuid/namespace.h>
73#else
74/* copied from uuid/namespace.h, just like BootX's fs.c does. */
75UUID_DEFINE( kFSUUIDNamespaceSHA1, 0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC );
76#endif
77
78extern int multiboot_partition;
79extern int multiboot_partition_set;
80
81struct devsw {
82 const char * name;
83 // size increased from char to short to handle non-BIOS internal devices
84 unsigned short biosdev;
85 int type;
86};
87
88static struct devsw devsw[] =
89{
90 { "sd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_SD */
91 { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */
92 { "fd", 0x00, kBIOSDevTypeFloppy }, /* DEV_FD */
93 { "en", 0xE0, kBIOSDevTypeNetwork }, /* DEV_EN */
94 { "rd", 0x100, kBIOSDevTypeHardDrive },
95 { "bt", 0x101, kBIOSDevTypeHardDrive }, // turbo - type for booter partition
96 { 0, 0 }
97};
98
99/*
100 * Max number of file descriptors.
101 */
102#define NFILES 6
103
104static struct iob iob[NFILES];
105
106void * gFSLoadAddress = 0;
107
108// Turbo - save what we think is our original BIOS boot volume if we have one 0xab
109BVRef gBIOSBootVolume = NULL;
110BVRef gBootVolume;
111
112// zef - ramdisk variables
113extern BVRef gRAMDiskVolume;
114extern bool gRAMDiskBTAliased;
115
116//static BVRef getBootVolumeRef( const char * path, const char ** outPath );
117static BVRef newBootVolumeRef( int biosdev, int partno );
118
119//==========================================================================
120// LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.
121// Load the specified file from the specified volume
122// to the load buffer at LOAD_ADDR.
123// If the file is fat, load only the i386 portion.
124
125long LoadVolumeFile(BVRef bvr, const char *filePath)
126{
127 long fileSize;
128
129 // Read file into load buffer. The data in the load buffer will be
130 // overwritten by the next LoadFile() call.
131
132 gFSLoadAddress = (void *) LOAD_ADDR;
133
134 fileSize = bvr->fs_loadfile(bvr, (char *)filePath);
135
136 // Return the size of the file, or -1 if load failed.
137
138 return fileSize;
139}
140
141//==========================================================================
142// LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.
143// Load the specified file to the load buffer at LOAD_ADDR.
144// If the file is fat, load only the i386 portion.
145
146long LoadFile(const char * fileSpec)
147{
148 const char * filePath;
149 BVRef bvr;
150
151 // Resolve the boot volume from the file spec.
152
153 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
154 return -1;
155
156 return LoadVolumeFile(bvr, filePath);
157}
158
159long ReadFileAtOffset(const char * fileSpec, void *buffer, uint64_t offset, uint64_t length)
160{
161 const char *filePath;
162 BVRef bvr;
163
164 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
165 return -1;
166
167 if (bvr->fs_readfile == NULL)
168 return -1;
169
170 return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);
171}
172
173long LoadThinFatFile(const char *fileSpec, void **binary)
174{
175 const char *filePath;
176 FSReadFile readFile;
177 BVRef bvr;
178 unsigned long length, length2;
179
180 // Resolve the boot volume from the file spec.
181
182 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)
183 return -1;
184
185 *binary = (void *)kLoadAddr;
186
187 // Read file into load buffer. The data in the load buffer will be
188 // overwritten by the next LoadFile() call.
189
190 gFSLoadAddress = (void *) LOAD_ADDR;
191
192 readFile = bvr->fs_readfile;
193
194 if (readFile != NULL) {
195 // Read the first 4096 bytes (fat header)
196 length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);
197 if (length > 0) {
198 if (ThinFatFile(binary, &length) == 0) {
199if (length == 0)
200return 0;
201 // We found a fat binary; read only the thin part
202 length = readFile(bvr, (char *)filePath,
203 (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);
204 *binary = (void *)kLoadAddr;
205 } else {
206 // Not a fat binary; read the rest of the file
207 length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);
208 if (length2 == -1) return -1;
209 length += length2;
210 }
211 }
212 } else {
213 length = bvr->fs_loadfile(bvr, (char *)filePath);
214 if (length > 0) {
215 ThinFatFile(binary, &length);
216 }
217 }
218
219 return length;
220}
221
222#if UNUSED
223long GetFSUUID(char *spec, char *uuidStr)
224{
225 BVRef bvr;
226 long rval = -1;
227 const char *devSpec;
228
229 if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)
230 return -1;
231
232 if(bvr->fs_getuuid)
233 rval = bvr->fs_getuuid(bvr, uuidStr);
234
235 return rval;
236}
237#endif
238
239// filesystem-specific getUUID functions call this shared string generator
240long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)
241{
242 unsigned fmtbase, fmtidx, i;
243 uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };
244 char *p = uuidStr;
245 MD5_CTX md5c;
246 uint8_t mdresult[16];
247
248 bzero(mdresult, sizeof(mdresult));
249
250 // just like AppleFileSystemDriver
251 MD5Init(&md5c);
252 MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));
253 MD5Update(&md5c, uubytes, nbytes);
254 MD5Final(mdresult, &md5c);
255
256 // this UUID has been made version 3 style (i.e. via namespace)
257 // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)
258 mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );
259 mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );
260
261
262 // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
263 i = 0; fmtbase = 0;
264 for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {
265 for(i=0; i < uuidfmt[fmtidx]; i++) {
266 uint8_t byte = mdresult[fmtbase+i];
267 char nib;
268
269 nib = byte >> 4;
270 *p = nib + '0'; // 0x4 -> '4'
271 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
272 p++;
273
274 nib = byte & 0xf;
275 *p = nib + '0'; // 0x4 -> '4'
276 if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'
277 p++;
278
279 }
280 fmtbase += i;
281 if(fmtidx < sizeof(uuidfmt)-1)
282 *(p++) = '-';
283 else
284 *p = '\0';
285 }
286
287 return 0;
288}
289
290
291//==========================================================================
292// GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.
293// Fetch the next directory entry for the given directory.
294
295long GetDirEntry(const char * dirSpec, long * dirIndex, const char ** name,
296 long * flags, long * time)
297{
298 const char * dirPath;
299 BVRef bvr;
300
301 // Resolve the boot volume from the dir spec.
302
303 if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)
304 return -1;
305
306 // Return 0 on success, or -1 if there are no additional entries.
307
308 return bvr->fs_getdirentry( bvr,
309 /* dirPath */ (char *)dirPath,
310 /* dirIndex */ dirIndex,
311 /* dirEntry */ (char **)name, flags, time, 0, 0 );
312}
313
314//==========================================================================
315// GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.
316// Get attributes for the specified file.
317
318static char* gMakeDirSpec;
319
320long GetFileInfo(const char * dirSpec, const char * name,
321 long * flags, long * time)
322{
323 long index = 0;
324 const char * entryName;
325
326 if (gMakeDirSpec == 0)
327 gMakeDirSpec = (char *)malloc(1024);
328
329 if (!dirSpec) {
330 long idx, len;
331
332 len = strlen(name);
333
334 for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}
335 if (idx == 0) {
336 gMakeDirSpec[0] = '/';
337 gMakeDirSpec[1] = '\0';
338 } else {
339 idx++;
340 strncpy(gMakeDirSpec, name, idx);
341 name += idx;
342 }
343 dirSpec = gMakeDirSpec;
344 }
345
346 while (GetDirEntry(dirSpec, &index, &entryName, flags, time) == 0)
347 {
348 if (strcmp(entryName, name) == 0)
349 return 0; // success
350 }
351 return -1; // file not found
352}
353
354long GetFileBlock(const char *fileSpec, unsigned long long *firstBlock)
355{
356 const char * filePath;
357 BVRef bvr;
358
359 // Resolve the boot volume from the file spec.
360
361 if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL) {
362 printf("Boot volume for '%s' is bogus\n", fileSpec);
363 return -1;
364 }
365
366 return bvr->fs_getfileblock(bvr, (char *)filePath, firstBlock);
367}
368
369//==========================================================================
370// iob_from_fdesc()
371//
372// Return a pointer to an allocated 'iob' based on the file descriptor
373// provided. Returns NULL if the file descriptor given is invalid.
374
375static struct iob * iob_from_fdesc(int fdesc)
376{
377 register struct iob * io;
378
379 if (fdesc < 0 || fdesc >= NFILES ||
380 ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0)
381 return NULL;
382 else
383 return io;
384}
385
386#if UNUSED
387//==========================================================================
388// openmem()
389
390int openmem(char * buf, int len)
391{
392 int fdesc;
393 struct iob * io;
394
395 // Locate a free descriptor slot.
396
397 for (fdesc = 0; fdesc < NFILES; fdesc++)
398 if (iob[fdesc].i_flgs == 0)
399 goto gotfile;
400
401 stop("Out of file descriptors");
402
403gotfile:
404 io = &iob[fdesc];
405 bzero(io, sizeof(*io));
406
407 // Mark the descriptor as taken. Set the F_MEM flag to indicate
408 // that the file buffer is provided by the caller.
409
410 io->i_flgs = F_ALLOC | F_MEM;
411 io->i_buf = buf;
412 io->i_filesize = len;
413
414 return fdesc;
415}
416#endif
417
418//==========================================================================
419// open() - Open the file specified by 'path' for reading.
420
421int open(const char * path, int flags)
422{
423 int fdesc, i;
424 struct iob * io;
425 const char * filePath;
426 BVRef bvr;
427
428 // Locate a free descriptor slot.
429
430 for (fdesc = 0; fdesc < NFILES; fdesc++)
431 if (iob[fdesc].i_flgs == 0)
432 goto gotfile;
433
434 stop("Out of file descriptors");
435
436gotfile:
437 io = &iob[fdesc];
438 bzero(io, sizeof(*io));
439
440 // Mark the descriptor as taken.
441
442 io->i_flgs = F_ALLOC;
443
444 // Resolve the boot volume from the file spec.
445
446 if ((bvr = getBootVolumeRef(path, &filePath)) == NULL)
447 goto error;
448
449 // Find the next available memory block in the download buffer.
450
451 io->i_buf = (char *) LOAD_ADDR;
452 for (i = 0; i < NFILES; i++)
453 {
454 if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) continue;
455 io->i_buf = max(iob[i].i_filesize + iob[i].i_buf, io->i_buf);
456 }
457
458 // Load entire file into memory. Unnecessary open() calls must
459 // be avoided.
460
461 gFSLoadAddress = io->i_buf;
462 io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);
463 if (io->i_filesize < 0) {
464goto error;
465 }
466
467 return fdesc;
468
469error:
470 close(fdesc);
471 return -1;
472}
473
474//==========================================================================
475// close() - Close a file descriptor.
476
477int close(int fdesc)
478{
479 struct iob * io;
480
481 if ((io = iob_from_fdesc(fdesc)) == NULL)
482 return (-1);
483
484 io->i_flgs = 0;
485
486 return 0;
487}
488
489//==========================================================================
490// lseek() - Reposition the byte offset of the file descriptor from the
491// beginning of the file. Returns the relocated offset.
492
493int b_lseek(int fdesc, int offset, int ptr)
494{
495 struct iob * io;
496
497 if ((io = iob_from_fdesc(fdesc)) == NULL)
498 return (-1);
499
500 io->i_offset = offset;
501
502 return offset;
503}
504
505//==========================================================================
506// tell() - Returns the byte offset of the file descriptor.
507
508int tell(int fdesc)
509{
510 struct iob * io;
511
512 if ((io = iob_from_fdesc(fdesc)) == NULL)
513 return 0;
514
515 return io->i_offset;
516}
517
518//==========================================================================
519// read() - Read up to 'count' bytes of data from the file descriptor
520// into the buffer pointed to by buf.
521
522int read(int fdesc, char * buf, int count)
523{
524 struct iob * io;
525
526 if ((io = iob_from_fdesc(fdesc)) == NULL)
527 return (-1);
528
529 if ((io->i_offset + count) > (unsigned int)io->i_filesize)
530 count = io->i_filesize - io->i_offset;
531
532 if (count <= 0)
533 return 0; // end of file
534
535 bcopy(io->i_buf + io->i_offset, buf, count);
536
537 io->i_offset += count;
538
539 return count;
540}
541
542//==========================================================================
543// file_size() - Returns the size of the file described by the file
544// descriptor.
545
546int file_size(int fdesc)
547{
548 struct iob * io;
549
550 if ((io = iob_from_fdesc(fdesc)) == 0)
551 return 0;
552
553 return io->i_filesize;
554}
555
556//==========================================================================
557
558struct dirstuff * vol_opendir(BVRef bvr, const char * path)
559{
560 struct dirstuff * dirp = 0;
561
562 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
563 if (dirp == NULL)
564 goto error;
565
566 dirp->dir_path = newString(path);
567 if (dirp->dir_path == NULL)
568 goto error;
569
570 dirp->dir_bvr = bvr;
571
572 return dirp;
573
574error:
575 closedir(dirp);
576 return NULL;
577}
578
579//==========================================================================
580
581struct dirstuff * opendir(const char * path)
582{
583 struct dirstuff * dirp = 0;
584 const char * dirPath;
585 BVRef bvr;
586
587 if ((bvr = getBootVolumeRef(path, &dirPath)) == NULL)
588 goto error;
589
590 dirp = (struct dirstuff *) malloc(sizeof(struct dirstuff));
591 if (dirp == NULL)
592 goto error;
593
594 dirp->dir_path = newString(dirPath);
595 if (dirp->dir_path == NULL)
596 goto error;
597
598 dirp->dir_bvr = bvr;
599
600 return dirp;
601
602error:
603 closedir(dirp);
604 return NULL;
605}
606
607//==========================================================================
608
609int closedir(struct dirstuff * dirp)
610{
611 if (dirp) {
612 if (dirp->dir_path) free(dirp->dir_path);
613 free(dirp);
614 }
615 return 0;
616}
617
618//==========================================================================
619
620int readdir(struct dirstuff * dirp, const char ** name, long * flags,
621 long * time)
622{
623 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
624 /* dirPath */ dirp->dir_path,
625 /* dirIndex */ &dirp->dir_index,
626 /* dirEntry */ (char **)name, flags, time,
627 0, 0);
628}
629
630//==========================================================================
631
632int readdir_ext(struct dirstuff * dirp, const char ** name, long * flags,
633 long * time, FinderInfo *finderInfo, long *infoValid)
634{
635 return dirp->dir_bvr->fs_getdirentry( dirp->dir_bvr,
636 /* dirPath */ dirp->dir_path,
637 /* dirIndex */ &dirp->dir_index,
638 /* dirEntry */ (char **)name,
639 flags, time,
640 finderInfo, infoValid);
641}
642
643//==========================================================================
644
645const char * systemConfigDir()
646{
647 if (gBootFileType == kNetworkDeviceType)
648return "";
649 return "/Library/Preferences/SystemConfiguration";
650}
651
652//==========================================================================
653
654int gBootFileType;
655
656void scanBootVolumes( int biosdev, int * count )
657{
658 BVRef bvr = 0;
659
660 bvr = diskScanBootVolumes(biosdev, count);
661 if (bvr == NULL)
662 {
663 bvr = nbpScanBootVolumes(biosdev, count);
664 if (bvr != NULL)
665 {
666 gBootFileType = kNetworkDeviceType;
667 }
668 }
669 else
670 {
671 gBootFileType = kBlockDeviceType;
672 }
673}
674
675//==========================================================================
676
677void scanDisks(int biosdev, int *count)
678{
679 #define MAX_HDD_COUNT 32
680 int bvCount;
681 int hd = 0;
682
683 // Testing up to MAX_HDD_COUNT hard drives.
684while(!testBiosread(0x80 + hd, 0) && hd < MAX_HDD_COUNT)
685{
686 bvCount = 0;
687 scanBootVolumes(0x80 + hd, &bvCount);
688 hd++;
689}
690
691 // Also scanning CD/DVD drive.
692if (biosDevIsCDROM(gBIOSDev))
693{
694 bvCount = 0;
695 scanBootVolumes(gBIOSDev, &bvCount);
696}
697}
698
699//==========================================================================
700
701BVRef selectBootVolume( BVRef chain )
702{
703 bool filteredChain = FALSE;
704 bool foundPrimary = FALSE;
705 BVRef bvr, bvr1 = 0, bvr2 = 0;
706
707if (chain->filtered) filteredChain = TRUE;
708
709if (multiboot_partition_set)
710for ( bvr = chain; bvr; bvr = bvr->next )
711if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
712return bvr;
713
714/*
715 * Checking "Default Partition" key in system configuration - use format: hd(x,y) -
716 * to override the default selection.
717 * We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
718 */
719 const char * val;
720 char testStr[64];
721 int cnt;
722
723 if (getValueForKey("Default Partition", &val, &cnt, &bootInfo->bootConfig) && cnt >= 7 && filteredChain)
724 {
725 for ( bvr = chain; bvr; bvr = bvr->next )
726 {
727 *testStr = '\0';
728 if ( bvr->biosdev >= 0x80 && bvr->biosdev < 0x100
729 && ( bvr->flags & ( kBVFlagSystemVolume|kBVFlagForeignBoot ) ) )
730 {
731 sprintf(testStr, "hd(%d,%d)", bvr->biosdev - 0x80, bvr->part_no);
732 if (strcmp(testStr, val) == 0)
733 return bvr;
734 }
735 }
736 }
737
738/*
739 * Scannig the volume chain backwards and trying to find
740 * a HFS+ volume with valid boot record signature.
741 * If not found any active partition then we will
742 * select this volume as the boot volume.
743 */
744 for ( bvr = chain; bvr; bvr = bvr->next )
745 {
746 if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = TRUE;
747 // zhell -- Undo a regression that was introduced from r491 to 492.
748 // if gBIOSBootVolume is set already, no change is required
749 if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)
750 && gBIOSBootVolume
751 && (!filteredChain || (filteredChain && bvr->visible))
752 && bvr->biosdev == gBIOSDev )
753 bvr2 = bvr;
754 // zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement
755 // from r491,
756 if ( bvr->flags & kBVFlagBootable
757 && ! gBIOSBootVolume
758 && bvr->biosdev == gBIOSDev )
759 bvr2 = bvr;
760 }
761
762
763/*
764 * Use the standrad method for selecting the boot volume.
765 */
766if (foundPrimary)
767{
768for ( bvr = chain; bvr; bvr = bvr->next )
769{
770if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;
771if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;
772}
773 }
774
775 bvr = bvr2 ? bvr2 :
776 bvr1 ? bvr1 : chain;
777
778 return bvr;
779}
780
781//==========================================================================
782
783#define LP '('
784#define RP ')'
785int gBIOSDev;
786
787/*!
788 This is like boot2's gBootVolume except it is for the internal use of
789 libsaio to track which volume an unqualified path should be relative to.
790 This replaces bootInfo->kernDev as the carrier of this information.
791 */
792static BVRef gRootVolume;
793
794void setRootVolume(BVRef volume)
795{
796 gRootVolume = volume;
797 // Veto non-native FS. Basically that means don't allow the root volume to
798 // be set to a volume we can't read files from.
799 if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))
800 gRootVolume = NULL;
801}
802
803void setBootGlobals(BVRef chain)
804{
805 // Record default boot device.
806 gBootVolume = selectBootVolume(chain);
807
808 // turbo - Save the ORIGINAL boot volume too for loading our mkext
809 if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;
810
811 setRootVolume(gBootVolume);
812}
813
814/*!
815 Extracts the volume selector from the pathname, returns the selected
816 BVRef, and sets *outPath to the remainder of the path.
817 If the path did not include a volume selector then the current volume
818 is used. When called with a volume selector the current volume
819 is changed to the selected volume unless the volume selector is
820 that of a ramdisk.
821 */
822BVRef getBootVolumeRef( const char * path, const char ** outPath )
823{
824 const char * cp;
825 BVRef bvr = gRootVolume;
826 int biosdev = gBIOSDev;
827
828 // Search for left parenthesis in the path specification.
829
830 for (cp = path; *cp; cp++) {
831 if (*cp == LP || *cp == '/') break;
832 }
833
834 if (*cp != LP) // no left paren found
835 {
836 // Path is using the implicit current device so if there is
837 // no current device, then we must fail.
838 cp = path;
839 if ( gRootVolume == NULL )
840 return NULL;
841 }
842 else if ((cp - path) == 2) // found "xx("
843 {
844 const struct devsw * dp;
845 const char * xp = path;
846 int i;
847 int unit = -1;
848 int part = -1;
849
850 cp++;
851
852 // Check the 2 character device name pointed by 'xp'.
853
854 for (dp = devsw; dp->name; dp++)
855 {
856 if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))
857 break; // found matching entry
858 }
859 if (dp->name == NULL)
860 {
861 error("Unknown device '%c%c'\n", xp[0], xp[1]);
862 return NULL;
863 }
864
865 // Extract the optional unit number from the specification.
866 // hd(unit) or hd(unit, part).
867
868 i = 0;
869 while (*cp >= '0' && *cp <= '9')
870 {
871 i = i * 10 + *cp++ - '0';
872 unit = i;
873 }
874
875 // Unit is no longer optional and never really was.
876 // If the user failed to specify it then the unit number from the previous kernDev
877 // would have been used which makes little sense anyway.
878 // For example, if the user did fd()/foobar and the current root device was the
879 // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!
880 if(unit == -1)
881 return NULL;
882
883 // Extract the optional partition number from the specification.
884
885 if (*cp == ',')
886 part = atoi(++cp);
887
888 // If part is not specified part will be -1 whereas before it would have been
889 // whatever the last partition was which makes about zero sense if the device
890 // has been switched.
891
892 // Skip past the right paren.
893
894 for ( ; *cp && *cp != RP; cp++) /* LOOP */;
895 if (*cp == RP) cp++;
896
897 biosdev = dp->biosdev + unit;
898
899 // turbo - bt(0,0) hook
900 if (biosdev == 0x101)
901 {
902 // zef - use the ramdisk if available and the alias is active.
903 if (gRAMDiskVolume != NULL && gRAMDiskBTAliased == 1)
904 bvr = gRAMDiskVolume;
905 else
906 bvr = gBIOSBootVolume;
907 }
908 else
909 {
910 bvr = newBootVolumeRef(biosdev, part);
911 }
912
913 if(bvr == NULL)
914 return NULL;
915 }
916 else
917 {
918 // Bad device specifier, skip past the right paren.
919
920 for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;
921 if (*cp == RP) cp++;
922 // If gRootVolume was NULL, then bvr will be NULL as well which
923 // should be caught by the caller.
924 }
925
926 // Returns the file path following the device spec.
927 // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.
928
929 *outPath = cp;
930
931 return bvr;
932}
933
934//==========================================================================
935
936// Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes
937// which caches the information. So it's only allocated on the first run.
938static BVRef newBootVolumeRef( int biosdev, int partno )
939{
940 BVRef bvr, bvr1, bvrChain;
941
942 // Fetch the volume list from the device.
943
944 scanBootVolumes( biosdev, NULL );
945 bvrChain = getBVChainForBIOSDev(biosdev);
946
947 // Look for a perfect match based on device and partition number.
948
949 for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )
950 {
951 if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;
952
953 bvr1 = bvr;
954 if ( bvr->part_no == partno ) break;
955 }
956
957 return bvr ? bvr : bvr1;
958}
959

Archive Download this file

Revision: 120