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