Home | History | Annotate | Line # | Download | only in mac68k
      1 /*	$NetBSD: disksubr.c,v 1.58 2019/04/03 22:10:50 christos 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 #include <sys/cdefs.h>
     68 __KERNEL_RCSID(0, "$NetBSD: disksubr.c,v 1.58 2019/04/03 22:10:50 christos Exp $");
     69 
     70 #include <sys/param.h>
     71 #include <sys/systm.h>
     72 #include <sys/buf.h>
     73 #include <sys/disk.h>
     74 #include <sys/disklabel.h>
     75 #include <sys/bootblock.h>
     76 #include <sys/syslog.h>
     77 
     78 #include <sys/bswap.h>
     79 
     80 #define NUM_PARTS 32
     81 
     82 #define ROOT_PART 1
     83 #define UFS_PART 2
     84 #define SWAP_PART 3
     85 #define HFS_PART 4
     86 #define SCRATCH_PART 5
     87 
     88 int fat_types[] = {
     89 	MBR_PTYPE_FAT12, MBR_PTYPE_FAT16S,
     90 	MBR_PTYPE_FAT16B, MBR_PTYPE_FAT32,
     91 	MBR_PTYPE_FAT32L, MBR_PTYPE_FAT16L,
     92 	-1
     93 };
     94 
     95 static int getFreeLabelEntry(struct disklabel *);
     96 static int whichType(struct part_map_entry *);
     97 static void setpartition(struct part_map_entry *, struct partition *, int);
     98 static int getNamedType(struct part_map_entry *, int, struct disklabel *, int,
     99 	    int, int *);
    100 static char *read_mac_label(char *, struct disklabel *, int *);
    101 static char *read_mbr_label(char *, struct disklabel *, int *);
    102 static const char *read_bsd_label(char *, struct disklabel *, int *);
    103 
    104 
    105 /*
    106  * Find an entry in the disk label that is unused and return it
    107  * or -1 if no entry
    108  */
    109 static int
    110 getFreeLabelEntry(struct disklabel *lp)
    111 {
    112 	int i;
    113 
    114 	for (i = 0; i < MAXPARTITIONS; i++) {
    115 		if ((i != RAW_PART)
    116 		    && (lp->d_partitions[i].p_fstype == FS_UNUSED))
    117 			return i;
    118 	}
    119 	return -1;
    120 }
    121 
    122 /*
    123  * figure out what the type of the given part is and return it
    124  */
    125 static int
    126 whichType(struct part_map_entry *part)
    127 {
    128 	struct blockzeroblock *bzb;
    129 	char typestr[32], *s;
    130 	int type;
    131 
    132 	if (part->pmSig != PART_ENTRY_MAGIC || part->pmPartType[0] == '\0')
    133 		return 0;
    134 
    135 	strncpy(typestr, (char *)part->pmPartType, sizeof(typestr));
    136 	typestr[sizeof(typestr) - 1] = '\0';
    137 	for (s = typestr; *s; s++)
    138 		if ((*s >= 'a') && (*s <= 'z'))
    139 			*s = (*s - 'a' + 'A');
    140 
    141 	if (strcmp(PART_TYPE_DRIVER, typestr) == 0 ||
    142 	    strcmp(PART_TYPE_DRIVER43, typestr) == 0 ||
    143 	    strcmp(PART_TYPE_DRIVERATA, typestr) == 0 ||
    144 	    strcmp(PART_TYPE_FWB_COMPONENT, typestr) == 0 ||
    145 	    strcmp(PART_TYPE_PARTMAP, typestr) == 0)
    146 		type = 0;
    147 	else if (strcmp(PART_TYPE_UNIX, typestr) == 0) {
    148 		/* unix part, swap, root, usr */
    149 		bzb = (struct blockzeroblock *)(&part->pmBootArgs);
    150 		if (bzb->bzbMagic != BZB_MAGIC)
    151 			type = 0;
    152 		else if (bzb->bzbFlags & BZB_ROOTFS)
    153 			type = ROOT_PART;
    154 		else if (bzb->bzbFlags & BZB_USRFS)
    155 			type = UFS_PART;
    156 		else if (bzb->bzbType == BZB_TYPESWAP)
    157 			type = SWAP_PART;
    158 		else
    159 			type = SCRATCH_PART;
    160 	} else if (strcmp(PART_TYPE_MAC, typestr) == 0)
    161 		type = HFS_PART;
    162 	else
    163 		type = SCRATCH_PART;	/* no known type */
    164 
    165 	return type;
    166 }
    167 
    168 static void
    169 setpartition(struct part_map_entry *part, struct partition *pp, int fstype)
    170 {
    171 	pp->p_size = part->pmPartBlkCnt;
    172 	pp->p_offset = part->pmPyPartStart;
    173 	pp->p_fstype = fstype;
    174 
    175 	part->pmPartType[0] = '\0';
    176 }
    177 
    178 static int
    179 getNamedType(struct part_map_entry *part, int num_parts, struct disklabel *lp,
    180     int type, int alt, int *maxslot)
    181 {
    182 	struct blockzeroblock *bzb;
    183 	int i;
    184 
    185 	for (i = 0; i < num_parts; i++) {
    186 		if (whichType(part + i) != type)
    187 			continue;
    188 
    189 		if (type == ROOT_PART) {
    190 			bzb = (struct blockzeroblock *)
    191 			    (&(part + i)->pmBootArgs);
    192 			if (alt >= 0 && alt != bzb->bzbCluster)
    193 				continue;
    194 			setpartition(part + i, &lp->d_partitions[0], FS_BSDFFS);
    195 		} else if (type == UFS_PART) {
    196 			bzb = (struct blockzeroblock *)
    197 			    (&(part + i)->pmBootArgs);
    198 			if (alt >= 0 && alt != bzb->bzbCluster)
    199 				continue;
    200 			setpartition(part + i, &lp->d_partitions[6], FS_BSDFFS);
    201 			if (*maxslot < 6)
    202 				*maxslot = 6;
    203 		} else if (type == SWAP_PART) {
    204 			setpartition(part + i, &lp->d_partitions[1], FS_SWAP);
    205 			if (*maxslot < 1)
    206 				*maxslot = 1;
    207 		} else
    208 			printf("disksubr.c: can't do type %d\n", type);
    209 
    210 		return 0;
    211 	}
    212 
    213 	return -1;
    214 }
    215 
    216 /*
    217  * MF --
    218  * here's what i'm gonna do:
    219  * read in the entire diskpartition table, it may be bigger or smaller
    220  * than NUM_PARTS but read that many entries.  Each entry has a magic
    221  * number so we'll know if an entry is crap.
    222  * next fill in the disklabel with info like this
    223  * next fill in the root, usr, and swap parts.
    224  * then look for anything else and fit it in.
    225  *	A: root
    226  *	B: Swap
    227  *	C: Whole disk
    228  *	G: Usr
    229  *
    230  *
    231  * I'm not entirely sure what netbsd386 wants in c & d
    232  * 386bsd wants other stuff, so i'll leave them alone
    233  *
    234  * AKB -- I added to Mike's original algorithm by searching for a bzbCluster
    235  *	of zero for root, first.  This allows A/UX to live on cluster 1 and
    236  *	NetBSD to live on cluster 0--regardless of the actual order on the
    237  *	disk.  This whole algorithm should probably be changed in the future.
    238  */
    239 
    240 /*
    241  * This uses sector zero.  If this contains what looks like a valid
    242  * Macintosh boot sector, we attempt to fill in the disklabel structure
    243  * with the partition data from block #1 on.
    244  */
    245 static char *
    246 read_mac_label(char *dlbuf, struct disklabel *lp, int *match)
    247 {
    248 	u_int16_t *sbSigp;
    249 	struct part_map_entry *part;
    250 	struct partition *pp;
    251 	char *msg;
    252 	int i, slot, maxslot;
    253 
    254 	maxslot = 0;
    255 	*match = 0;
    256 	msg = NULL;
    257 
    258 	sbSigp = (u_int16_t *)dlbuf;
    259 	if (*sbSigp != DRIVER_MAP_MAGIC)
    260 		return msg;
    261 
    262 	/* Found Macintosh partition magic number; set up disklabel */
    263 	*match = (-1);
    264 
    265 	/* the Macintosh partition table starts at sector #1 */
    266 	part = (struct part_map_entry *)(dlbuf + DEV_BSIZE);
    267 
    268 	/* Fill in standard partitions */
    269 	lp->d_npartitions = RAW_PART + 1;
    270 	if (getNamedType(part, NUM_PARTS, lp, ROOT_PART, 0, &maxslot))
    271 		getNamedType(part, NUM_PARTS, lp, ROOT_PART, -1, &maxslot);
    272 	if (getNamedType(part, NUM_PARTS, lp, UFS_PART, 0, &maxslot))
    273 		getNamedType(part, NUM_PARTS, lp, UFS_PART, -1, &maxslot);
    274 	getNamedType(part, NUM_PARTS, lp, SWAP_PART, -1, &maxslot);
    275 
    276 	/* Now get as many of the rest of the partitions as we can */
    277 	for (i = 0; i < NUM_PARTS; i++) {
    278 		slot = getFreeLabelEntry(lp);
    279 		if (slot < 0)
    280 			break;
    281 
    282 		pp = &lp->d_partitions[slot];
    283 
    284 		switch (whichType(part + i)) {
    285 		case ROOT_PART:
    286 		/*
    287 		 * another root part will turn into a plain old
    288 		 * UFS_PART partition, live with it.
    289 		 */
    290 		case UFS_PART:
    291 			setpartition(part + i, pp, FS_BSDFFS);
    292 			break;
    293 		case SWAP_PART:
    294 			setpartition(part + i, pp, FS_SWAP);
    295 			break;
    296 		case HFS_PART:
    297 			setpartition(part + i, pp, FS_HFS);
    298 			break;
    299 		case SCRATCH_PART:
    300 			setpartition(part + i, pp, FS_OTHER);
    301 			break;
    302 		default:
    303 			slot = 0;
    304 			break;
    305 		}
    306 		if (slot > maxslot)
    307 			maxslot = slot;
    308 	}
    309 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
    310 	return msg;
    311 }
    312 
    313 /*
    314  * Scan the disk buffer for a DOS style master boot record.
    315  * Return if no match; otherwise, set up an in-core disklabel .
    316  *
    317  * XXX stuff like this really should be MI
    318  *
    319  * Since FFS is endian sensitive, we pay no effort in attempting to
    320  * dig up *BSD/i386 disk labels that may be present on the disk.
    321  * Hence anything but DOS partitions is treated as unknown FS type, but
    322  * this should suffice to mount_msdos Zip and other removable media.
    323  */
    324 static char *
    325 read_mbr_label(char *dlbuf, struct disklabel *lp, int *match)
    326 {
    327 	struct mbr_partition *dp;
    328 	struct partition *pp;
    329 	char *msg;
    330 	size_t mbr_lbl_off;
    331 	int i, *ip, slot, maxslot;
    332 
    333 	maxslot = 0;
    334 	*match = 0;
    335 	msg = NULL;
    336 
    337 	if (MBR_MAGIC != bswap16(*(u_int16_t *)(dlbuf + MBR_MAGIC_OFFSET)))
    338 		return msg;
    339 
    340 	/* Found MBR magic number; set up disklabel */
    341 	*match = (-1);
    342 	mbr_lbl_off = MBR_BBSECTOR * lp->d_secsize + MBR_PART_OFFSET;
    343 
    344 	dp = (struct mbr_partition *)(dlbuf + mbr_lbl_off);
    345 	for (i = 0; i < MBR_PART_COUNT; i++, dp++) {
    346 		if (dp->mbrp_type == 0)
    347 			continue;
    348 
    349 		slot = getFreeLabelEntry(lp);
    350 		maxslot = (slot > maxslot) ? maxslot : slot;
    351 
    352 		pp = &lp->d_partitions[slot];
    353 		pp->p_fstype = FS_OTHER;
    354 		pp->p_offset = bswap32(dp->mbrp_start);
    355 		pp->p_size = bswap32(dp->mbrp_size);
    356 
    357 		for (ip = fat_types; *ip != -1; ip++) {
    358 			if (dp->mbrp_type == *ip) {
    359 				pp->p_fstype = FS_MSDOS;
    360 				break;
    361 			}
    362 		}
    363 	}
    364 	lp->d_npartitions = ((maxslot >= RAW_PART) ? maxslot : RAW_PART) + 1;
    365 	return msg;
    366 }
    367 
    368 /*
    369  * Scan the disk buffer in four byte steps for a native BSD disklabel
    370  * (different ports have variable-sized bootcode before the label)
    371  */
    372 static const char *
    373 read_bsd_label(char *dlbuf, struct disklabel *lp, int *match)
    374 {
    375 	struct disklabel *dlp;
    376 	const char *msg;
    377 	struct disklabel *blk_start, *blk_end;
    378 
    379 	*match = 0;
    380 	msg = NULL;
    381 
    382 	blk_start = (struct disklabel *)dlbuf;
    383 	blk_end = (struct disklabel *)(dlbuf + (NUM_PARTS << DEV_BSHIFT) -
    384 	    sizeof(struct disklabel));
    385 
    386 	for (dlp = blk_start; dlp <= blk_end;
    387 	     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    388 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC) {
    389 			/* Sanity check */
    390 			if (dlp->d_npartitions <= MAXPARTITIONS &&
    391 			    dkcksum(dlp) == 0) {
    392 				*lp = *dlp;
    393 				*match = (-1);
    394 			} else
    395 				msg = "Disk label corrupted";
    396 			break;
    397 		}
    398 	}
    399 	return msg;
    400 }
    401 
    402 /*
    403  * Attempt to read a disk label from a device using the indicated strategy
    404  * routine.  The label must be partly set up before this: secpercyl and
    405  * anything required in the strategy routine (e.g., sector size) must be
    406  * filled in before calling us.  Returns null on success and an error
    407  * string on failure.
    408  */
    409 const char *
    410 readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    411     struct cpu_disklabel *osdep)
    412 {
    413 	struct buf *bp;
    414 	const char *msg;
    415 	int size;
    416 
    417 	if (lp->d_secperunit == 0)
    418 		lp->d_secperunit = 0x1fffffff;
    419 
    420 	if (lp->d_secpercyl == 0)
    421 		return msg = "Zero secpercyl";
    422 
    423 	msg = NULL;
    424 
    425 	/*
    426 	 * Read in the first #(NUM_PARTS + 1) blocks of the disk.
    427 	 * The native Macintosh partition table starts at
    428 	 * sector #1, but we want #0 too for the BSD label.
    429 	 */
    430 
    431 	size = roundup((NUM_PARTS + 1) << DEV_BSHIFT, lp->d_secsize);
    432 	bp = geteblk(size);
    433 
    434 	bp->b_dev = dev;
    435 	bp->b_blkno = 0;
    436 	bp->b_resid = 0;
    437 	bp->b_bcount = size;
    438 	bp->b_flags |= B_READ;
    439 	bp->b_cylinder = 1 / lp->d_secpercyl;
    440 	(*strat)(bp);
    441 
    442 	if (biowait(bp)) {
    443 		msg = "I/O error reading block zero";
    444 	} else {
    445 		int match;
    446 
    447 		/* Add any offsets in the table handlers */
    448 		msg = read_mac_label(bp->b_data, lp, &match);
    449 		if (!match && msg == NULL)
    450 			msg = read_mbr_label(bp->b_data, lp, &match);
    451 		if (!match && msg == NULL)
    452 			msg = read_bsd_label(bp->b_data, lp, &match);
    453 		if (!match && msg == NULL)
    454 			msg = "no disk label";
    455 	}
    456 
    457 	brelse(bp, 0);
    458 	return (msg);
    459 }
    460 
    461 /*
    462  * Check new disk label for sensibility before setting it.
    463  */
    464 int
    465 setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
    466     struct cpu_disklabel *osdep)
    467 {
    468 	return 0;
    469 }
    470 
    471 /*
    472  * Write disk label back to device after modification.
    473  *
    474  *  MF - 8-14-93 This function is never called.  It is here just in case
    475  *  we want to write dos disklabels some day. Really!
    476  */
    477 int
    478 writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
    479     struct cpu_disklabel *osdep)
    480 {
    481 #if 0
    482 	struct buf *bp;
    483 	struct disklabel *dlp;
    484 	int labelpart;
    485 	int error = 0;
    486 
    487 	labelpart = DISKPART(dev);
    488 	if (lp->d_partitions[labelpart].p_offset != 0) {
    489 		if (lp->d_partitions[0].p_offset != 0)
    490 			return (EXDEV);	/* not quite right */
    491 		labelpart = 0;
    492 	}
    493 	bp = geteblk((int)lp->d_secsize);
    494 	bp->b_dev = MAKEDISKDEV(major(dev), DISKUNIT(dev), labelpart);
    495 	bp->b_blkno = LABELSECTOR;
    496 	bp->b_bcount = lp->d_secsize;
    497 	bp->b_flags |= B_READ;
    498 	(*strat)(bp);
    499 	if (error = biowait(bp))
    500 		goto done;
    501 	for (dlp = (struct disklabel *)bp->b_data;
    502 	    dlp <= (struct disklabel *)
    503 	    ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
    504 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
    505 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
    506 		    dkcksum(dlp) == 0) {
    507 			*dlp = *lp;
    508 			bp->b_oflags &= ~(BO_DONE);
    509 			bp->b_flags &= ~(B_READ);
    510 			bp->b_flags |= B_WRITE;
    511 			(*strat)(bp);
    512 			error = biowait(bp);
    513 			goto done;
    514 		}
    515 	}
    516 	error = ESRCH;
    517 done:
    518 	brelse(bp, 0);
    519 	return (error);
    520 #else
    521 	int i;
    522 
    523 	/*
    524 	 * Clear and re-analyze the ondisk Apple Disk Partition Map,
    525 	 * then recompute the faked incore disk label. This is necessary
    526 	 * for sysinst, which may have modified the disk layout. We don't
    527 	 * (yet?) support writing real BSD disk labels, so this hack
    528 	 * instead causes the DIOCWDINFO ioctl invoked by sysinst to
    529 	 * update the in-core disk label when it is "written" to disk.
    530 	 * This code was originally developed by Bob Nestor on 9/13/99.
    531 	 */
    532 	lp->d_npartitions = 0;
    533 	for (i = 0; i < MAXPARTITIONS; i++) {
    534 		lp->d_partitions[i].p_fstype = FS_UNUSED;
    535 		lp->d_partitions[i].p_offset = 0;
    536 		if (i != RAW_PART)
    537 			lp->d_partitions[i].p_size = 0;
    538 	}
    539 	return (readdisklabel(dev, strat, lp, osdep) ? EINVAL : 0);
    540 #endif
    541 }
    542