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