Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 665