1/* $NetBSD: disksubr.c,v 1.50 2022/08/13 09:34:47 martin 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 * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, 35 * Michael L. Finch, Bradley A. Grantham, and 36 * Lawrence A. Kesteloot 37 * All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the Alice Group. 50 * 4. The names of the Alice Group or any of its members may not be used 51 * to endorse or promote products derived from this software without 52 * specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR 55 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 56 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 57 * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, 58 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 59 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 60 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 61 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 62 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 63 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 64 * 65 */ 66/* 67 * Copyright (C) 1996 Wolfgang Solfrank. 68 * Copyright (C) 1996 TooLs GmbH. 69 * All rights reserved. 70 * 71 * Redistribution and use in source and binary forms, with or without 72 * modification, are permitted provided that the following conditions 73 * are met: 74 * 1. Redistributions of source code must retain the above copyright 75 * notice, this list of conditions and the following disclaimer. 76 * 2. Redistributions in binary form must reproduce the above copyright 77 * notice, this list of conditions and the following disclaimer in the 78 * documentation and/or other materials provided with the distribution. 79 * 3. All advertising materials mentioning features or use of this software 80 * must display the following acknowledgement: 81 * This product includes software developed by TooLs GmbH. 82 * 4. The name of TooLs GmbH may not be used to endorse or promote products 83 * derived from this software without specific prior written permission. 84 * 85 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 86 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 87 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 88 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 89 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 90 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 91 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 92 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 93 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 94 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 95 */ 96 97/* rewritten, 2-5-93 MLF */ 98/* its alot cleaner now, and adding support for new partition types 99 * is possible without causing serious brain-damage 100 * known bugs: 101 * 1) when only an HFS_PART part exists on a drive it gets assigned to "B" 102 * this is because of line 623 of sd.c, I think this line should go. 103 * 2) /sbin/disklabel expects the whole disk to be in "D", we put it in 104 * "C" (I think) and we don't set that position in the disklabel structure 105 * as used. Again, not my fault. 106 */ 107 108#include <sys/cdefs.h> 109__KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.50 2022/08/13 09:34:47 martin Exp $"); 110 111#include <sys/param.h> 112#include <sys/systm.h> 113#include <sys/buf.h> 114#include <sys/conf.h> 115#include <sys/disk.h> 116#include <sys/disklabel.h> 117#include <sys/bootblock.h> 118#include <sys/syslog.h> 119 120#include <sys/bswap.h> 121 122#define NUM_PARTS 32 123 124#define ROOT_PART 1 125#define UFS_PART 2 126#define SWAP_PART 3 127#define HFS_PART 4 128#define SCRATCH_PART 5 129 130static int getFreeLabelEntry(struct disklabel *); 131static int whichType(struct part_map_entry *, u_int8_t *, int *); 132static void setpartition(struct part_map_entry *, 133 struct partition *, int); 134static int getNamedType(struct part_map_entry *, int, 135 struct disklabel *, int, int, int *); 136static const char *read_mac_label(dev_t, void (*)(struct buf *), 137 struct disklabel *, struct cpu_disklabel *); 138static const char *read_dos_label(dev_t, void (*)(struct buf *), 139 struct disklabel *, struct cpu_disklabel *); 140static const char *read_bsd_label(dev_t, void (*)(struct buf *), 141 struct disklabel *, struct cpu_disklabel *); 142static int get_netbsd_label(dev_t, void (*)(struct buf *), 143 struct disklabel *, struct cpu_disklabel *); 144 145/* 146 * Find an entry in the disk label that is unused and return it 147 * or -1 if no entry 148 */ 149static int 150getFreeLabelEntry(struct disklabel *lp) 151{ 152 int i = 0; 153 154 for (i = 0; i < MAXPARTITIONS; i++) { 155 if ((i != RAW_PART) 156 && (lp->d_partitions[i].p_fstype == FS_UNUSED)) 157 return i; 158 } 159 160 return -1; 161} 162 163/* 164 * figure out what the type of the given part is and return it 165 */ 166static int 167whichType(struct part_map_entry *part, u_int8_t *fstype, int *clust) 168{ 169 struct blockzeroblock *bzb; 170 char typestr[32], *s; 171 int type; 172 173 /* Set default unix partition type. Certain partition types can 174 * specify a different partition type. */ 175 *fstype = FS_OTHER; 176 *clust = 0; /* only A/UX partitions not in cluster 0 */ 177 178 if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0') 179 return 0; 180 181 strncpy(typestr, (char *)part->pmPartType, sizeof(typestr)); 182 typestr[sizeof(typestr) - 1] = '\0'; 183 for (s = typestr; *s; s++) 184 if ((*s >= 'a') && (*s <= 'z')) 185 *s = (*s - 'a' + 'A'); 186 187 if (strncmp(PART_TYPE_DRIVER, typestr, strlen(PART_TYPE_DRIVER)) == 0 || 188 strcmp(PART_TYPE_DRIVER43, typestr) == 0 || 189 strcmp(PART_TYPE_DRIVERATA, typestr) == 0 || 190 strcmp(PART_TYPE_DRIVERIOKIT, typestr) == 0 || 191 strcmp(PART_TYPE_FWDRIVER, typestr) == 0 || 192 strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 || 193 strcmp(PART_TYPE_PARTMAP, typestr) == 0 || 194 strcmp(PART_TYPE_PATCHES, typestr) == 0) 195 type = 0; 196 else if (strcmp(PART_TYPE_NBSD_PPCBOOT, typestr) == 0) { 197 type = ROOT_PART; 198 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 199 if ((bzb->bzbMagic == BZB_MAGIC) && 200 (bzb->bzbType < FSMAXTYPES)) 201 *fstype = bzb->bzbType; 202 else 203 *fstype = FS_BSDFFS; 204 } else if (strcmp(PART_TYPE_NETBSD, typestr) == 0 || 205 strcmp(PART_TYPE_NBSD_68KBOOT, typestr) == 0) { 206 type = UFS_PART; 207 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 208 if ((bzb->bzbMagic == BZB_MAGIC) && 209 (bzb->bzbType < FSMAXTYPES)) 210 *fstype = bzb->bzbType; 211 else 212 *fstype = FS_BSDFFS; 213 } else if (strcmp(PART_TYPE_UNIX, typestr) == 0) { 214 /* unix part, swap, root, usr */ 215 bzb = (struct blockzeroblock *)(&part->pmBootArgs); 216 *clust = bzb->bzbCluster; 217 if (bzb->bzbMagic != BZB_MAGIC) { 218 type = 0; 219 } else if (bzb->bzbFlags & BZB_ROOTFS) { 220 type = ROOT_PART; 221 *fstype = FS_BSDFFS; 222 } else if (bzb->bzbFlags & (BZB_USRFS | BZB_USRFS_NEW)) { 223 type = UFS_PART; 224 *fstype = FS_BSDFFS; 225 } else if (bzb->bzbType == BZB_TYPESWAP) { 226 type = SWAP_PART; 227 *fstype = FS_SWAP; 228 } else { 229 type = SCRATCH_PART; 230 *fstype = FS_OTHER; 231 } 232 } else if (strcmp(PART_TYPE_MAC, typestr) == 0) { 233 type = HFS_PART; 234 *fstype = FS_HFS; 235 } else if (strcmp(PART_TYPE_APPLEUFS, typestr) == 0) { 236 type = SCRATCH_PART; 237 *fstype = FS_APPLEUFS; 238 } else if (strcmp(PART_TYPE_LINUX, typestr) == 0) { 239 type = SCRATCH_PART; 240 *fstype = FS_OTHER; 241 } else if (strcmp(PART_TYPE_LINUX_SWAP, typestr) == 0) { 242 type = SCRATCH_PART; 243 *fstype = FS_OTHER; 244 } else { 245 type = SCRATCH_PART; /* no known type */ 246 *fstype = FS_OTHER; 247 } 248 249 return type; 250} 251 252static void 253setpartition(struct part_map_entry *part, struct partition *pp, int fstype) 254{ 255 pp->p_size = part->pmPartBlkCnt; 256 pp->p_offset = part->pmPyPartStart; 257 pp->p_fstype = fstype; 258 259 part->pmPartType[0] = '\0'; 260} 261 262static int 263getNamedType(struct part_map_entry *part, int num_parts, struct disklabel *lp, int type, int alt, int *maxslot) 264{ 265 int i = 0, clust; 266 u_int8_t realtype; 267 268 for (i = 0; i < num_parts; i++) { 269 if (whichType(part + i, &realtype, &clust) != type) 270 continue; 271 272 if (type == ROOT_PART) { 273 if (alt >= 0 && alt != clust) 274 continue; 275 setpartition(part + i, &lp->d_partitions[0], realtype); 276 } else if (type == UFS_PART) { 277 if (alt >= 0 && alt != clust) 278 continue; 279 setpartition(part + i, &lp->d_partitions[6], realtype); 280 if (*maxslot < 6) 281 *maxslot = 6; 282 } else if (type == SWAP_PART) { 283 setpartition(part + i, &lp->d_partitions[1], realtype); 284 if (*maxslot < 1) 285 *maxslot = 1; 286 } else if (type == HFS_PART) { 287 setpartition(part + i, &lp->d_partitions[3], realtype); 288 if (*maxslot < 3) 289 *maxslot = 3; 290 } else 291 printf("disksubr.c: can't do type %d\n", type); 292 293 return 0; 294 } 295 296 return -1; 297} 298 299/* 300 * MF -- 301 * here's what i'm gonna do: 302 * read in the entire diskpartition table, it may be bigger or smaller 303 * than NUM_PARTS but read that many entries. Each entry has a magic 304 * number so we'll know if an entry is crap. 305 * next fill in the disklabel with info like this 306 * next fill in the root, usr, and swap parts. 307 * then look for anything else and fit it in. 308 * A: root 309 * B: Swap 310 * C: Whole disk 311 * G: Usr 312 * 313 * 314 * I'm not entirely sure what netbsd386 wants in c & d 315 * 386bsd wants other stuff, so i'll leave them alone 316 * 317 * AKB -- I added to Mike's original algorithm by searching for a bzbCluster 318 * of zero for root, first. This allows A/UX to live on cluster 1 and 319 * NetBSD to live on cluster 0--regardless of the actual order on the 320 * disk. This whole algorithm should probably be changed in the future. 321 */ 322static const char * 323read_mac_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) 324{ 325 struct part_map_entry *part; 326 struct partition *pp; 327 struct buf *bp; 328 const char *msg = NULL; 329 int i, slot, maxslot = 0, clust; 330 u_int8_t realtype; 331 332 /* get buffer and initialize it */ 333 bp = geteblk((int)lp->d_secsize * NUM_PARTS); 334 bp->b_dev = dev; 335 336 /* read partition map */ 337 bp->b_blkno = 1; /* partition map starts at blk 1 */ 338 bp->b_bcount = lp->d_secsize * NUM_PARTS; 339 bp->b_flags |= B_READ; 340 bp->b_cylinder = 1 / lp->d_secpercyl; 341 (*strat)(bp); 342 343 if (biowait(bp)) { 344 msg = "Macintosh partition map I/O error"; 345 goto done; 346 } 347 348 part = (struct part_map_entry *)bp->b_data; 349 350 /* Fill in standard partitions */ 351 lp->d_npartitions = RAW_PART + 1; 352 if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot)) 353 getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot); 354 if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot)) 355 getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot); 356 getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot); 357 getNamedType(part, NUM_PARTS, lp, HFS_PART, -1, &maxslot); 358 359 /* Now get as many of the rest of the partitions as we can */ 360 for (i = 0; i < NUM_PARTS; i++) { 361 slot = getFreeLabelEntry(lp); 362 if (slot < 0) 363 break; 364 365 pp = &lp->d_partitions[slot]; 366 367 /* 368 * Additional ROOT_PART will turn into a plain old 369 * UFS_PART partition, live with it. 370 */ 371 372 if (whichType(part + i, &realtype, &clust)) { 373 setpartition(part + i, pp, realtype); 374 } else { 375 slot = 0; 376 } 377 if (slot > maxslot) 378 maxslot = slot; 379 } 380 lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1; 381 382done: 383 brelse(bp, 0); 384 return msg; 385} 386 387/* 388 * Scan the disk buffer in four byte strides for a native BSD 389 * disklabel (different ports have variably-sized bootcode before 390 * the label) 391 */ 392static const char * 393read_bsd_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, 394 struct cpu_disklabel *osdep) 395{ 396 struct disklabel *dlp; 397 struct buf *bp; 398 const char *msg; 399 struct disklabel *blk_start, *blk_end; 400 int size, match; 401 402 msg = NULL; 403 404 /* 405 * Read in the first #(NUM_PARTS + 1) blocks of the disk. 406 * The native Macintosh partition table starts at 407 * sector #1, but we want #0 too for the BSD label. 408 */ 409 size = roundup((NUM_PARTS + 1) << DEV_BSHIFT, lp->d_secsize); 410 bp = geteblk(size); 411 412 bp->b_dev = dev; 413 bp->b_blkno = 0; 414 bp->b_resid = 0; 415 bp->b_bcount = size; 416 bp->b_flags |= B_READ; 417 bp->b_cylinder = 1 / lp->d_secpercyl; 418 (*strat)(bp); 419 420 match = 0; 421 422 if (biowait(bp)) { 423 msg = "I/O error reading BSD disklabel"; 424 } else { 425 /* 426 * Hunt the label, starting at the beginning of the disk. 427 * When we find an inconsistent label, report and continue. 428 */ 429 blk_start = (struct disklabel *)bp->b_data; 430 blk_end = (struct disklabel *)((char *)bp->b_data + 431 (NUM_PARTS << DEV_BSHIFT) - sizeof(struct disklabel)); 432 433 for (dlp = blk_start; dlp <= blk_end; 434 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 435 if (dlp->d_magic == DISKMAGIC && 436 dlp->d_magic2 == DISKMAGIC) { 437 /* Sanity check */ 438 if (dlp->d_npartitions <= MAXPARTITIONS && 439 dkcksum(dlp) == 0) { 440 *lp = *dlp; 441 match = -1; 442 break; 443#ifdef DIAGNOSTIC 444 } else { 445 printf("read_bsd_label() found " 446 "damaged disklabel starting at " 447 "0x0%p, ignore\n", dlp); 448#endif /* DIAGNOSTIC */ 449 } 450 } 451 } 452 if (!match) 453 msg = "BSD disklabel not found"; 454 } 455 brelse(bp, 0); 456 return msg; 457} 458 459/* Read MS-DOS partition table. 460 * 461 * XXX - 462 * Since FFS is endian sensitive, we pay no effort in attempting to 463 * dig up *BSD/i386 disk labels that may be present on the disk. 464 * Hence anything but DOS partitions is treated as unknown FS type, but 465 * this should suffice to mount_msdos Zip and other removable media. 466 */ 467static const char * 468read_dos_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) 469{ 470 struct mbr_partition *dp; 471 struct buf *bp; 472 const char *msg = NULL; 473 int i, slot, maxslot = 0; 474 u_int32_t bsdpartoff; 475 struct mbr_partition *bsdp; 476 477 /* get a buffer and initialize it */ 478 bp = geteblk((int)lp->d_secsize); 479 bp->b_dev = dev; 480 481 /* read master boot record */ 482 bp->b_blkno = MBR_BBSECTOR; 483 bp->b_bcount = lp->d_secsize; 484 bp->b_flags |= B_READ; 485 bp->b_cylinder = MBR_BBSECTOR / lp->d_secpercyl; 486 (*strat)(bp); 487 488 bsdpartoff = 0; 489 490 /* if successful, wander through dos partition table */ 491 if (biowait(bp)) { 492 msg = "dos partition I/O error"; 493 goto done; 494 } 495 /* XXX */ 496 dp = (struct mbr_partition *)((char *)bp->b_data + MBR_PART_OFFSET); 497 bsdp = NULL; 498 for (i = 0; i < MBR_PART_COUNT; i++, dp++) { 499 switch (dp->mbrp_type) { 500 case MBR_PTYPE_PMBR: 501 goto done; /* do not fake anything for GPT disks */ 502 case MBR_PTYPE_NETBSD: 503 bsdp = dp; 504 break; 505 case MBR_PTYPE_OPENBSD: 506 case MBR_PTYPE_386BSD: 507 if (!bsdp) 508 bsdp = dp; 509 break; 510 } 511 } 512 if (!bsdp) { 513 /* generate fake disklabel */ 514 dp = (struct mbr_partition *)((char *)bp->b_data + 515 MBR_PART_OFFSET); 516 for (i = 0; i < MBR_PART_COUNT; i++, dp++) { 517 if (!dp->mbrp_type) 518 continue; 519 slot = getFreeLabelEntry(lp); 520 if (slot < 0) 521 break; 522 if (slot > maxslot) 523 maxslot = slot; 524 525 lp->d_partitions[slot].p_offset = bswap32(dp->mbrp_start); 526 lp->d_partitions[slot].p_size = bswap32(dp->mbrp_size); 527 528 switch (dp->mbrp_type) { 529 case MBR_PTYPE_FAT12: 530 case MBR_PTYPE_FAT16S: 531 case MBR_PTYPE_FAT16B: 532 case MBR_PTYPE_FAT32: 533 case MBR_PTYPE_FAT32L: 534 case MBR_PTYPE_FAT16L: 535 lp->d_partitions[slot].p_fstype = FS_MSDOS; 536 break; 537 default: 538 lp->d_partitions[slot].p_fstype = FS_OTHER; 539 break; 540 } 541 } 542 msg = "no NetBSD disk label"; 543 } else { 544 /* NetBSD partition on MBR */ 545 bsdpartoff = bswap32(bsdp->mbrp_start); 546 547 lp->d_partitions[2].p_size = bswap32(bsdp->mbrp_size); 548 lp->d_partitions[2].p_offset = bswap32(bsdp->mbrp_start); 549 if (2 > maxslot) 550 maxslot = 2; 551 /* read in disklabel, blkno + 1 for DOS disklabel offset */ 552 osdep->cd_labelsector = bsdpartoff + MBR_LABELSECTOR; 553 osdep->cd_labeloffset = MBR_LABELOFFSET; 554 if (get_netbsd_label(dev, strat, lp, osdep)) 555 goto done; 556 msg = "no NetBSD disk label"; 557 } 558 559 lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1; 560 561 done: 562 brelse(bp, 0); 563 return (msg); 564} 565 566/* 567 * Get real NetBSD disk label 568 */ 569static int 570get_netbsd_label(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) 571{ 572 struct buf *bp; 573 struct disklabel *dlp; 574 575 /* get a buffer and initialize it */ 576 bp = geteblk((int)lp->d_secsize); 577 bp->b_dev = dev; 578 579 /* Now get the label block */ 580 bp->b_blkno = osdep->cd_labelsector; 581 bp->b_bcount = lp->d_secsize; 582 bp->b_flags |= B_READ; 583 bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 584 (*strat)(bp); 585 586 if (biowait(bp)) 587 goto done; 588 589 for (dlp = (struct disklabel *)((char *)bp->b_data + 590 osdep->cd_labeloffset); 591 dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - 592 sizeof (*dlp)); 593 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { 594 if (dlp->d_magic == DISKMAGIC 595 && dlp->d_magic2 == DISKMAGIC 596 && dlp->d_npartitions <= MAXPARTITIONS 597 && dkcksum(dlp) == 0) { 598 *lp = *dlp; 599 osdep->cd_labeloffset = (char *)dlp - 600 (char *)bp->b_data; 601 brelse(bp, 0); 602 return 1; 603 } 604 } 605done: 606 brelse(bp, 0); 607 return 0; 608} 609 610/* 611 * Attempt to read a disk label from a device using the indicated strategy 612 * routine. The label must be partly set up before this: secpercyl and 613 * anything required in the strategy routine (e.g., sector size) must be 614 * filled in before calling us. Returns null on success and an error 615 * string on failure. 616 * 617 * This will read sector zero. If this contains what looks like a valid 618 * Macintosh boot sector, we attempt to fill in the disklabel structure. 619 * If the first longword of the disk is a NetBSD disk label magic number, 620 * then we assume that it's a real disklabel and return it. 621 */ 622const char * 623readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) 624{ 625 struct buf *bp; 626 const char *msg = NULL; 627 628 if (lp->d_secperunit == 0) 629 lp->d_secperunit = 0x1fffffff; 630 631 if (lp->d_secpercyl == 0) { 632 return msg = "Zero secpercyl"; 633 } 634 bp = geteblk((int)lp->d_secsize); 635 636 bp->b_dev = dev; 637 bp->b_blkno = 0; 638 bp->b_resid = 0; 639 bp->b_bcount = lp->d_secsize; 640 bp->b_flags |= B_READ; 641 bp->b_cylinder = 1 / lp->d_secpercyl; 642 (*strat)(bp); 643 644 osdep->cd_start = -1; 645 646 /* XXX cd_start is abused as a flag for fictious disklabel */ 647 648 if (biowait(bp)) { 649 msg = "I/O error reading block zero"; 650 goto done; 651 } 652 osdep->cd_labelsector = LABELSECTOR; 653 osdep->cd_labeloffset = LABELOFFSET; 654 if (get_netbsd_label(dev, strat, lp, osdep)) 655 osdep->cd_start = 0; 656 else { 657 u_int16_t *sbSigp; 658 659 sbSigp = (u_int16_t *)bp->b_data; 660 if (*sbSigp == 0x4552) { 661 /* it ignores labelsector/offset */ 662 msg = read_mac_label(dev, strat, lp, osdep); 663 /* the disklabel is fictious */ 664 } else if (bswap16(*(u_int16_t *)((char *)bp->b_data + 665 MBR_MAGIC_OFFSET)) == MBR_MAGIC) { 666 /* read_dos_label figures out labelsector/offset */ 667 msg = read_dos_label(dev, strat, lp, osdep); 668 if (!msg) 669 osdep->cd_start = 0; 670 } else { 671 msg = read_bsd_label(dev, strat, lp, osdep); 672 if (!msg) 673 osdep->cd_start = 0; /* XXX for now */ 674 } 675 } 676 677done: 678 brelse(bp, 0); 679 return (msg); 680} 681 682/* 683 * Check new disk label for sensibility before setting it. 684 */ 685int 686setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask, struct cpu_disklabel *osdep) 687{ 688 /* sanity clause */ 689 if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 690 || (nlp->d_secsize % DEV_BSIZE) != 0) 691 return EINVAL; 692 693 /* special case to allow disklabel to be invalidated */ 694 if (nlp->d_magic == 0xffffffff) { 695 *olp = *nlp; 696 return 0; 697 } 698 699 if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC 700 || dkcksum(nlp) != 0) 701 return EINVAL; 702 703 /* openmask parameter ignored */ 704 705 *olp = *nlp; 706 return 0; 707} 708 709/* 710 * Write disk label back to device after modification. 711 */ 712int 713writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *osdep) 714{ 715 struct buf *bp; 716 int error; 717 struct disklabel label; 718 719 /* 720 * Try to re-read a disklabel, in case he changed the MBR. 721 */ 722 label = *lp; 723 readdisklabel(dev, strat, &label, osdep); 724 if (osdep->cd_start < 0) 725 return EINVAL; 726 727 /* get a buffer and initialize it */ 728 bp = geteblk(lp->d_secsize); 729 bp->b_dev = dev; 730 731 bp->b_blkno = osdep->cd_start + osdep->cd_labelsector; 732 bp->b_cylinder = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) / lp->d_secpercyl; 733 bp->b_bcount = lp->d_secsize; 734 735 bp->b_flags |= B_READ; 736 (*strat)(bp); 737 error = biowait(bp); 738 if (error != 0) 739 goto done; 740 741 bp->b_flags &= ~B_READ; 742 bp->b_flags |= B_WRITE; 743 bp->b_oflags &= ~BO_DONE; 744 745 memcpy((char *)bp->b_data + osdep->cd_labeloffset, (void *)lp, 746 sizeof *lp); 747 748 (*strat)(bp); 749 error = biowait(bp); 750 751done: 752 brelse(bp, 0); 753 754 return error; 755} 756