Root/
Source at commit 1808 created 12 years 3 months ago. By blackosx, Revise layout of package installer 'Welcome' file so it looks cleaner. Change the copyright notice to begin from 2009 as seen in the Chameleon 2.0 r431 installer. Should this date be set earlier? | |
---|---|
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.c␉7.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 | ␊ |
69 | #include <libkern/crypto/md5.h>␊ |
70 | //#include <uuid/uuid.h>␊ |
71 | ␊ |
72 | #if 0 /* No OS X release has ever included this. */␊ |
73 | #include <Kernel/uuid/namespace.h>␊ |
74 | #else␊ |
75 | // from our uuid/namespace.h (UFS and HFS uuids can live in the same space?)␊ |
76 | static unsigned char kFSUUIDNamespaceSHA1[] = {0xB3,0xE2,0x0F,0x39,0xF2,0x92,0x11,0xD6,0x97,0xA4,0x00,0x30,0x65,0x43,0xEC,0xAC};␊ |
77 | #endif␊ |
78 | ␊ |
79 | extern int multiboot_partition;␊ |
80 | extern int multiboot_partition_set;␊ |
81 | extern int multiboot_skip_partition;␊ |
82 | extern int multiboot_skip_partition_set;␊ |
83 | ␊ |
84 | struct devsw {␊ |
85 | const char * name;␊ |
86 | // size increased from char to short to handle non-BIOS internal devices␊ |
87 | unsigned short biosdev;␊ |
88 | int type;␊ |
89 | };␊ |
90 | ␊ |
91 | // Device entries must be ordered by bios device numbers. ␊ |
92 | static struct devsw devsw[] =␊ |
93 | {␊ |
94 | { "hd", 0x80, kBIOSDevTypeHardDrive }, /* DEV_HD */␊ |
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 | // Pseudo BIOS devices␊ |
102 | enum {␊ |
103 | ␉kPseudoBIOSDevRAMDisk = 0x100,␊ |
104 | ␉kPseudoBIOSDevBooter = 0x101␊ |
105 | };␊ |
106 | ␊ |
107 | /*␊ |
108 | * Max number of file descriptors.␊ |
109 | */␊ |
110 | #define NFILES 6␊ |
111 | ␊ |
112 | static struct iob iob[NFILES];␊ |
113 | ␊ |
114 | void * gFSLoadAddress = 0;␊ |
115 | ␊ |
116 | // Turbo - save what we think is our original BIOS boot volume if we have one 0xab␊ |
117 | BVRef gBIOSBootVolume = NULL;␊ |
118 | BVRef gBootVolume;␊ |
119 | ␊ |
120 | //static BVRef getBootVolumeRef( const char * path, const char ** outPath );␊ |
121 | static BVRef newBootVolumeRef( int biosdev, int partno );␊ |
122 | ␊ |
123 | //==========================================================================␊ |
124 | // LoadVolumeFile - LOW-LEVEL FILESYSTEM FUNCTION.␊ |
125 | // Load the specified file from the specified volume␊ |
126 | // to the load buffer at LOAD_ADDR.␊ |
127 | // If the file is fat, load only the i386 portion.␊ |
128 | ␊ |
129 | long LoadVolumeFile(BVRef bvr, const char *filePath)␊ |
130 | {␊ |
131 | long fileSize;␊ |
132 | ␊ |
133 | // Read file into load buffer. The data in the load buffer will be␊ |
134 | // overwritten by the next LoadFile() call.␊ |
135 | ␊ |
136 | gFSLoadAddress = (void *) LOAD_ADDR;␊ |
137 | ␊ |
138 | fileSize = bvr->fs_loadfile(bvr, (char *)filePath);␊ |
139 | ␊ |
140 | // Return the size of the file, or -1 if load failed.␊ |
141 | ␊ |
142 | return fileSize;␊ |
143 | }␊ |
144 | ␊ |
145 | //==========================================================================␊ |
146 | // LoadFile - LOW-LEVEL FILESYSTEM FUNCTION.␊ |
147 | // Load the specified file to the load buffer at LOAD_ADDR.␊ |
148 | // If the file is fat, load only the i386 portion.␊ |
149 | ␊ |
150 | long LoadFile(const char * fileSpec)␊ |
151 | {␊ |
152 | const char * filePath;␊ |
153 | BVRef bvr;␊ |
154 | ␊ |
155 | // Resolve the boot volume from the file spec.␊ |
156 | ␊ |
157 | if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)␊ |
158 | return -1;␊ |
159 | ␊ |
160 | return LoadVolumeFile(bvr, filePath);␊ |
161 | }␊ |
162 | ␊ |
163 | long ReadFileAtOffset(const char * fileSpec, void *buffer, uint64_t offset, uint64_t length)␊ |
164 | {␊ |
165 | const char *filePath;␊ |
166 | BVRef bvr;␊ |
167 | ␊ |
168 | if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)␊ |
169 | return -1;␊ |
170 | ␊ |
171 | if (bvr->fs_readfile == NULL)␊ |
172 | return -1;␊ |
173 | ␊ |
174 | return bvr->fs_readfile(bvr, (char *)filePath, buffer, offset, length);␊ |
175 | }␊ |
176 | ␊ |
177 | long LoadThinFatFile(const char *fileSpec, void **binary)␊ |
178 | {␊ |
179 | const char *filePath;␊ |
180 | FSReadFile readFile;␊ |
181 | BVRef bvr;␊ |
182 | unsigned long length, length2;␊ |
183 | ␊ |
184 | // Resolve the boot volume from the file spec.␊ |
185 | ␊ |
186 | if ((bvr = getBootVolumeRef(fileSpec, &filePath)) == NULL)␊ |
187 | return -1;␊ |
188 | ␊ |
189 | *binary = (void *)kLoadAddr;␊ |
190 | ␊ |
191 | // Read file into load buffer. The data in the load buffer will be␊ |
192 | // overwritten by the next LoadFile() call.␊ |
193 | ␊ |
194 | gFSLoadAddress = (void *) LOAD_ADDR;␊ |
195 | ␊ |
196 | readFile = bvr->fs_readfile;␊ |
197 | ␊ |
198 | if (readFile != NULL) {␊ |
199 | // Read the first 4096 bytes (fat header)␊ |
200 | length = readFile(bvr, (char *)filePath, *binary, 0, 0x1000);␊ |
201 | if (length > 0) {␊ |
202 | if (ThinFatFile(binary, &length) == 0) {␊ |
203 | ␉␉␉␉if (length == 0)␊ |
204 | ␉␉␉␉␉return 0;␊ |
205 | // We found a fat binary; read only the thin part␊ |
206 | length = readFile(bvr, (char *)filePath,␊ |
207 | (void *)kLoadAddr, (unsigned long)(*binary) - kLoadAddr, length);␊ |
208 | *binary = (void *)kLoadAddr;␊ |
209 | } else {␊ |
210 | // Not a fat binary; read the rest of the file␊ |
211 | length2 = readFile(bvr, (char *)filePath, (void *)(kLoadAddr + length), length, 0);␊ |
212 | if (length2 == -1) return -1;␊ |
213 | length += length2;␊ |
214 | }␊ |
215 | }␊ |
216 | } else {␊ |
217 | length = bvr->fs_loadfile(bvr, (char *)filePath);␊ |
218 | if (length > 0) {␊ |
219 | ThinFatFile(binary, &length);␊ |
220 | }␊ |
221 | }␊ |
222 | ␊ |
223 | return length;␊ |
224 | }␊ |
225 | ␊ |
226 | #if UNUSED␊ |
227 | long GetFSUUID(char *spec, char *uuidStr)␊ |
228 | {␊ |
229 | BVRef bvr;␊ |
230 | long rval = -1;␊ |
231 | const char *devSpec;␊ |
232 | ␊ |
233 | if ((bvr = getBootVolumeRef(spec, &devSpec)) == NULL)␊ |
234 | return -1;␊ |
235 | ␊ |
236 | if(bvr->fs_getuuid)␊ |
237 | rval = bvr->fs_getuuid(bvr, uuidStr);␊ |
238 | ␊ |
239 | return rval;␊ |
240 | }␊ |
241 | #endif␊ |
242 | ␊ |
243 | // filesystem-specific getUUID functions call this shared string generator␊ |
244 | long CreateUUIDString(uint8_t uubytes[], int nbytes, char *uuidStr)␊ |
245 | {␊ |
246 | unsigned fmtbase, fmtidx, i;␊ |
247 | uint8_t uuidfmt[] = { 4, 2, 2, 2, 6 };␊ |
248 | char *p = uuidStr;␊ |
249 | MD5_CTX md5c;␊ |
250 | uint8_t mdresult[16];␊ |
251 | ␊ |
252 | bzero(mdresult, sizeof(mdresult));␊ |
253 | ␊ |
254 | // just like AppleFileSystemDriver␊ |
255 | MD5Init(&md5c);␊ |
256 | MD5Update(&md5c, kFSUUIDNamespaceSHA1, sizeof(kFSUUIDNamespaceSHA1));␊ |
257 | MD5Update(&md5c, uubytes, nbytes);␊ |
258 | MD5Final(mdresult, &md5c);␊ |
259 | ␊ |
260 | // this UUID has been made version 3 style (i.e. via namespace)␊ |
261 | // see "-uuid-urn-" IETF draft (which otherwise copies byte for byte)␊ |
262 | mdresult[6] = 0x30 | ( mdresult[6] & 0x0F );␊ |
263 | mdresult[8] = 0x80 | ( mdresult[8] & 0x3F );␊ |
264 | ␊ |
265 | ␊ |
266 | // generate the text: e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292␊ |
267 | i = 0; fmtbase = 0;␊ |
268 | for(fmtidx = 0; fmtidx < sizeof(uuidfmt); fmtidx++) {␊ |
269 | for(i=0; i < uuidfmt[fmtidx]; i++) {␊ |
270 | uint8_t byte = mdresult[fmtbase+i];␊ |
271 | char nib;␊ |
272 | ␊ |
273 | nib = byte >> 4;␊ |
274 | *p = nib + '0'; // 0x4 -> '4'␊ |
275 | if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'␊ |
276 | p++;␊ |
277 | ␊ |
278 | nib = byte & 0xf;␊ |
279 | *p = nib + '0'; // 0x4 -> '4'␊ |
280 | if(*p > '9') *p = (nib - 9 + ('A'-1)); // 0xB -> 'B'␊ |
281 | p++;␊ |
282 | ␊ |
283 | }␊ |
284 | fmtbase += i;␊ |
285 | if(fmtidx < sizeof(uuidfmt)-1)␊ |
286 | *(p++) = '-';␊ |
287 | else␊ |
288 | *p = '\0';␊ |
289 | }␊ |
290 | ␊ |
291 | return 0;␊ |
292 | }␊ |
293 | ␊ |
294 | ␊ |
295 | //==========================================================================␊ |
296 | // GetDirEntry - LOW-LEVEL FILESYSTEM FUNCTION.␊ |
297 | // Fetch the next directory entry for the given directory.␊ |
298 | ␊ |
299 | long GetDirEntry(const char * dirSpec, long long * dirIndex, const char ** name, ␊ |
300 | long * flags, long * time)␊ |
301 | {␊ |
302 | const char * dirPath;␊ |
303 | BVRef bvr;␊ |
304 | ␊ |
305 | // Resolve the boot volume from the dir spec.␊ |
306 | ␊ |
307 | if ((bvr = getBootVolumeRef(dirSpec, &dirPath)) == NULL)␊ |
308 | return -1;␊ |
309 | ␊ |
310 | // Return 0 on success, or -1 if there are no additional entries.␊ |
311 | ␊ |
312 | return bvr->fs_getdirentry( bvr,␊ |
313 | /* dirPath */ (char *)dirPath,␊ |
314 | /* dirIndex */ dirIndex,␊ |
315 | /* dirEntry */ (char **)name, flags, time, 0, 0 );␊ |
316 | }␊ |
317 | ␊ |
318 | //==========================================================================␊ |
319 | // GetFileInfo - LOW-LEVEL FILESYSTEM FUNCTION.␊ |
320 | // Get attributes for the specified file.␊ |
321 | ␊ |
322 | static char* gMakeDirSpec;␊ |
323 | ␊ |
324 | long GetFileInfo(const char * dirSpec, const char * name,␊ |
325 | long * flags, long * time)␊ |
326 | {␊ |
327 | long long index = 0;␊ |
328 | const char * entryName;␊ |
329 | ␊ |
330 | if (gMakeDirSpec == 0)␊ |
331 | gMakeDirSpec = (char *)malloc(1024);␊ |
332 | ␊ |
333 | if (!dirSpec) {␊ |
334 | long idx, len;␊ |
335 | ␊ |
336 | len = strlen(name);␊ |
337 | ␊ |
338 | for (idx = len; idx && (name[idx] != '/' && name[idx] != '\\'); idx--) {}␊ |
339 | if (idx == 0) {␊ |
340 | if(name[idx] == '/' || name[idx] == '\\') ++name; // todo: ensure other functions handel \ properly␊ |
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 | ␊ |
359 | long 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 | ␊ |
377 | static int GetFreeFd(void)␊ |
378 | {␊ |
379 | ␉int␉fd;␊ |
380 | ␊ |
381 | ␉// Locate a free descriptor slot.␊ |
382 | ␉for (fd = 0; fd < NFILES; fd++) {␊ |
383 | ␉␉if (iob[fd].i_flgs == 0) {␊ |
384 | ␉␉␉return fd;␊ |
385 | ␉ ␉}␊ |
386 | ␉}␊ |
387 | ␉stop("Out of file descriptors");␊ |
388 | ␉// not reached␊ |
389 | ␉return -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 | ␊ |
398 | static 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 | ␊ |
412 | int 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 | ␊ |
434 | static int open_bvr(BVRef bvr, const char *filePath, int flags)␊ |
435 | {␊ |
436 | ␉struct iob␉*io;␊ |
437 | ␉int␉␉fdesc;␊ |
438 | ␉int␉␉i;␊ |
439 | ␊ |
440 | ␉if (bvr == NULL) {␊ |
441 | ␉␉return -1;␊ |
442 | ␉}␊ |
443 | ␊ |
444 | ␉fdesc = GetFreeFd();␊ |
445 | ␉io = &iob[fdesc];␊ |
446 | ␉bzero(io, sizeof(*io));␊ |
447 | ␊ |
448 | ␉// Mark the descriptor as taken.␊ |
449 | ␉io->i_flgs = F_ALLOC;␊ |
450 | ␊ |
451 | ␉// Find the next available memory block in the download buffer.␊ |
452 | ␉io->i_buf = (char *) LOAD_ADDR;␊ |
453 | ␉for (i = 0; i < NFILES; i++) {␊ |
454 | ␉␉if ((iob[i].i_flgs != F_ALLOC) || (i == fdesc)) {␊ |
455 | ␉␉␉continue;␊ |
456 | ␉␉}␊ |
457 | ␉␉io->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.␊ |
461 | ␉gFSLoadAddress = io->i_buf;␊ |
462 | ␉io->i_filesize = bvr->fs_loadfile(bvr, (char *)filePath);␊ |
463 | ␉if (io->i_filesize < 0) {␊ |
464 | ␉␉close(fdesc);␊ |
465 | ␉␉return -1;␊ |
466 | ␉}␊ |
467 | ␉return fdesc;␊ |
468 | }␊ |
469 | ␊ |
470 | int open(const char *path, int flags)␊ |
471 | {␊ |
472 | ␉const char␉*filepath;␊ |
473 | ␉BVRef␉␉bvr;␊ |
474 | ␊ |
475 | ␉// Resolve the boot volume from the file spec.␊ |
476 | ␉if ((bvr = getBootVolumeRef(path, &filepath)) != NULL) {␊ |
477 | ␉␉return open_bvr(bvr, filepath, flags);␊ |
478 | ␉}␊ |
479 | ␉return -1;␊ |
480 | }␊ |
481 | ␊ |
482 | int open_bvdev(const char *bvd, const char *path, int flags)␊ |
483 | {␊ |
484 | const struct devsw␉*dp;␊ |
485 | ␉const char␉␉␉*cp;␊ |
486 | ␉BVRef␉␉␉␉bvr;␊ |
487 | ␉int␉␉␉␉␉i;␊ |
488 | ␉int␉␉␉␉␉len;␊ |
489 | ␉int␉␉␉␉␉unit;␊ |
490 | ␉int␉␉␉␉␉partition;␊ |
491 | ␊ |
492 | ␉if ((i = open(path, flags)) >= 0) {␊ |
493 | ␉␉return i;␊ |
494 | ␉}␊ |
495 | ␊ |
496 | ␉if (bvd == NULL || (len = strlen(bvd)) < 2) {␊ |
497 | ␉␉return -1;␊ |
498 | ␉}␊ |
499 | ␊ |
500 | ␉for (dp=devsw; dp->name; dp++) {␊ |
501 | ␉␉if (bvd[0] == dp->name[0] && bvd[1] == dp->name[1]) {␊ |
502 | ␉␉␉unit = 0;␊ |
503 | ␉␉␉partition = 0;␊ |
504 | ␉␉␉/* get optional unit and partition */␊ |
505 | ␉␉␉if (len >= 5 && bvd[2] == '(') { /* min must be present xx(0) */␊ |
506 | ␉␉␉␉cp = &bvd[3];␊ |
507 | ␉␉␉␉i = 0;␊ |
508 | ␉␉␉␉while ((cp - path) < len && isdigit(*cp)) {␊ |
509 | ␉␉␉␉␉i = i * 10 + *cp++ - '0';␊ |
510 | ␉␉␉␉␉unit = i;␊ |
511 | ␉␉␉␉}␊ |
512 | ␉␉␉␉if (*cp++ == ',') {␊ |
513 | ␉␉␉␉␉i = 0;␊ |
514 | ␉␉␉␉␉while ((cp - path) < len && isdigit(*cp)) {␊ |
515 | ␉␉␉␉␉␉i = i * 10 + *cp++ - '0';␊ |
516 | ␉␉␉␉␉␉partition = i;␊ |
517 | ␉␉␉␉␉}␊ |
518 | ␉␉␉␉}␊ |
519 | ␉␉␉}␊ |
520 | ␉␉␉bvr = newBootVolumeRef(dp->biosdev + unit, partition);␊ |
521 | ␉␉␉return open_bvr(bvr, path, flags);␊ |
522 | ␉␉}␊ |
523 | }␊ |
524 | ␉return -1;␊ |
525 | }␊ |
526 | ␊ |
527 | //==========================================================================␊ |
528 | // close() - Close a file descriptor.␊ |
529 | ␊ |
530 | int 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 | ␊ |
546 | int 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 | ␊ |
561 | int 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 | ␊ |
575 | int 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 | ␊ |
599 | int 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 | ␊ |
619 | int 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 | ␊ |
634 | int 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 | ␊ |
655 | int 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 | ␊ |
667 | struct 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 | ␊ |
683 | error:␊ |
684 | closedir(dirp);␊ |
685 | return NULL;␊ |
686 | }␊ |
687 | ␊ |
688 | //==========================================================================␊ |
689 | ␊ |
690 | struct 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 | ␊ |
711 | error:␊ |
712 | closedir(dirp);␊ |
713 | return NULL;␊ |
714 | }␊ |
715 | ␊ |
716 | //==========================================================================␊ |
717 | ␊ |
718 | int 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 | ␊ |
729 | int 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 | ␊ |
741 | int 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 | ␊ |
754 | const char * systemConfigDir()␊ |
755 | {␊ |
756 | if (gBootFileType == kNetworkDeviceType)␊ |
757 | ␉return "";␊ |
758 | return "/Library/Preferences/SystemConfiguration";␊ |
759 | }␊ |
760 | ␊ |
761 | //==========================================================================␊ |
762 | ␊ |
763 | int gBootFileType;␊ |
764 | ␊ |
765 | void 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 | ␊ |
786 | void 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.␊ |
793 | ␉while(!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.␊ |
801 | ␉if (biosDevIsCDROM(gBIOSDev))␊ |
802 | ␉{␊ |
803 | ␉ bvCount = 0;␊ |
804 | ␉scanBootVolumes(gBIOSDev, &bvCount);␊ |
805 | ␉}␊ |
806 | }␊ |
807 | ␊ |
808 | //==========================================================================␊ |
809 | ␊ |
810 | BVRef selectBootVolume( BVRef chain )␊ |
811 | {␊ |
812 | ␉bool filteredChain = false;␊ |
813 | ␉bool foundPrimary = false;␊ |
814 | ␉BVRef bvr, bvr1 = 0, bvr2 = 0;␊ |
815 | ␉␊ |
816 | ␉if (chain->filtered) filteredChain = true;␊ |
817 | ␉␊ |
818 | ␉if (multiboot_partition_set)␊ |
819 | ␉␉for ( bvr = chain; bvr; bvr = bvr->next )␊ |
820 | ␉␉␉if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev ) ␊ |
821 | ␉␉␉␉return 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 | ␉ */␊ |
828 | ␉char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->chameleonConfig));␊ |
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 | ␉ */␊ |
845 | ␉for ( bvr = chain; bvr; bvr = bvr->next )␊ |
846 | ␉{␊ |
847 | if (multiboot_skip_partition_set) {␊ |
848 | if (bvr->part_no == multiboot_skip_partition) continue;␊ |
849 | }␊ |
850 | ␉␉if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) foundPrimary = true;␊ |
851 | ␉␉// zhell -- Undo a regression that was introduced from r491 to 492.␊ |
852 | ␉␉// if gBIOSBootVolume is set already, no change is required␊ |
853 | ␉␉if ( bvr->flags & (kBVFlagBootable|kBVFlagSystemVolume)␊ |
854 | ␉␉␉&& gBIOSBootVolume␊ |
855 | ␉␉␉&& (!filteredChain || (filteredChain && bvr->visible))␊ |
856 | ␉␉␉&& bvr->biosdev == gBIOSDev )␊ |
857 | ␉␉␉bvr2 = bvr;␊ |
858 | ␉␉// zhell -- if gBIOSBootVolume is NOT set, we use the "if" statement␊ |
859 | ␉␉// from r491,␊ |
860 | ␉␉if ( bvr->flags & kBVFlagBootable␊ |
861 | ␉␉␉&& ! gBIOSBootVolume␊ |
862 | ␉␉␉&& bvr->biosdev == gBIOSDev )␊ |
863 | ␉␉␉bvr2 = bvr;␊ |
864 | ␉} ␊ |
865 | ␉␊ |
866 | ␉␊ |
867 | ␉/*␊ |
868 | ␉ * Use the standrad method for selecting the boot volume.␊ |
869 | ␉ */␊ |
870 | ␉if (foundPrimary)␊ |
871 | ␉{␊ |
872 | ␉␉for ( bvr = chain; bvr; bvr = bvr->next )␊ |
873 | ␉␉{␊ |
874 | ␉␉␉if ( bvr->flags & kBVFlagNativeBoot && bvr->biosdev == gBIOSDev ) bvr1 = bvr;␊ |
875 | ␉␉␉if ( bvr->flags & kBVFlagPrimary && bvr->biosdev == gBIOSDev ) bvr2 = bvr;␊ |
876 | ␉␉}␊ |
877 | ␉}␊ |
878 | ␉␊ |
879 | ␉bvr = bvr2 ? bvr2 :␊ |
880 | ␉bvr1 ? bvr1 : chain;␊ |
881 | ␉␊ |
882 | ␉return bvr;␊ |
883 | }␊ |
884 | ␊ |
885 | //==========================================================================␊ |
886 | ␊ |
887 | #define LP '('␊ |
888 | #define RP ')'␊ |
889 | int gBIOSDev;␊ |
890 | ␊ |
891 | /*!␊ |
892 | This is like boot2's gBootVolume except it is for the internal use of␊ |
893 | libsaio to track which volume an unqualified path should be relative to.␊ |
894 | This replaces bootInfo->kernDev as the carrier of this information.␊ |
895 | */␊ |
896 | static BVRef gRootVolume;␊ |
897 | ␊ |
898 | void setRootVolume(BVRef volume)␊ |
899 | {␊ |
900 | gRootVolume = volume;␊ |
901 | // Veto non-native FS. Basically that means don't allow the root volume to␊ |
902 | // be set to a volume we can't read files from.␊ |
903 | if(gRootVolume != NULL && ((gRootVolume->flags & kBVFlagNativeBoot) == 0))␊ |
904 | gRootVolume = NULL;␊ |
905 | }␊ |
906 | ␊ |
907 | void setBootGlobals(BVRef chain)␊ |
908 | {␊ |
909 | // Record default boot device.␊ |
910 | gBootVolume = selectBootVolume(chain);␊ |
911 | ␊ |
912 | // turbo - Save the ORIGINAL boot volume too for loading our mkext␊ |
913 | if (!gBIOSBootVolume) gBIOSBootVolume = gBootVolume;␊ |
914 | ␊ |
915 | setRootVolume(gBootVolume);␉␊ |
916 | }␊ |
917 | ␊ |
918 | /*!␊ |
919 | Extracts the volume selector from the pathname, returns the selected␊ |
920 | BVRef, and sets *outPath to the remainder of the path.␊ |
921 | If the path did not include a volume selector then the current volume␊ |
922 | is used. When called with a volume selector the current volume␊ |
923 | is changed to the selected volume unless the volume selector is␊ |
924 | that of a ramdisk.␊ |
925 | */␊ |
926 | BVRef getBootVolumeRef( const char * path, const char ** outPath )␊ |
927 | {␊ |
928 | const char * cp;␊ |
929 | BVRef bvr = gRootVolume;␊ |
930 | int biosdev = gBIOSDev;␊ |
931 | ␊ |
932 | // Search for left parenthesis in the path specification.␊ |
933 | ␊ |
934 | for (cp = path; *cp; cp++) {␊ |
935 | if (*cp == LP || *cp == '/') break;␊ |
936 | }␊ |
937 | ␊ |
938 | if (*cp != LP) // no left paren found␊ |
939 | {␊ |
940 | // Path is using the implicit current device so if there is␊ |
941 | // no current device, then we must fail.␊ |
942 | cp = path;␊ |
943 | if ( gRootVolume == NULL )␊ |
944 | return NULL;␊ |
945 | }␊ |
946 | else if ((cp - path) == 2) // found "xx("␊ |
947 | {␊ |
948 | const struct devsw * dp;␊ |
949 | const char * xp = path;␊ |
950 | int i;␊ |
951 | int unit = -1;␊ |
952 | int part = -1;␊ |
953 | ␊ |
954 | cp++;␊ |
955 | ␊ |
956 | // Check the 2 character device name pointed by 'xp'.␊ |
957 | ␊ |
958 | for (dp = devsw; dp->name; dp++)␊ |
959 | {␊ |
960 | if ((xp[0] == dp->name[0]) && (xp[1] == dp->name[1]))␊ |
961 | break; // found matching entry␊ |
962 | }␊ |
963 | if (dp->name == NULL)␊ |
964 | {␊ |
965 | error("Unknown device '%c%c'\n", xp[0], xp[1]);␊ |
966 | return NULL;␊ |
967 | }␊ |
968 | ␊ |
969 | // Extract the optional unit number from the specification.␊ |
970 | // hd(unit) or hd(unit, part).␊ |
971 | ␊ |
972 | i = 0;␊ |
973 | while (*cp >= '0' && *cp <= '9')␊ |
974 | {␊ |
975 | i = i * 10 + *cp++ - '0';␊ |
976 | unit = i;␊ |
977 | }␊ |
978 | ␊ |
979 | // Unit is no longer optional and never really was.␊ |
980 | // If the user failed to specify it then the unit number from the previous kernDev␊ |
981 | // would have been used which makes little sense anyway.␊ |
982 | // For example, if the user did fd()/foobar and the current root device was the␊ |
983 | // second hard disk (i.e. unit 1) then fd() would select the second floppy drive!␊ |
984 | if(unit == -1)␊ |
985 | return NULL;␊ |
986 | ␊ |
987 | // Extract the optional partition number from the specification.␊ |
988 | ␊ |
989 | if (*cp == ',')␊ |
990 | part = atoi(++cp);␊ |
991 | ␊ |
992 | // If part is not specified part will be -1 whereas before it would have been␊ |
993 | // whatever the last partition was which makes about zero sense if the device␊ |
994 | // has been switched.␊ |
995 | ␊ |
996 | // Skip past the right paren.␊ |
997 | ␊ |
998 | for ( ; *cp && *cp != RP; cp++) /* LOOP */;␊ |
999 | if (*cp == RP) cp++;␊ |
1000 | ␊ |
1001 | biosdev = dp->biosdev + unit;␊ |
1002 | bvr = newBootVolumeRef(biosdev, part);␊ |
1003 | ␊ |
1004 | if(bvr == NULL)␊ |
1005 | return NULL;␊ |
1006 | }␊ |
1007 | else␊ |
1008 | {␊ |
1009 | // Bad device specifier, skip past the right paren.␊ |
1010 | ␊ |
1011 | for ( cp++; *cp && *cp != RP; cp++) /* LOOP */;␊ |
1012 | if (*cp == RP) cp++;␊ |
1013 | // If gRootVolume was NULL, then bvr will be NULL as well which␊ |
1014 | // should be caught by the caller.␊ |
1015 | }␊ |
1016 | ␊ |
1017 | // Returns the file path following the device spec.␊ |
1018 | // e.g. 'hd(1,b)mach_kernel' is reduced to 'mach_kernel'.␊ |
1019 | ␊ |
1020 | *outPath = cp;␊ |
1021 | ␊ |
1022 | return bvr;␊ |
1023 | }␊ |
1024 | ␊ |
1025 | //==========================================================================␊ |
1026 | // Function name is a misnomer as scanBootVolumes usually calls diskScanBootVolumes␊ |
1027 | // which caches the information. So it's only allocated on the first run.␊ |
1028 | static BVRef newBootVolumeRef( int biosdev, int partno )␊ |
1029 | {␊ |
1030 | ␉BVRef bvr, bvr1, bvrChain;␊ |
1031 | ␊ |
1032 | ␉bvr = bvr1 = NULL;␊ |
1033 | ␊ |
1034 | // Try resolving "rd" and "bt" devices first.␊ |
1035 | ␉if (biosdev == kPseudoBIOSDevRAMDisk)␊ |
1036 | ␉{␊ |
1037 | ␉␉if (gRAMDiskVolume)␊ |
1038 | ␉␉ bvr1 = gRAMDiskVolume;␊ |
1039 | ␉}␊ |
1040 | ␉else if (biosdev == kPseudoBIOSDevBooter)␊ |
1041 | ␉{␊ |
1042 | ␉␉if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)␊ |
1043 | ␉␉␉bvr1 = gRAMDiskVolume;␊ |
1044 | ␉␉else␊ |
1045 | ␉␉␉bvr1 = gBIOSBootVolume;␊ |
1046 | ␉}␊ |
1047 | ␉else␊ |
1048 | ␉{␊ |
1049 | ␉␉// Fetch the volume list from the device.␊ |
1050 | ␊ |
1051 | ␉␉scanBootVolumes( biosdev, NULL );␊ |
1052 | ␉␉bvrChain = getBVChainForBIOSDev(biosdev);␊ |
1053 | ␊ |
1054 | ␉␉// Look for a perfect match based on device and partition number.␊ |
1055 | ␊ |
1056 | ␉␉for ( bvr1 = NULL, bvr = bvrChain; bvr; bvr = bvr->next )␊ |
1057 | ␉␉{␊ |
1058 | ␉␉␉if ( ( bvr->flags & kBVFlagNativeBoot ) == 0 ) continue;␊ |
1059 | ␊ |
1060 | ␉␉␉bvr1 = bvr;␊ |
1061 | ␉␉␉if ( bvr->part_no == partno ) break;␊ |
1062 | ␉␉}␊ |
1063 | ␉}␊ |
1064 | ␊ |
1065 | ␉return bvr ? bvr : bvr1;␊ |
1066 | }␊ |
1067 | ␊ |
1068 | //==========================================================================␊ |
1069 | // getDeviceDescription() - Extracts unit number and partition number␊ |
1070 | // from bvr structure into "dw(u,p)" format.␊ |
1071 | // Returns length of the out string␊ |
1072 | int getDeviceDescription(BVRef bvr, char *str)␊ |
1073 | {␊ |
1074 | if(!str)␊ |
1075 | return 0;␊ |
1076 | ␊ |
1077 | ␉*str = '\0';␊ |
1078 | ␊ |
1079 | ␉if (bvr)␊ |
1080 | ␉{␊ |
1081 | const struct devsw *dp = devsw;␊ |
1082 | ␉␉while(dp->name && bvr->biosdev >= dp->biosdev)␊ |
1083 | dp++;␊ |
1084 | ␊ |
1085 | ␉␉dp--;␊ |
1086 | ␉␉if (dp->name)␊ |
1087 | return sprintf(str, "%s(%d,%d)", dp->name, bvr->biosdev - dp->biosdev, bvr->part_no);␊ |
1088 | ␉}␊ |
1089 | ␉␊ |
1090 | ␉return 0;␊ |
1091 | }␊ |
1092 |