Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2531