Home | History | Annotate | Line # | Download | only in macppc
      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 
    130 static int getFreeLabelEntry(struct disklabel *);
    131 static int whichType(struct part_map_entry *, u_int8_t *, int *);
    132 static void setpartition(struct part_map_entry *,
    133 		struct partition *, int);
    134 static int getNamedType(struct part_map_entry *, int,
    135 		struct disklabel *, int, int, int *);
    136 static const char *read_mac_label(dev_t, void (*)(struct buf *),
    137 		struct disklabel *, struct cpu_disklabel *);
    138 static const char *read_dos_label(dev_t, void (*)(struct buf *),
    139 		struct disklabel *, struct cpu_disklabel *);
    140 static const char *read_bsd_label(dev_t, void (*)(struct buf *),
    141 		struct disklabel *, struct cpu_disklabel *);
    142 static 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  */
    149 static int
    150 getFreeLabelEntry(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  */
    166 static int
    167 whichType(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 
    252 static void
    253 setpartition(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 
    262 static int
    263 getNamedType(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  */
    322 static const char *
    323 read_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 
    382 done:
    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  */
    392 static const char *
    393 read_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  */
    467 static const char *
    468 read_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  */
    569 static int
    570 get_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 	}
    605 done:
    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  */
    622 const char *
    623 readdisklabel(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 
    677 done:
    678 	brelse(bp, 0);
    679 	return (msg);
    680 }
    681 
    682 /*
    683  * Check new disk label for sensibility before setting it.
    684  */
    685 int
    686 setdisklabel(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  */
    712 int
    713 writedisklabel(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 
    751 done:
    752 	brelse(bp, 0);
    753 
    754 	return error;
    755 }
    756