xref: /netbsd-src/sys/arch/macppc/macppc/disksubr.c (revision 1149feacd20e1210be630f7b5af031686219362e)
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
getFreeLabelEntry(struct disklabel * lp)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
whichType(struct part_map_entry * part,u_int8_t * fstype,int * clust)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
setpartition(struct part_map_entry * part,struct partition * pp,int fstype)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
getNamedType(struct part_map_entry * part,int num_parts,struct disklabel * lp,int type,int alt,int * maxslot)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 *
read_mac_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)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 *
read_bsd_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)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 *
read_dos_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)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
get_netbsd_label(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)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 *
readdisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)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
setdisklabel(struct disklabel * olp,struct disklabel * nlp,u_long openmask,struct cpu_disklabel * osdep)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
writedisklabel(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep)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