1 /* $NetBSD: disksubr.c,v 1.27 2008/01/02 11:48:28 ad Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.27 2008/01/02 11:48:28 ad Exp $"); 36 37 #include "opt_mbr.h" 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/buf.h> 42 #include <sys/disklabel.h> 43 #include <sys/disk.h> 44 #include <sys/syslog.h> 45 46 #include <sys/bswap.h> 47 48 int fat_types[] = { MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S, 49 MBR_PTYPE_FAT16B, MBR_PTYPE_FAT32, 50 MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L, 51 -1 }; 52 53 #define NO_MBR_SIGNATURE ((struct mbr_partition *) -1) 54 55 #ifdef BSDDISKLABEL_EI 56 void swap_endian_disklabel(struct disklabel *, struct disklabel *); 57 uint16_t dkcksum_re(struct disklabel *); 58 #endif 59 #ifdef COMPAT_MMEYE_OLDLABEL 60 void swap_mmeye_disklabel(struct disklabel *, struct disklabel *); 61 uint16_t dkcksum_mmeye(struct disklabel *); 62 #endif 63 64 static struct mbr_partition *mbr_findslice(struct mbr_partition *, 65 struct buf *); 66 67 #ifdef BSDDISKLABEL_EI 68 void 69 swap_endian_disklabel(struct disklabel *nlp, struct disklabel *olp) 70 { 71 int i; 72 #define SW16(X) nlp->X = bswap16(olp->X) 73 #define SW32(X) nlp->X = bswap32(olp->X) 74 75 SW32(d_magic); 76 SW16(d_type); 77 SW16(d_subtype); 78 79 /* no need to swap char strings */ 80 memcpy(nlp->d_typename, olp->d_typename, sizeof(nlp->d_typename)); 81 82 /* XXX What should we do for d_un (an union of char and pointers) ? */ 83 memcpy(nlp->d_packname, olp->d_packname, sizeof(nlp->d_packname)); 84 85 SW32(d_secsize); 86 SW32(d_nsectors); 87 SW32(d_ntracks); 88 SW32(d_ncylinders); 89 SW32(d_secpercyl); 90 SW32(d_secperunit); 91 92 SW16(d_sparespertrack); 93 SW16(d_sparespercyl); 94 95 SW32(d_acylinders); 96 97 SW16(d_rpm); 98 SW16(d_interleave); 99 SW16(d_trackskew); /* sector 0 skew, per track */ 100 SW16(d_cylskew); /* sector 0 skew, per cylinder */ 101 SW32(d_headswitch); /* head switch time, usec */ 102 SW32(d_trkseek); /* track-to-track seek, usec */ 103 SW32(d_flags); /* generic flags */ 104 105 for (i = 0; i < NDDATA; i++) 106 SW32(d_drivedata[i]); /* drive-type specific information */ 107 108 for (i = 0; i < NSPARE; i++) 109 SW32(d_spare[i]); /* reserved for future use */ 110 111 SW32(d_magic2); /* the magic number (again) */ 112 SW16(d_checksum); /* xor of data incl. partitions */ 113 114 /* filesystem and partition information: */ 115 SW16(d_npartitions); /* number of partitions in following */ 116 SW32(d_bbsize); /* size of boot area at sn0, bytes */ 117 SW32(d_sbsize); /* max size of fs superblock, bytes */ 118 119 for (i = 0; i < MAXPARTITIONS; i++) { 120 SW32(d_partitions[i].p_size); 121 SW32(d_partitions[i].p_offset); 122 SW32(d_partitions[i].p_fsize); 123 /* p_fstype and p_frag is uint8_t, so no need to swap */ 124 nlp->d_partitions[i].p_fstype = olp->d_partitions[i].p_fstype; 125 nlp->d_partitions[i].p_frag = olp->d_partitions[i].p_frag; 126 SW16(d_partitions[i].p_cpg); 127 } 128 #undef SW32 129 #undef SW16 130 } 131 132 uint16_t 133 dkcksum_re(struct disklabel *lp) 134 { 135 uint16_t *start, *end; 136 uint16_t sum = 0; 137 138 start = (uint16_t *)lp; 139 end = (uint16_t *)&lp->d_partitions[bswap16(lp->d_npartitions)]; 140 while (start < end) 141 sum ^= *start++; 142 return (sum); 143 } 144 #endif 145 146 #ifdef COMPAT_MMEYE_OLDLABEL 147 void 148 swap_mmeye_disklabel(struct disklabel *nlp, struct disklabel *olp) 149 { 150 int i; 151 uint16_t *np, *op; 152 153 #if BYTE_ORDER == BIG_ENDIAN 154 #define SW16(X) nlp->X = bswap16(olp->X) 155 #define SW32(X) nlp->X = bswap32(olp->X) 156 #else 157 #define SW16(X) nlp->X = olp->X 158 #define SW32(X) nlp->X = olp->X 159 #endif 160 161 SW32(d_magic); 162 SW16(d_type); 163 SW16(d_subtype); 164 165 op = (uint16_t *)&olp->d_typename[0]; 166 np = (uint16_t *)&nlp->d_typename[0]; 167 for (i = 0; i < sizeof(olp->d_typename) / sizeof(uint16_t); i++) 168 *np++ = bswap16(*op++); 169 170 op = (uint16_t *)&olp->d_un.un_d_packname[0]; 171 np = (uint16_t *)&nlp->d_un.un_d_packname[0]; 172 for (i = 0; i < sizeof(olp->d_un) / sizeof(uint16_t); i++) 173 *np++ = bswap16(*op++); 174 175 SW32(d_secsize); 176 SW32(d_nsectors); 177 SW32(d_ntracks); 178 SW32(d_ncylinders); 179 SW32(d_secpercyl); 180 SW32(d_secperunit); 181 182 SW16(d_sparespertrack); 183 SW16(d_sparespercyl); 184 185 SW32(d_acylinders); 186 187 SW16(d_rpm); 188 SW16(d_interleave); 189 SW16(d_trackskew); /* sector 0 skew, per track */ 190 SW16(d_cylskew); /* sector 0 skew, per cylinder */ 191 SW32(d_headswitch); /* head switch time, usec */ 192 SW32(d_trkseek); /* track-to-track seek, usec */ 193 SW32(d_flags); /* generic flags */ 194 195 for (i = 0; i < NDDATA; i++) 196 SW32(d_drivedata[i]); /* drive-type specific information */ 197 198 for (i = 0; i < NSPARE; i++) 199 SW32(d_spare[i]); /* reserved for future use */ 200 201 SW32(d_magic2); /* the magic number (again) */ 202 SW16(d_checksum); /* xor of data incl. partitions */ 203 204 /* filesystem and partition information: */ 205 SW16(d_npartitions); /* number of partitions in following */ 206 SW32(d_bbsize); /* size of boot area at sn0, bytes */ 207 SW32(d_sbsize); /* max size of fs superblock, bytes */ 208 209 for (i = 0; i < MAXPARTITIONS; i++) { 210 SW32(d_partitions[i].p_size); 211 SW32(d_partitions[i].p_offset); 212 SW32(d_partitions[i].p_fsize); 213 nlp->d_partitions[i].p_fstype = olp->d_partitions[i].p_fstype; 214 nlp->d_partitions[i].p_frag = olp->d_partitions[i].p_frag; 215 SW16(d_partitions[i].p_cpg); 216 } 217 #undef SW32 218 #undef SW16 219 } 220 221 uint16_t 222 dkcksum_mmeye(struct disklabel *lp) 223 { 224 struct disklabel tdl; 225 int i, offset; 226 uint16_t *start, *end, *fstype; 227 uint16_t sum = 0; 228 229 tdl = *lp; 230 231 for (i = 0; i < MAXPARTITIONS; i++) { 232 fstype = (uint16_t *)&tdl.d_partitions[i].p_fstype; 233 *fstype = bswap16(*fstype); 234 } 235 236 offset = offsetof(struct disklabel, 237 d_partitions[le16toh(lp->d_npartitions)]); 238 start = (uint16_t *)&tdl; 239 end = start + offset; 240 241 while (start < end) 242 sum ^= *start++; 243 return (sum); 244 } 245 #endif 246 247 /* 248 * Scan MBR for NetBSD partittion. Return NO_MBR_SIGNATURE if no MBR found 249 * Otherwise, copy valid MBR partition-table into dp, and if a NetBSD 250 * partition is found, return a pointer to it; else return NULL. 251 */ 252 static struct mbr_partition * 253 mbr_findslice(struct mbr_partition *dp, struct buf *bp) 254 { 255 struct mbr_partition *ourdp = NULL; 256 uint16_t *mbrmagicp; 257 int i; 258 259 /* Note: Magic number is little-endian. */ 260 mbrmagicp = (uint16_t *)((char *)bp->b_data + MBR_MAGIC_OFFSET); 261 if (le16toh(*mbrmagicp) != MBR_MAGIC) 262 return (NO_MBR_SIGNATURE); 263 264 /* XXX how do we check veracity/bounds of this? */ 265 memcpy(dp, (char *)bp->b_data + MBR_PART_OFFSET, 266 MBR_PART_COUNT * sizeof(*dp)); 267 268 /* look for NetBSD partition */ 269 for (i = 0; i < MBR_PART_COUNT; i++) { 270 if (dp[i].mbrp_type == MBR_PTYPE_NETBSD) { 271 ourdp = &dp[i]; 272 break; 273 } 274 } 275 276 return (ourdp); 277 } 278 279 280 /* 281 * Attempt to read a disk label from a device 282 * using the indicated strategy routine. 283 * The label must be partly set up before this: 284 * secpercyl, secsize and anything required for a block i/o read 285 * operation in the driver's strategy/start routines 286 * must be filled in before calling us. 287 * 288 * If dos partition table requested, attempt to load it and 289 * find disklabel inside a DOS partition. Also, if bad block 290 * table needed, attempt to extract it as well. Return buffer 291 * for use in signalling errors if requested. 292 * 293 * Returns null on success and an error string on failure. 294 */ 295 const char * 296 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 297 struct cpu_disklabel *osdep) 298 { 299 struct mbr_partition *dp; 300 struct partition *pp; 301 struct dkbad *bdp; 302 struct buf *bp; 303 struct disklabel *dlp; 304 const char *msg = NULL; 305 int dospartoff, cyl, i, *ip; 306 307 /* minimal requirements for archtypal disk label */ 308 if (lp->d_secsize == 0) 309 lp->d_secsize = DEV_BSIZE; 310 if (lp->d_secperunit == 0) 311 lp->d_secperunit = 0x1fffffff; 312 #if 0 313 if (lp->d_ncylinders == 16383) { 314 printf("disklabel: Disk > 8G ... readjusting chs %d/%d/%d to ", 315 lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors); 316 lp->d_ncylinders = lp->d_secperunit / lp->d_ntracks / lp->d_nsectors; 317 printf("%d/%d/%d\n", 318 lp->d_ncylinders, lp->d_ntracks, lp->d_nsectors); 319 } 320 #endif 321 lp->d_npartitions = RAW_PART + 1; 322 for (i = 0; i < RAW_PART; i++) { 323 lp->d_partitions[i].p_size = 0; 324 lp->d_partitions[i].p_offset = 0; 325 } 326 if (lp->d_partitions[i].p_size == 0) 327 lp->d_partitions[i].p_size = 0x1fffffff; 328 lp->d_partitions[i].p_offset = 0; 329 330 /* get a buffer and initialize it */ 331 bp = geteblk((int)lp->d_secsize); 332 bp->b_dev = dev; 333 334 /* do dos partitions in the process of getting disklabel? */ 335 dospartoff = 0; 336 cyl = LABELSECTOR / lp->d_secpercyl; 337 if (!osdep) 338 goto nombrpart; 339 dp = osdep->dosparts; 340 341 /* read master boot record */ 342 bp->b_blkno = MBR_BBSECTOR; 343 bp->b_bcount = lp->d_secsize; 344 bp->b_flags |= B_READ; 345 bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl; 346 (*strat)(bp); 347 348 /* if successful, wander through dos partition table */ 349 if (biowait(bp)) { 350 msg = "dos partition I/O error"; 351 goto done; 352 } else { 353 struct mbr_partition *ourdp = NULL; 354 355 ourdp = mbr_findslice(dp, bp); 356 if (ourdp == NO_MBR_SIGNATURE) 357 goto nombrpart; 358 359 for (i = 0; i < MBR_PART_COUNT; i++, dp++) { 360 /* Install in partition e, f, g, or h. */ 361 pp = &lp->d_partitions[RAW_PART + 1 + i]; 362 pp->p_offset = le32toh(dp->mbrp_start); 363 pp->p_size = le32toh(dp->mbrp_size); 364 for (ip = fat_types; *ip != -1; ip++) { 365 if (dp->mbrp_type == *ip) 366 pp->p_fstype = FS_MSDOS; 367 } 368 if (dp->mbrp_type == MBR_PTYPE_LNXEXT2) 369 pp->p_fstype = FS_EX2FS; 370 371 if (dp->mbrp_type == MBR_PTYPE_NTFS) 372 pp->p_fstype = FS_NTFS; 373 374 /* is this ours? */ 375 if (dp == ourdp) { 376 /* need sector address for SCSI/IDE, 377 cylinder for ESDI/ST506/RLL */ 378 dospartoff = le32toh(dp->mbrp_start); 379 cyl = MBR_PCYL(dp->mbrp_scyl, dp->mbrp_ssect); 380 381 /* update disklabel with details */ 382 lp->d_partitions[2].p_size = 383 le32toh(dp->mbrp_size); 384 lp->d_partitions[2].p_offset = 385 le32toh(dp->mbrp_start); 386 #if 0 387 if (lp->d_ntracks != dp->mbrp_ehd + 1 || 388 lp->d_nsectors != MBR_PSECT(dp->mbrp_esect)) { 389 printf("disklabel: BIOS sees chs %d/%d/%d as ", 390 lp->d_ncylinders, lp->d_ntracks, 391 lp->d_nsectors); 392 lp->d_ntracks = dp->mbrp_ehd + 1; 393 lp->d_nsectors = MBR_PSECT(dp->mbrp_esect); 394 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 395 lp->d_ncylinders = lp->d_secperunit / lp->d_secpercyl; 396 if (! lp->d_ncylinders) 397 lp->d_ncylinders = 1; 398 printf("%d/%d/%d\n", 399 lp->d_ncylinders, lp->d_ntracks, 400 lp->d_nsectors); 401 } 402 #endif 403 } 404 } 405 lp->d_npartitions = RAW_PART + 1 + i; 406 } 407 408 nombrpart: 409 /* next, dig out disk label */ 410 bp->b_blkno = dospartoff + LABELSECTOR; 411 bp->b_cylinder = cyl; 412 bp->b_bcount = lp->d_secsize; 413 bp->b_oflags &= ~(BO_DONE); 414 bp->b_flags |= B_READ; 415 (*strat)(bp); 416 417 /* if successful, locate disk label within block and validate */ 418 if (biowait(bp)) { 419 msg = "disk label I/O error"; 420 goto done; 421 } 422 for (dlp = (struct disklabel *)bp->b_data; 423 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - 424 sizeof(*dlp)); 425 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 426 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) { 427 /* disklabel is written in host's endian */ 428 if (dlp->d_npartitions > MAXPARTITIONS || 429 dkcksum(dlp) != 0) 430 msg = "disk label corruptted"; 431 else { 432 *lp = *dlp; 433 msg = NULL; 434 break; 435 } 436 } 437 #ifdef BSDDISKLABEL_EI 438 if (bswap32(dlp->d_magic) == DISKMAGIC && 439 bswap32(dlp->d_magic2) == DISKMAGIC) { 440 /* disklabel is written in reversed endian */ 441 if (bswap16(dlp->d_npartitions) > MAXPARTITIONS || 442 dkcksum_re(dlp) != 0) 443 msg = "disk label corruptted"; 444 else { 445 swap_endian_disklabel(lp, dlp); 446 /* recalculate cksum in host's endian */ 447 lp->d_checksum = 0; 448 lp->d_checksum = dkcksum(lp); 449 450 msg = NULL; 451 break; 452 } 453 } 454 #endif 455 #ifdef COMPAT_MMEYE_OLDLABEL 456 if (le32toh(dlp->d_magic) == DISKMAGIC && 457 le32toh(dlp->d_magic2) == DISKMAGIC) { 458 if (le16toh(dlp->d_npartitions) > MAXPARTITIONS || 459 dkcksum_mmeye(dlp) != 0) 460 msg = "disk label corruptted"; 461 else { 462 /* disklabel is written in old mmeye's way */ 463 swap_mmeye_disklabel(lp, dlp); 464 /* recalculate cksum in host's endian */ 465 lp->d_checksum = 0; 466 lp->d_checksum = dkcksum(lp); 467 468 msg = NULL; 469 break; 470 } 471 } 472 #endif 473 if (msg == NULL) 474 msg = "no disk label"; 475 } 476 477 if (msg) 478 goto done; 479 480 /* obtain bad sector table if requested and present */ 481 if (osdep && (lp->d_flags & D_BADSECT)) { 482 struct dkbad *db; 483 484 bdp = &osdep->bad; 485 i = 0; 486 do { 487 /* read a bad sector table */ 488 bp->b_oflags &= ~(BO_DONE); 489 bp->b_flags |= B_READ; 490 bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i; 491 if (lp->d_secsize > DEV_BSIZE) 492 bp->b_blkno *= lp->d_secsize / DEV_BSIZE; 493 else 494 bp->b_blkno /= DEV_BSIZE / lp->d_secsize; 495 bp->b_bcount = lp->d_secsize; 496 bp->b_cylinder = lp->d_ncylinders - 1; 497 (*strat)(bp); 498 499 /* if successful, validate, otherwise try another */ 500 if (biowait(bp)) { 501 msg = "bad sector table I/O error"; 502 } else { 503 db = (struct dkbad *)(bp->b_data); 504 #define DKBAD_MAGIC 0x4321 505 if (db->bt_mbz == 0 506 && db->bt_flag == DKBAD_MAGIC) { 507 msg = NULL; 508 *bdp = *db; 509 break; 510 } else 511 msg = "bad sector table corrupted"; 512 } 513 } while (bp->b_error != 0 && (i += 2) < 10 && 514 i < lp->d_nsectors); 515 } 516 517 done: 518 brelse(bp, 0); 519 return (msg); 520 } 521 522 /* 523 * Check new disk label for sensibility 524 * before setting it. 525 */ 526 int 527 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, 528 struct cpu_disklabel *osdep) 529 { 530 int i; 531 struct partition *opp, *npp; 532 533 /* sanity clause */ 534 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 535 || (nlp->d_secsize % DEV_BSIZE) != 0) 536 return(EINVAL); 537 538 /* special case to allow disklabel to be invalidated */ 539 if (nlp->d_magic == 0xffffffff) { 540 *olp = *nlp; 541 return (0); 542 } 543 544 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC || 545 dkcksum(nlp) != 0) 546 return (EINVAL); 547 548 /* XXX missing check if other dos partitions will be overwritten */ 549 550 while (openmask != 0) { 551 i = ffs(openmask) - 1; 552 openmask &= ~(1 << i); 553 if (nlp->d_npartitions <= i) 554 return (EBUSY); 555 opp = &olp->d_partitions[i]; 556 npp = &nlp->d_partitions[i]; 557 if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size) 558 return (EBUSY); 559 /* 560 * Copy internally-set partition information 561 * if new label doesn't include it. XXX 562 */ 563 if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) { 564 npp->p_fstype = opp->p_fstype; 565 npp->p_fsize = opp->p_fsize; 566 npp->p_frag = opp->p_frag; 567 npp->p_cpg = opp->p_cpg; 568 } 569 } 570 nlp->d_checksum = 0; 571 nlp->d_checksum = dkcksum(nlp); 572 *olp = *nlp; 573 return (0); 574 } 575 576 577 /* 578 * Write disk label back to device after modification. 579 */ 580 int 581 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 582 struct cpu_disklabel *osdep) 583 { 584 struct mbr_partition *dp; 585 struct buf *bp; 586 struct disklabel *dlp; 587 int error, dospartoff, cyl; 588 589 /* get a buffer and initialize it */ 590 bp = geteblk((int)lp->d_secsize); 591 bp->b_dev = dev; 592 593 /* do dos partitions in the process of getting disklabel? */ 594 dospartoff = 0; 595 cyl = LABELSECTOR / lp->d_secpercyl; 596 if (!osdep) 597 goto nombrpart; 598 dp = osdep->dosparts; 599 600 /* read master boot record */ 601 bp->b_blkno = MBR_BBSECTOR; 602 bp->b_bcount = lp->d_secsize; 603 bp->b_flags |= B_READ; 604 bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl; 605 (*strat)(bp); 606 607 if ((error = biowait(bp)) == 0) { 608 struct mbr_partition *ourdp = NULL; 609 610 ourdp = mbr_findslice(dp, bp); 611 if (ourdp == NO_MBR_SIGNATURE) 612 goto nombrpart; 613 614 if (ourdp) { 615 /* need sector address for SCSI/IDE, 616 cylinder for ESDI/ST506/RLL */ 617 dospartoff = le32toh(ourdp->mbrp_start); 618 cyl = MBR_PCYL(ourdp->mbrp_scyl, ourdp->mbrp_ssect); 619 } 620 } 621 622 nombrpart: 623 #ifdef maybe 624 /* disklabel in appropriate location? */ 625 if (lp->d_partitions[2].p_offset != 0 626 && lp->d_partitions[2].p_offset != dospartoff) { 627 error = EXDEV; 628 goto done; 629 } 630 #endif 631 632 /* next, dig out disk label */ 633 bp->b_blkno = dospartoff + LABELSECTOR; 634 bp->b_cylinder = cyl; 635 bp->b_bcount = lp->d_secsize; 636 bp->b_oflags &= ~(BO_DONE); 637 bp->b_flags |= B_READ; 638 (*strat)(bp); 639 640 /* if successful, locate disk label within block and validate */ 641 if ((error = biowait(bp)) != 0) 642 goto done; 643 for (dlp = (struct disklabel *)bp->b_data; 644 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - 645 sizeof(*dlp)); 646 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 647 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC && 648 dlp->d_npartitions <= MAXPARTITIONS && 649 dkcksum(dlp) == 0) { 650 /* found disklabel in host's endian */ 651 *dlp = *lp; 652 goto found; 653 #ifdef BSDDISKLABEL_EI 654 } else if (bswap32(dlp->d_magic) == DISKMAGIC && 655 bswap32(dlp->d_magic2) == DISKMAGIC && 656 bswap16(dlp->d_npartitions) <= MAXPARTITIONS && 657 dkcksum_re(dlp) == 0) { 658 /* found disklabel in the opposite endian */ 659 swap_endian_disklabel(dlp, lp); 660 /* recalculate cksum in reversed endian */ 661 dlp->d_checksum = 0; 662 dlp->d_checksum = dkcksum_re(dlp); 663 goto found; 664 #endif 665 #ifdef COMPAT_MMEYE_OLDLABEL 666 } else if (le32toh(dlp->d_magic) == DISKMAGIC && 667 le32toh(dlp->d_magic2) == DISKMAGIC && 668 le16toh(dlp->d_npartitions) <= MAXPARTITIONS && 669 dkcksum_mmeye(dlp) == 0) { 670 /* found disklabel by old mmeye's rule */ 671 swap_mmeye_disklabel(dlp, lp); 672 /* recalculate cksum for it */ 673 dlp->d_checksum = 0; 674 dlp->d_checksum = dkcksum_mmeye(dlp); 675 goto found; 676 #endif 677 } 678 } 679 /* No valid disklabel found on disk */ 680 error = ESRCH; 681 goto done; 682 683 found: 684 bp->b_oflags &= ~(BO_DONE); 685 bp->b_flags &= ~(B_READ); 686 bp->b_flags |= B_WRITE; 687 (*strat)(bp); 688 error = biowait(bp); 689 690 done: 691 brelse(bp, 0); 692 return (error); 693 } 694