1 /* $NetBSD: subr_disk_mbr.c,v 1.63 2026/07/21 14:37:24 thorpej 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 /* 35 * Code to find a NetBSD label on a disk that contains an i386 style MBR. 36 * The first NetBSD label found in the 2nd sector of a NetBSD partition 37 * is used. 38 * If we don't find a label searching the MBR, we look at the start of the 39 * disk, if that fails then a label is faked up from the MBR. 40 * 41 * If there isn't a disklabel or anything in the MBR then the disc is searched 42 * for ecma-167/iso9660/udf style partition indicators. 43 * Useful for media or files that contain single filesystems (etc). 44 * 45 * This code will read host endian netbsd labels from little endian MBR. 46 * 47 * Based on the i386 disksubr.c 48 * 49 * Since the mbr only has 32bit fields for sector addresses, we do the same. 50 * 51 * XXX There are potential problems writing labels to disks where there 52 * is only space for 8 netbsd partitions but this code has been compiled 53 * with MAXPARTITIONS=16. 54 */ 55 56 #include <sys/cdefs.h> 57 __KERNEL_RCSID(0, "$NetBSD: subr_disk_mbr.c,v 1.63 2026/07/21 14:37:24 thorpej Exp $"); 58 59 #ifdef _KERNEL_OPT 60 #include "opt_mbr.h" 61 #include "opt_disklabel.h" 62 #endif /* _KERNEL_OPT */ 63 64 #include <sys/param.h> 65 #include <sys/types.h> 66 67 #include <sys/bootblock.h> 68 #include <sys/buf.h> 69 #include <sys/cdio.h> 70 #include <sys/conf.h> 71 #include <sys/disk.h> 72 #include <sys/disklabel.h> 73 #include <sys/fcntl.h> 74 #include <sys/kauth.h> 75 #include <sys/sdt.h> 76 #include <sys/syslog.h> 77 #include <sys/systm.h> 78 #include <sys/vnode.h> 79 80 #include <fs/udf/ecma167-udf.h> 81 82 typedef struct mbr_partition mbr_partition_t; 83 84 /* 85 * We allocate a buffer 3 sectors large, and look in all.... 86 * That means we find labels written by other ports with different offsets. 87 * LABELSECTOR and LABELOFFSET are only used if the disk doesn't have a label. 88 */ 89 #define SCANBLOCKS 3 90 #define DISKLABEL_SIZE 404 91 #if LABELSECTOR*DEV_BSIZE + LABELOFFSET > SCANBLOCKS*DEV_BSIZE - DISKLABEL_SIZE 92 #if _MACHINE != ews4800mips /* XXX: fail silently, ews4800mips LABELSECTOR */ 93 #error Invalid LABELSECTOR or LABELOFFSET 94 #endif 95 #endif 96 97 #define MBR_LABELSECTOR 1 98 99 #define SCAN_CONTINUE 0 100 #define SCAN_FOUND 1 101 #define SCAN_ERROR 2 102 103 typedef struct mbr_args { 104 struct disklabel *lp; 105 void (*strat)(struct buf *); 106 struct buf *bp; 107 const char *msg; 108 int error; 109 int written; /* number of times we wrote label */ 110 int found_mbr; /* set if disk has a valid mbr */ 111 uint label_sector; /* where we found the label */ 112 int action; 113 uint32_t secperunit; 114 #define READ_LABEL 1 115 #define UPDATE_LABEL 2 116 #define WRITE_LABEL 3 117 } mbr_args_t; 118 119 static int validate_label(mbr_args_t *, uint); 120 static int look_netbsd_part(mbr_args_t *, mbr_partition_t *, int, uint); 121 static int write_netbsd_label(mbr_args_t *, mbr_partition_t *, int, uint); 122 123 static int 124 read_sector(mbr_args_t *a, uint sector, int count) 125 { 126 int error; 127 128 error = disk_read_sectors(a->strat, a->lp, a->bp, sector, count); 129 if (error != 0) 130 a->error = error; 131 return error; 132 } 133 134 /* 135 * Scan MBR for partitions, call 'action' routine for each. 136 */ 137 138 static int 139 scan_mbr(mbr_args_t *a, int (*actn)(mbr_args_t *, mbr_partition_t *, int, uint)) 140 { 141 mbr_partition_t ptns[MBR_PART_COUNT]; 142 mbr_partition_t *dp; 143 struct mbr_sector *mbr; 144 uint ext_base, this_ext, next_ext; 145 int rval; 146 int i; 147 int j; 148 #ifdef COMPAT_386BSD_MBRPART 149 int dp_386bsd = -1; 150 int ap_386bsd = -1; 151 #endif 152 153 ext_base = 0; 154 this_ext = 0; 155 for (;;) { 156 if (read_sector(a, this_ext, 1)) { 157 a->msg = "dos partition I/O error"; 158 return SCAN_ERROR; 159 } 160 161 /* Note: Magic number is little-endian. */ 162 mbr = (void *)a->bp->b_data; 163 if (mbr->mbr_magic != htole16(MBR_MAGIC)) 164 return SCAN_CONTINUE; 165 166 /* 167 * If this is a protective MBR, bail now. 168 */ 169 if (mbr->mbr_parts[0].mbrp_type == MBR_PTYPE_PMBR 170 && mbr->mbr_parts[1].mbrp_type == MBR_PTYPE_UNUSED 171 && mbr->mbr_parts[2].mbrp_type == MBR_PTYPE_UNUSED 172 && mbr->mbr_parts[3].mbrp_type == MBR_PTYPE_UNUSED) 173 return SCAN_CONTINUE; 174 175 /* Copy data out of buffer so action can use bp */ 176 memcpy(ptns, &mbr->mbr_parts, sizeof ptns); 177 178 /* Look for drivers and skip them */ 179 if (ext_base == 0 && ptns[0].mbrp_type == MBR_PTYPE_DM6_DDO) { 180 /* We've found a DM6 DDO partition type (used by 181 * the Ontrack Disk Manager drivers). 182 * 183 * Ensure that there are no other partitions in the 184 * MBR and jump to the real partition table (stored 185 * in the first sector of the second track). */ 186 bool ok = true; 187 188 for (i = 1; i < MBR_PART_COUNT; i++) 189 if (ptns[i].mbrp_type != MBR_PTYPE_UNUSED) 190 ok = false; 191 192 if (ok) { 193 this_ext = le32toh(a->lp->d_secpercyl / 194 a->lp->d_ntracks); 195 continue; 196 } 197 } 198 199 /* look for NetBSD partition */ 200 next_ext = 0; 201 dp = ptns; 202 j = 0; 203 for (i = 0; i < MBR_PART_COUNT; i++, dp++) { 204 if (dp->mbrp_type == MBR_PTYPE_UNUSED) 205 continue; 206 /* Check end of partition is inside disk limits */ 207 if ((uint64_t)ext_base + le32toh(dp->mbrp_start) + 208 le32toh(dp->mbrp_size) > a->lp->d_secperunit) { 209 /* This mbr doesn't look good.... */ 210 a->msg = "mbr partition exceeds disk size"; 211 /* ...but don't report this as an error (yet) */ 212 return SCAN_CONTINUE; 213 } 214 a->found_mbr = 1; 215 if (MBR_IS_EXTENDED(dp->mbrp_type)) { 216 next_ext = le32toh(dp->mbrp_start); 217 continue; 218 } 219 #ifdef COMPAT_386BSD_MBRPART 220 if (dp->mbrp_type == MBR_PTYPE_386BSD) { 221 /* 222 * If more than one matches, take last, 223 * as NetBSD install tool does. 224 */ 225 if (this_ext == 0) { 226 dp_386bsd = i; 227 ap_386bsd = j; 228 } 229 continue; 230 } 231 #endif 232 rval = (*actn)(a, dp, j, this_ext); 233 if (rval != SCAN_CONTINUE) 234 return rval; 235 j++; 236 } 237 if (next_ext == 0) 238 break; 239 if (ext_base == 0) { 240 ext_base = next_ext; 241 next_ext = 0; 242 } 243 next_ext += ext_base; 244 if (next_ext <= this_ext) 245 break; 246 this_ext = next_ext; 247 } 248 #ifdef COMPAT_386BSD_MBRPART 249 if (this_ext == 0 && dp_386bsd != -1) 250 return (*actn)(a, &ptns[dp_386bsd], ap_386bsd, 0); 251 #endif 252 return SCAN_CONTINUE; 253 } 254 255 256 static void 257 scan_iso_vrs_session(mbr_args_t *a, uint32_t first_sector, 258 int *is_iso9660, int *is_udf) 259 { 260 struct vrs_desc *vrsd; 261 uint64_t vrs; 262 int sector_size; 263 int inc; 264 265 sector_size = a->lp->d_secsize; 266 inc = MAX(1, 2048 / sector_size); 267 268 /* by definition */ 269 vrs = ((32*1024 + sector_size - 1) / sector_size) 270 + first_sector; 271 272 /* read first vrs sector */ 273 if (read_sector(a, vrs, 1)) 274 return; 275 276 /* skip all CD001 records */ 277 vrsd = a->bp->b_data; 278 /* printf("vrsd->identifier = `%s`\n", vrsd->identifier); */ 279 while (memcmp(vrsd->identifier, "CD001", 5) == 0) { 280 /* for sure */ 281 *is_iso9660 = first_sector; 282 283 vrs += inc; 284 if (read_sector(a, vrs, 1)) 285 return; 286 } 287 288 /* search for BEA01 */ 289 vrsd = a->bp->b_data; 290 /* printf("vrsd->identifier = `%s`\n", vrsd->identifier); */ 291 if (memcmp(vrsd->identifier, "BEA01", 5)) 292 return; 293 294 /* read successor */ 295 vrs += inc; 296 if (read_sector(a, vrs, 1)) 297 return; 298 299 /* check for NSR[23] */ 300 vrsd = a->bp->b_data; 301 /* printf("vrsd->identifier = `%s`\n", vrsd->identifier); */ 302 if (memcmp(vrsd->identifier, "NSR0", 4)) 303 return; 304 305 *is_udf = first_sector; 306 } 307 308 309 /* 310 * Scan for ISO Volume Recognition Sequences 311 */ 312 313 static int 314 scan_iso_vrs(mbr_args_t *a) 315 { 316 struct mmc_discinfo di; 317 struct mmc_trackinfo ti; 318 dev_t dev; 319 uint64_t sector; 320 int is_iso9660, is_udf; 321 int tracknr, sessionnr; 322 int new_session, error; 323 324 is_iso9660 = is_udf = -1; 325 326 /* parse all sessions of disc if we're on a SCSI MMC device */ 327 if (a->lp->d_flags & D_SCSI_MMC) { 328 /* get disc info */ 329 dev = a->bp->b_dev; 330 error = bdev_ioctl(dev, MMCGETDISCINFO, &di, FKIOCTL, curlwp); 331 if (error) 332 goto notmmc; 333 334 /* go through all (data) tracks */ 335 sessionnr = -1; 336 for (tracknr = di.first_track; 337 tracknr <= di.first_track_last_session; tracknr++) 338 { 339 ti.tracknr = tracknr; 340 error = bdev_ioctl(dev, MMCGETTRACKINFO, &ti, 341 FKIOCTL, curlwp); 342 if (error) 343 goto notmmc; 344 new_session = (ti.sessionnr != sessionnr); 345 sessionnr = ti.sessionnr; 346 if (new_session) { 347 if (ti.flags & MMC_TRACKINFO_BLANK) 348 continue; 349 if (!(ti.flags & MMC_TRACKINFO_DATA)) 350 continue; 351 sector = ti.track_start; 352 scan_iso_vrs_session(a, sector, 353 &is_iso9660, &is_udf); 354 } 355 } 356 } else { 357 notmmc: 358 /* try start of disc */ 359 sector = 0; 360 scan_iso_vrs_session(a, sector, &is_iso9660, &is_udf); 361 } 362 363 if ((is_iso9660 < 0) && (is_udf < 0)) 364 return SCAN_CONTINUE; 365 366 strncpy(a->lp->d_typename, "iso partition", 16); 367 368 /* adjust session information for iso9660 partition */ 369 if (is_iso9660 >= 0) { 370 /* set 'a' partition to iso9660 */ 371 a->lp->d_partitions[0].p_offset = 0; 372 a->lp->d_partitions[0].p_size = a->lp->d_secperunit; 373 a->lp->d_partitions[0].p_cdsession = is_iso9660; 374 a->lp->d_partitions[0].p_fstype = FS_ISO9660; 375 } 376 377 /* UDF doesn't care about the cd session specified here */ 378 379 return SCAN_FOUND; 380 } 381 382 383 /* 384 * Attempt to read a disk label from a device 385 * using the indicated strategy routine. 386 * The label must be partly set up before this: 387 * secpercyl, secsize and anything required for a block i/o read 388 * operation in the driver's strategy/start routines 389 * must be filled in before calling us. 390 * 391 * If dos partition table requested, attempt to load it and 392 * find disklabel inside a DOS partition. Also, if bad block 393 * table needed, attempt to extract it as well. Return buffer 394 * for use in signalling errors if requested. 395 * 396 * Returns null on success and an error string on failure. 397 */ 398 const char * 399 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 400 struct cpu_disklabel *osdep) 401 { 402 int rval; 403 int i; 404 mbr_args_t a; 405 406 memset(&a, 0, sizeof a); 407 a.lp = lp; 408 a.strat = strat; 409 a.action = READ_LABEL; 410 411 /* minimal requirements for architypal disk label */ 412 if (lp->d_secsize == 0) 413 lp->d_secsize = DEV_BSIZE; 414 if (lp->d_secperunit == 0) 415 lp->d_secperunit = 0x1fffffff; 416 a.secperunit = lp->d_secperunit; 417 lp->d_npartitions = RAW_PART + 1; 418 for (i = 0; i < RAW_PART; i++) { 419 lp->d_partitions[i].p_size = 0; 420 lp->d_partitions[i].p_offset = 0; 421 } 422 if (lp->d_partitions[RAW_PART].p_size == 0) 423 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; 424 lp->d_partitions[RAW_PART].p_offset = 0; 425 426 /* 427 * Set partition 'a' to be the whole disk. 428 * Cleared if we find an mbr or a netbsd label. 429 */ 430 lp->d_partitions[0].p_size = lp->d_partitions[RAW_PART].p_size; 431 lp->d_partitions[0].p_fstype = FS_BSDFFS; 432 433 /* 434 * Get a buffer big enough to read a disklabel in and initialize it 435 * make it three sectors long for the validate_label(); see comment at 436 * start of file. 437 */ 438 a.bp = geteblk(SCANBLOCKS * (int)lp->d_secsize); 439 a.bp->b_dev = dev; 440 441 if (osdep) 442 /* 443 * Scan mbr searching for netbsd partition and saving 444 * bios partition information to use if the netbsd one 445 * is absent. 446 */ 447 rval = scan_mbr(&a, look_netbsd_part); 448 else 449 rval = SCAN_CONTINUE; 450 451 if (rval == SCAN_CONTINUE) { 452 /* Look at start of disk */ 453 rval = validate_label(&a, 0); 454 } 455 456 if (rval == SCAN_CONTINUE) { 457 rval = scan_iso_vrs(&a); 458 } 459 #if 0 460 /* 461 * Save sector where we found the label for the 'don't overwrite 462 * the label' check in bounds_check_with_label. 463 */ 464 if (rval == SCAN_FOUND) 465 xxx->label_sector = a.label_sector; 466 #endif 467 468 brelse(a.bp, 0); 469 if (rval == SCAN_ERROR || rval == SCAN_CONTINUE) 470 return a.msg; 471 return NULL; 472 } 473 474 static int 475 look_netbsd_part(mbr_args_t *a, mbr_partition_t *dp, int slot, uint ext_base) 476 { 477 struct partition *pp; 478 int ptn_base = ext_base + le32toh(dp->mbrp_start); 479 int rval; 480 481 if ( 482 #ifdef COMPAT_386BSD_MBRPART 483 dp->mbrp_type == MBR_PTYPE_386BSD || 484 #endif 485 dp->mbrp_type == MBR_PTYPE_NETBSD) { 486 rval = validate_label(a, ptn_base); 487 488 /* 489 * If RAW_PART == 3 ('d'), put actual location where we found 490 * the label into ptn 2 ('c'). 491 */ 492 if (RAW_PART == 3 && 493 (rval == SCAN_FOUND || 494 a->lp->d_partitions[2].p_size == 0)) { 495 a->lp->d_partitions[2].p_size = le32toh(dp->mbrp_size); 496 a->lp->d_partitions[2].p_offset = ptn_base; 497 } 498 499 /* If we got a netbsd label look no further */ 500 if (rval == SCAN_FOUND) 501 return rval; 502 } 503 504 /* Install main partitions into e..h and extended into i+ */ 505 if (ext_base == 0) 506 slot += 4; 507 else { 508 slot = 4 + MBR_PART_COUNT; 509 pp = &a->lp->d_partitions[slot]; 510 for (; slot < MAXPARTITIONS; pp++, slot++) { 511 /* This gets called twice - avoid duplicates */ 512 if (pp->p_offset == ptn_base && 513 pp->p_size == le32toh(dp->mbrp_size)) 514 break; 515 if (pp->p_size == 0) 516 break; 517 } 518 } 519 520 if (slot < MAXPARTITIONS) { 521 /* Stop 'a' being the entire disk */ 522 a->lp->d_partitions[0].p_size = 0; 523 a->lp->d_partitions[0].p_fstype = 0; 524 525 /* save partition info */ 526 pp = &a->lp->d_partitions[slot]; 527 pp->p_offset = ptn_base; 528 pp->p_size = le32toh(dp->mbrp_size); 529 pp->p_fstype = xlat_mbr_fstype(dp->mbrp_type); 530 531 if (slot >= a->lp->d_npartitions) 532 a->lp->d_npartitions = slot + 1; 533 } 534 535 return SCAN_CONTINUE; 536 } 537 538 __noubsan 539 static bool 540 check_label_magic(const struct disklabel *dlp, uint32_t diskmagic) 541 { 542 return memcmp(&dlp->d_magic, &diskmagic, sizeof(diskmagic)) == 0 && 543 memcmp(&dlp->d_magic2, &diskmagic, sizeof(diskmagic)) == 0; 544 } 545 546 #ifdef DISKLABEL_EI 547 /* 548 * - For read, convert a label to the native byte order. 549 * - For update or write, if a label already exists, keep its byte order. 550 * Otherwise, write a new label in the native byte order. 551 */ 552 #endif 553 static int 554 validate_label(mbr_args_t *a, uint label_sector) 555 { 556 struct disklabel *dlp; 557 char *dlp_lim, *dlp_byte; 558 int error; 559 #ifdef DISKLABEL_EI 560 int swapped = 0; 561 uint16_t npartitions; 562 #endif 563 564 /* Next, dig out disk label */ 565 if (read_sector(a, label_sector, SCANBLOCKS)) { 566 a->msg = "disk label read failed"; 567 return SCAN_ERROR; 568 } 569 570 /* Locate disk label within block and validate */ 571 /* 572 * XXX (dsl) This search may be a waste of time, a lot of other i386 573 * code assumes the label is at offset LABELOFFSET (=0) in the sector. 574 * 575 * If we want to support disks from other netbsd ports, then the 576 * code should also allow for a shorter label nearer the end of 577 * the disk sector, and (IIRC) labels within 8k of the disk start. 578 */ 579 dlp = (void *)a->bp->b_data; 580 dlp_lim = (char *)a->bp->b_data + a->bp->b_bcount - sizeof *dlp; 581 for (;; dlp = (void *)((char *)dlp + sizeof(uint32_t))) { 582 if ((char *)dlp > dlp_lim) { 583 if (a->action != WRITE_LABEL) 584 return SCAN_CONTINUE; 585 /* Write at arch. dependent default location */ 586 dlp_byte = (char *)a->bp->b_data + LABELOFFSET; 587 if (label_sector) 588 dlp_byte += MBR_LABELSECTOR * a->lp->d_secsize; 589 else 590 dlp_byte += LABELSECTOR * a->lp->d_secsize; 591 dlp = (void *)dlp_byte; 592 break; 593 } 594 if (!check_label_magic(dlp, DISKMAGIC)) 595 #ifdef DISKLABEL_EI 596 { 597 if (!check_label_magic(dlp, bswap32(DISKMAGIC))) 598 continue; 599 600 /* 601 * The label is in the other byte order. We need to 602 * checksum before swapping the byte order. 603 */ 604 npartitions = bswap16(dlp->d_npartitions); 605 if (npartitions > MAXPARTITIONS || 606 dkcksum_sized(dlp, npartitions) != 0) 607 goto corrupted; 608 609 swapped = 1; 610 } 611 #else 612 continue; 613 #endif 614 else if (dlp->d_npartitions > MAXPARTITIONS || 615 dkcksum(dlp) != 0) { 616 #ifdef DISKLABEL_EI 617 corrupted: 618 #endif 619 a->msg = "disk label corrupted"; 620 continue; 621 } 622 break; 623 } 624 625 switch (a->action) { 626 case READ_LABEL: 627 #ifdef DISKLABEL_EI 628 if (swapped) 629 disklabel_swap(a->lp, dlp); 630 else 631 *a->lp = *dlp; 632 #else 633 *a->lp = *dlp; 634 #endif 635 if ((a->msg = convertdisklabel(a->lp, a->strat, a->bp, 636 a->secperunit)) != NULL) 637 return SCAN_ERROR; 638 a->label_sector = label_sector; 639 return SCAN_FOUND; 640 case UPDATE_LABEL: 641 case WRITE_LABEL: 642 #ifdef DISKLABEL_EI 643 /* DO NOT swap a->lp itself for later references. */ 644 if (swapped) 645 disklabel_swap(dlp, a->lp); 646 else 647 *dlp = *a->lp; 648 #else 649 *dlp = *a->lp; 650 #endif 651 a->bp->b_oflags &= ~BO_DONE; 652 a->bp->b_flags &= ~B_READ; 653 a->bp->b_flags |= B_WRITE; 654 (*a->strat)(a->bp); 655 error = biowait(a->bp); 656 if (error != 0) { 657 a->error = error; 658 a->msg = "disk label write failed"; 659 return SCAN_ERROR; 660 } 661 a->written++; 662 /* Write label to all mbr partitions */ 663 return SCAN_CONTINUE; 664 default: 665 return SCAN_ERROR; 666 } 667 } 668 669 /* 670 * Write disk label back to device after modification. 671 */ 672 int 673 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 674 struct cpu_disklabel *osdep) 675 { 676 mbr_args_t a; 677 678 memset(&a, 0, sizeof a); 679 a.lp = lp; 680 a.strat = strat; 681 682 /* get a buffer and initialize it */ 683 a.bp = geteblk(SCANBLOCKS * (int)lp->d_secsize); 684 a.bp->b_dev = dev; 685 686 /* osdep => we expect an mbr with label in netbsd ptn */ 687 a.action = osdep != NULL ? WRITE_LABEL : UPDATE_LABEL; 688 689 /* Write/update the label to every netbsd mbr partition */ 690 scan_mbr(&a, write_netbsd_label); 691 692 /* Old write the label at the start of the volume on disks that 693 * don't have a valid mbr (always update an existing one) */ 694 a.action = a.found_mbr ? UPDATE_LABEL : WRITE_LABEL; 695 validate_label(&a, 0); 696 697 if (a.written == 0 && a.error == 0) 698 a.error = SET_ERROR(ESRCH); 699 700 brelse(a.bp, 0); 701 return a.error; 702 } 703 704 static int 705 write_netbsd_label(mbr_args_t *a, mbr_partition_t *dp, int slot, uint ext_base) 706 { 707 int ptn_base = ext_base + le32toh(dp->mbrp_start); 708 709 if (dp->mbrp_type != MBR_PTYPE_NETBSD) 710 return SCAN_CONTINUE; 711 712 return validate_label(a, ptn_base); 713 } 714