Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 182