1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2011 Gary Mills
25 * Copyright 2024 MNX Cloud, Inc.
26 */
27
28 /*
29 * common functions used by pcfs tools.
30 */
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <err.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <libintl.h>
38 #include <locale.h>
39 #include <langinfo.h>
40 #include <regex.h>
41 #include <sys/isa_defs.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <sys/fcntl.h>
45 #include <sys/dktp/fdisk.h>
46 #include <sys/dkio.h>
47 #include <sys/fs/pc_fs.h>
48 #include <sys/fs/pc_dir.h>
49 #include <sys/fs/pc_label.h>
50 #include "pcfs_common.h"
51 #include "pcfs_bpb.h"
52
53 /*
54 * The assumption here is that _BIG_ENDIAN implies sparc, and
55 * so in addition to swapping bytes we also have to construct
56 * packed structures by hand to avoid bus errors due to improperly
57 * aligned pointers.
58 */
59 #ifdef _BIG_ENDIAN
60 void swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp);
61 void swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp);
62 #endif /* _BIG_ENDIAN */
63
64 /*
65 * Validate sector size.
66 */
67 bool
is_sector_size_valid(size_t size)68 is_sector_size_valid(size_t size)
69 {
70 if (size != 512 && size != 1024 && size != 2048 && size != 4096)
71 return (false);
72 return (true);
73 }
74
75 /*
76 * Use DKIOCGMEDIAINFO to get sector size.
77 */
78 int
get_media_sector_size(int fd,size_t * sizep)79 get_media_sector_size(int fd, size_t *sizep)
80 {
81 struct dk_minfo dkminfo;
82
83 if (ioctl(fd, DKIOCGMEDIAINFO, &dkminfo) != -1) {
84 *sizep = dkminfo.dki_lbsize;
85 return (0);
86 }
87 /* In case the DKIOCGMEDIAINFO is not supported, return MINBPS. */
88 if (errno == ENOTTY) {
89 *sizep = MINBPS;
90 return (0);
91 }
92
93 return (errno);
94 }
95
96 /*
97 * store_16_bits
98 * Save the lower 16 bits of a 32 bit value (v) into the provided
99 * buffer (pointed at by *bp), and increment the buffer pointer
100 * as well. This way the routine can be called multiple times in
101 * succession to fill buffers. The value is stored in little-endian
102 * order.
103 */
104 void
store_16_bits(uchar_t ** bp,uint32_t v)105 store_16_bits(uchar_t **bp, uint32_t v)
106 {
107 uchar_t *l = *bp;
108
109 *l++ = v & 0xff;
110 *l = (v >> 8) & 0xff;
111 *bp += 2;
112 }
113
114 void
read_16_bits(uchar_t * bp,uint32_t * value)115 read_16_bits(uchar_t *bp, uint32_t *value)
116 {
117 *value = *bp++;
118 *value += *bp << 8;
119 }
120
121 /*
122 * store_32_bits
123 * Save the 32 bit value (v) into the provided buffer (pointed
124 * at by *bp), and increment the buffer pointer as well. This way
125 * the routine can be called multiple times in succession to fill
126 * buffers. The value is stored in little-endian order.
127 */
128 void
store_32_bits(uchar_t ** bp,uint32_t v)129 store_32_bits(uchar_t **bp, uint32_t v)
130 {
131 uchar_t *l = *bp;
132 int b;
133
134 for (b = 0; b < 4; b++) {
135 *l++ = v & 0xff;
136 v = v >> 8;
137 }
138 *bp += 4;
139 }
140
141 void
read_32_bits(uchar_t * bp,uint32_t * value)142 read_32_bits(uchar_t *bp, uint32_t *value)
143 {
144 *value = *bp++;
145 *value += *bp++ << 8;
146 *value += *bp++ << 16;
147 *value += *bp++ << 24;
148 }
149
150 /*
151 * dump_bytes -- display bytes as hex numbers.
152 * b is the pointer to the byte buffer
153 * n is the number of bytes in the buffer
154 */
155 /* Note: BPL = bytes to display per line */
156 #define BPL 16
157
158 void
dump_bytes(uchar_t * buf,int n)159 dump_bytes(uchar_t *buf, int n)
160 {
161 int printedCount;
162 int countdown = n;
163 int countup = 0;
164 int offset = 0;
165 int byte;
166
167 /* Display offset, 16 bytes per line, and printable ascii version */
168 while (countdown > 0) {
169 printedCount = 0;
170 (void) fprintf(stderr, "\n%06x: ", offset);
171 /*
172 * Print Hex value of characters in columns on left
173 */
174 for (byte = 0; byte < BPL; byte++) {
175 if (countup + byte < n) {
176 (void) fprintf(stderr,
177 "%02x ", (buf[countup + byte] & 0xff));
178 printedCount++;
179 } else {
180 (void) fprintf(stderr, " ");
181 }
182 }
183 /*
184 * Right side has the printable character or '.' for
185 * unprintable for each column of the left.
186 */
187 for (byte = 0; byte < BPL; byte++) {
188 if ((countup + byte < n) &&
189 ((buf[countup + byte] >= ' ') &&
190 (buf[countup + byte] <= '~'))) {
191 (void) fprintf(stderr, "%c",
192 buf[countup + byte]);
193 } else {
194 (void) fprintf(stderr, ".");
195 }
196 }
197 countup += printedCount;
198 offset += printedCount;
199 countdown -= printedCount;
200 }
201 (void) fprintf(stderr, "\n\n");
202 }
203
204 /*
205 * header_for_dump -- display simple header over what will be output.
206 */
207 void
header_for_dump(void)208 header_for_dump(void)
209 {
210 int byte;
211
212 (void) fprintf(stderr, "\n ");
213 for (byte = 0; byte < BPL; byte++)
214 (void) fprintf(stderr, "%02x ", byte);
215 (void) fprintf(stderr, "\n ");
216 byte = 3 * BPL;
217 while (byte-- > 0)
218 (void) fprintf(stderr, "-");
219 }
220
221 /*
222 * We are basically (incorrectly) assuming that if you aren't running
223 * on x86 the BPB has to be packed by hand AND that the bytes must
224 * be swapped. One or both of these assumptions may one day be invalid.
225 * (if they aren't already :-))
226 */
227 #ifdef _BIG_ENDIAN
228 /*
229 * swap_pack_grab{32}bpb
230 * If not on an x86 we assume the structures making up the bpb
231 * were not packed and that longs and shorts need to be byte swapped
232 * (we've kept everything in host order up until now). A new architecture
233 * might not need to swap or might not need to pack, in which case
234 * new routines will have to be written. Of course if an architecture
235 * supports both packing and little-endian host order, it can follow the
236 * same path as the x86 code.
237 */
238 void
swap_pack_grabbpb(bpb_t * wbpb,struct _boot_sector * bsp)239 swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp)
240 {
241 uchar_t *grabp;
242
243 grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]);
244
245 ((uchar_t *)&(wbpb->bpb.bytes_per_sector))[1] = *grabp++;
246 ((uchar_t *)&(wbpb->bpb.bytes_per_sector))[0] = *grabp++;
247 wbpb->bpb.sectors_per_cluster = *grabp++;
248 ((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++;
249 ((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++;
250 wbpb->bpb.num_fats = *grabp++;
251 ((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++;
252 ((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++;
253 ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++;
254 ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++;
255 wbpb->bpb.media = *grabp++;
256 ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++;
257 ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++;
258 ((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++;
259 ((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++;
260 ((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++;
261 ((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++;
262 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++;
263 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++;
264 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++;
265 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++;
266 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++;
267 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++;
268 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++;
269 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++;
270 wbpb->ebpb.phys_drive_num = *grabp++;
271 wbpb->ebpb.reserved = *grabp++;
272 wbpb->ebpb.ext_signature = *grabp++;
273 ((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++;
274 ((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++;
275 ((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++;
276 ((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++;
277
278 (void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11);
279 grabp += 11;
280 (void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8);
281 }
282
283 void
swap_pack_grab32bpb(bpb_t * wbpb,struct _boot_sector * bsp)284 swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp)
285 {
286 uchar_t *grabp;
287
288 grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]);
289
290 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++;
291 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++;
292 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++;
293 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++;
294 ((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++;
295 ((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++;
296 wbpb->bpb32.fs_vers_lo = *grabp++;
297 wbpb->bpb32.fs_vers_hi = *grabp++;
298 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++;
299 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++;
300 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++;
301 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++;
302 ((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++;
303 ((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++;
304 ((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++;
305 ((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++;
306 ((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++;
307 ((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++;
308 ((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++;
309 ((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++;
310 ((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++;
311 ((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++;
312 ((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++;
313 ((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++;
314 ((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++;
315 ((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++;
316 ((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++;
317 ((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++;
318 }
319 #endif /* _BIG_ENDIAN */
320
321 char *
stat_actual_disk(const char * diskname,struct stat * info,char ** suffix)322 stat_actual_disk(const char *diskname, struct stat *info, char **suffix)
323 {
324 char *actualdisk;
325
326 if (stat(diskname, info) != 0) {
327 /*
328 * Device named on command line doesn't exist. That
329 * probably means there is a partition-specifying
330 * suffix attached to the actual disk name.
331 */
332 if ((actualdisk = strdup(diskname)) == NULL) {
333 (void) fprintf(stderr,
334 gettext("Out of memory for disk name.\n"));
335 exit(2);
336 }
337 if ((*suffix = strchr(actualdisk, ':')) != NULL) {
338 **suffix = '\0';
339 (*suffix)++;
340 }
341
342 if (stat(actualdisk, info)) {
343 err(2, "Failed to stat disk device %s",
344 actualdisk);
345 }
346 } else {
347 if ((actualdisk = strdup(diskname)) == NULL) {
348 (void) fprintf(stderr,
349 gettext("Out of memory for disk name.\n"));
350 exit(2);
351 }
352 }
353
354 return (actualdisk);
355 }
356
357 extern void usage(void);
358
359 void
bad_arg(char * option)360 bad_arg(char *option)
361 {
362 (void) fprintf(stderr,
363 gettext("Unrecognized option -o %s.\n"), option);
364 usage();
365 exit(2);
366 }
367
368 void
missing_arg(char * option)369 missing_arg(char *option)
370 {
371 (void) fprintf(stderr,
372 gettext("Option %s requires a value.\n"), option);
373 usage();
374 exit(3);
375 }
376
377 static int
parse_drvnum(char * pn)378 parse_drvnum(char *pn)
379 {
380 int drvnum;
381
382 /*
383 * Determine logical drive to seek after.
384 */
385 if ((strlen(pn) == 1) && ((*pn >= 'c') && (*pn <= 'z'))) {
386 drvnum = *pn - 'c' + 1;
387 } else if ((*pn >= '0') && (*pn <= '9')) {
388 char *d;
389 int v = 0;
390
391 d = pn;
392 while ((*d != '\0') && (*d >= '0') && (*d <= '9')) {
393 v *= 10;
394 v += *d - '0';
395 d++;
396 }
397 if ((*d != '\0') || (v > 24)) {
398 (void) fprintf(stderr,
399 gettext("%s: bogus logical drive specification.\n"),
400 pn);
401 return (-1);
402 }
403 drvnum = v;
404 } else if (strcmp(pn, "boot") == 0) {
405 drvnum = 99;
406 } else {
407 (void) fprintf(stderr,
408 gettext("%s: bogus logical drive specification.\n"), pn);
409 return (-1);
410 }
411
412 return (drvnum);
413 }
414
415 /*
416 * isDosDrive()
417 * Boolean function. Give it the systid field for an fdisk partition
418 * and it decides if that's a systid that describes a DOS drive. We
419 * use systid values defined in sys/dktp/fdisk.h.
420 */
421 static int
isDosDrive(uchar_t checkMe)422 isDosDrive(uchar_t checkMe)
423 {
424 return ((checkMe == DOSOS12) || (checkMe == DOSOS16) ||
425 (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) ||
426 (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) ||
427 (checkMe == DIAGPART));
428 }
429
430 /*
431 * isDosExtended()
432 * Boolean function. Give it the systid field for an fdisk partition
433 * and it decides if that's a systid that describes an extended DOS
434 * partition.
435 */
436 static int
isDosExtended(uchar_t checkMe)437 isDosExtended(uchar_t checkMe)
438 {
439 return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA));
440 }
441
442 /*
443 * isBootPart()
444 * Boolean function. Give it the systid field for an fdisk partition
445 * and it decides if that's a systid that describes a Solaris boot
446 * partition.
447 */
448 static int
isBootPart(uchar_t checkMe)449 isBootPart(uchar_t checkMe)
450 {
451 return (checkMe == X86BOOT);
452 }
453
454 off64_t
findPartitionOffset(int fd,size_t bpsec,char * ldrive)455 findPartitionOffset(int fd, size_t bpsec, char *ldrive)
456 {
457 struct ipart part[FD_NUMPART];
458 struct mboot extmboot;
459 struct mboot mb;
460 diskaddr_t xstartsect;
461 off64_t nextseek = 0;
462 off64_t lastseek = 0;
463 off64_t found = 0;
464 off64_t error = -1;
465 int logicalDriveCount = 0;
466 int extendedPart = -1;
467 int primaryPart = -1;
468 int bootPart = -1;
469 uint32_t xnumsect = 0;
470 int drvnum;
471 int driveIndex;
472 int i;
473 /*
474 * Count of drives in the current extended partition's
475 * FDISK table, and indexes of the drives themselves.
476 */
477 int extndDrives[FD_NUMPART];
478 int numDrives = 0;
479 /*
480 * Count of drives (beyond primary) in master boot record's
481 * FDISK table, and indexes of the drives themselves.
482 */
483 int extraDrives[FD_NUMPART];
484 int numExtraDrives = 0;
485
486 if ((drvnum = parse_drvnum(ldrive)) < 0)
487 return (error);
488
489 if (read(fd, &mb, bpsec) != (ssize_t)bpsec) {
490 (void) fprintf(stderr,
491 gettext("Couldn't read a Master Boot Record\n"));
492 return (error);
493 }
494
495 if (ltohs(mb.signature) != BOOTSECSIG) {
496 (void) fprintf(stderr,
497 gettext("Bad signature on master boot record (%x)\n"),
498 ltohs(mb.signature));
499 return (error);
500 }
501
502 /*
503 * Copy partition table into memory
504 */
505 (void) memcpy(part, mb.parts, sizeof (part));
506
507 /*
508 * Get a summary of what is in the Master FDISK table.
509 * Normally we expect to find one partition marked as a DOS drive.
510 * This partition is the one Windows calls the primary dos partition.
511 * If the machine has any logical drives then we also expect
512 * to find a partition marked as an extended DOS partition.
513 *
514 * Sometimes we'll find multiple partitions marked as DOS drives.
515 * The Solaris fdisk program allows these partitions
516 * to be created, but Windows fdisk no longer does. We still need
517 * to support these, though, since Windows does. We also need to fix
518 * our fdisk to behave like the Windows version.
519 *
520 * It turns out that some off-the-shelf media have *only* an
521 * Extended partition, so we need to deal with that case as
522 * well.
523 *
524 * Only a single (the first) Extended or Boot Partition will
525 * be recognized. Any others will be ignored.
526 */
527 for (i = 0; i < FD_NUMPART; i++) {
528 if (isDosDrive(part[i].systid)) {
529 if (primaryPart < 0) {
530 logicalDriveCount++;
531 primaryPart = i;
532 } else {
533 extraDrives[numExtraDrives++] = i;
534 }
535 continue;
536 }
537 if ((extendedPart < 0) && isDosExtended(part[i].systid)) {
538 extendedPart = i;
539 continue;
540 }
541 if ((bootPart < 0) && isBootPart(part[i].systid)) {
542 bootPart = i;
543 continue;
544 }
545 }
546
547 if (drvnum == BOOT_PARTITION_DRIVE) {
548 if (bootPart < 0) {
549 (void) fprintf(stderr,
550 gettext("No boot partition found on drive\n"));
551 return (error);
552 }
553 found = ltohi(part[bootPart].relsect) * bpsec;
554 return (found);
555 }
556
557 if (drvnum == PRIMARY_DOS_DRIVE && primaryPart >= 0) {
558 found = ltohi(part[primaryPart].relsect) * bpsec;
559 return (found);
560 }
561
562 /*
563 * We are not looking for the C: drive (or there was no primary
564 * drive found), so we had better have an extended partition or
565 * extra drives in the Master FDISK table.
566 */
567 if ((extendedPart < 0) && (numExtraDrives == 0)) {
568 (void) fprintf(stderr,
569 gettext("No such logical drive "
570 "(missing extended partition entry)\n"));
571 return (error);
572 }
573
574 if (extendedPart >= 0) {
575 nextseek = xstartsect = ltohi(part[extendedPart].relsect);
576 xnumsect = ltohi(part[extendedPart].numsect);
577 do {
578 /*
579 * If the seek would not cause us to change
580 * position on the drive, then we're out of
581 * extended partitions to examine.
582 */
583 if (nextseek == lastseek)
584 break;
585 logicalDriveCount += numDrives;
586 /*
587 * Seek the next extended partition, and find
588 * logical drives within it.
589 */
590 if (lseek64(fd, nextseek * bpsec, SEEK_SET) < 0 ||
591 read(fd, &extmboot, sizeof (extmboot)) !=
592 sizeof (extmboot)) {
593 perror(gettext("Unable to read extended "
594 "partition record"));
595 return (error);
596 }
597 (void) memcpy(part, extmboot.parts, sizeof (part));
598 lastseek = nextseek;
599 if (ltohs(extmboot.signature) != MBB_MAGIC) {
600 (void) fprintf(stderr,
601 gettext("Bad signature on "
602 "extended partition\n"));
603 return (error);
604 }
605 /*
606 * Count up drives, and track where the next
607 * extended partition is in case we need it. We
608 * are expecting only one extended partition. If
609 * there is more than one we'll only go to the
610 * first one we see, but warn about ignoring.
611 */
612 numDrives = 0;
613 for (i = 0; i < FD_NUMPART; i++) {
614 if (isDosDrive(part[i].systid)) {
615 extndDrives[numDrives++] = i;
616 continue;
617 } else if (isDosExtended(part[i].systid)) {
618 if (nextseek != lastseek) {
619 /*
620 * Already found an extended
621 * partition in this table.
622 */
623 (void) fprintf(stderr,
624 gettext("WARNING: "
625 "Ignoring unexpected "
626 "additional extended "
627 "partition"));
628 continue;
629 }
630 nextseek = xstartsect +
631 ltohi(part[i].relsect);
632 continue;
633 }
634 }
635 } while (drvnum > logicalDriveCount + numDrives);
636
637 if (drvnum <= logicalDriveCount + numDrives) {
638 /*
639 * The number of logical drives we've found thus
640 * far is enough to get us to the one we were
641 * searching for.
642 */
643 driveIndex = logicalDriveCount + numDrives - drvnum;
644 found =
645 ltohi(part[extndDrives[driveIndex]].relsect) +
646 lastseek;
647 if (found > (xstartsect + xnumsect)) {
648 (void) fprintf(stderr,
649 gettext("Logical drive start sector (%d) "
650 "is not within the partition!\n"), found);
651 return (error);
652 } else {
653 found *= bpsec;
654 }
655 return (found);
656 } else {
657 /*
658 * We ran out of extended dos partition
659 * drives. The only hope now is to go
660 * back to extra drives defined in the master
661 * fdisk table. But we overwrote that table
662 * already, so we must load it in again.
663 */
664 logicalDriveCount += numDrives;
665 (void) memcpy(part, mb.parts, sizeof (part));
666 }
667 }
668 /*
669 * Still haven't found the drive, is it an extra
670 * drive defined in the main FDISK table?
671 */
672 if (drvnum <= logicalDriveCount + numExtraDrives) {
673 driveIndex = logicalDriveCount + numExtraDrives - drvnum;
674 found = ltohi(part[extraDrives[driveIndex]].relsect) * bpsec;
675 return (found);
676 }
677 return (error);
678 }
679