192108Sphk/*-
292108Sphk * Copyright (c) 2002 Poul-Henning Kamp
392108Sphk * Copyright (c) 2002 Networks Associates Technology, Inc.
492108Sphk * All rights reserved.
592108Sphk *
692108Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp
792108Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc.
892108Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
992108Sphk * DARPA CHATS research program.
1092108Sphk *
1192108Sphk * Redistribution and use in source and binary forms, with or without
1292108Sphk * modification, are permitted provided that the following conditions
1392108Sphk * are met:
1492108Sphk * 1. Redistributions of source code must retain the above copyright
1592108Sphk *    notice, this list of conditions and the following disclaimer.
1692108Sphk * 2. Redistributions in binary form must reproduce the above copyright
1792108Sphk *    notice, this list of conditions and the following disclaimer in the
1892108Sphk *    documentation and/or other materials provided with the distribution.
1992108Sphk *
2092108Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2192108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2292108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2392108Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2492108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2592108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2692108Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2792108Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2892108Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2992108Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3092108Sphk * SUCH DAMAGE.
3192108Sphk */
3292108Sphk
33116196Sobrien#include <sys/cdefs.h>
34116196Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/geom/geom_mbr.c 243333 2012-11-20 12:32:18Z jh $");
35116196Sobrien
3692108Sphk#include <sys/param.h>
37107956Sphk#include <sys/errno.h>
38113011Sphk#include <sys/endian.h>
3992108Sphk#include <sys/systm.h>
40219029Snetchild#include <sys/sysctl.h>
4192108Sphk#include <sys/kernel.h>
42138732Sphk#include <sys/fcntl.h>
4392108Sphk#include <sys/malloc.h>
4492108Sphk#include <sys/bio.h>
4592108Sphk#include <sys/lock.h>
4692108Sphk#include <sys/mutex.h>
47140532Spjd#include <sys/md5.h>
48230643Sattilio#include <sys/proc.h>
4992108Sphk
50104292Sphk#include <sys/diskmbr.h>
5192108Sphk#include <sys/sbuf.h>
5292108Sphk#include <geom/geom.h>
5392108Sphk#include <geom/geom_slice.h>
5492108Sphk
55219029SnetchildFEATURE(geom_mbr, "GEOM DOS/MBR partitioning support");
56219029Snetchild
5797075Sphk#define MBR_CLASS_NAME "MBR"
5897075Sphk#define MBREXT_CLASS_NAME "MBREXT"
5992108Sphk
60107956Sphkstatic struct dos_partition historical_bogus_partition_table[NDOSPART] = {
61107956Sphk        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
62107956Sphk        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
63107956Sphk        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
64107956Sphk        { 0x80, 0, 1, 0, DOSPTYP_386BSD, 255, 255, 255, 0, 50000, },
65107956Sphk};
66113286Sphk
67107956Sphkstatic struct dos_partition historical_bogus_partition_table_fixed[NDOSPART] = {
68107956Sphk        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
69107956Sphk        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
70107956Sphk        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
71107956Sphk        { 0x80, 0, 1, 0, DOSPTYP_386BSD, 254, 255, 255, 0, 50000, },
72107956Sphk};
73109101Sphk
7493090Sphkstatic void
75109101Sphkg_mbr_print(int i, struct dos_partition *dp)
76109101Sphk{
77109101Sphk
78109101Sphk	printf("[%d] f:%02x typ:%d", i, dp->dp_flag, dp->dp_typ);
79113286Sphk	printf(" s(CHS):%d/%d/%d", DPCYL(dp->dp_scyl, dp->dp_ssect),
80113286Sphk	    dp->dp_shd, DPSECT(dp->dp_ssect));
81113286Sphk	printf(" e(CHS):%d/%d/%d", DPCYL(dp->dp_ecyl, dp->dp_esect),
82113286Sphk	    dp->dp_ehd, DPSECT(dp->dp_esect));
83109101Sphk	printf(" s:%d l:%d\n", dp->dp_start, dp->dp_size);
84109101Sphk}
85109101Sphk
8692108Sphkstruct g_mbr_softc {
8792108Sphk	int		type [NDOSPART];
88109101Sphk	u_int		sectorsize;
89108393Sphk	u_char		sec0[512];
90140532Spjd	u_char		slicesum[16];
9192108Sphk};
9292108Sphk
93148034Sphk/*
94148034Sphk * XXX: Add gctl_req arg and give good error msgs.
95148034Sphk * XXX: Check that length argument does not bring boot code inside any slice.
96148034Sphk */
9792108Sphkstatic int
98148034Sphkg_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0, int len __unused)
99107956Sphk{
100107956Sphk	int i, error;
101107956Sphk	off_t l[NDOSPART];
102108393Sphk	struct dos_partition ndp[NDOSPART], *dp;
103140532Spjd	MD5_CTX md5sum;
104107956Sphk
105107956Sphk	g_topology_assert();
106107956Sphk
107108393Sphk	if (sec0[0x1fe] != 0x55 && sec0[0x1ff] != 0xaa)
108108393Sphk		return (EBUSY);
109108393Sphk
110108393Sphk	dp = ndp;
111109101Sphk	for (i = 0; i < NDOSPART; i++) {
112113389Sphk		dos_partition_dec(
113108393Sphk		    sec0 + DOSPARTOFF + i * sizeof(struct dos_partition),
114108393Sphk		    dp + i);
115109101Sphk	}
116107956Sphk	if ((!bcmp(dp, historical_bogus_partition_table,
117107956Sphk	    sizeof historical_bogus_partition_table)) ||
118107956Sphk	    (!bcmp(dp, historical_bogus_partition_table_fixed,
119107956Sphk	    sizeof historical_bogus_partition_table_fixed))) {
120107956Sphk		/*
121107956Sphk		 * We will not allow people to write these from "the inside",
122107956Sphk		 * Since properly selfdestructing takes too much code.  If
123107956Sphk		 * people really want to do this, they cannot have any
124107956Sphk		 * providers of this geom open, and in that case they can just
125107956Sphk		 * as easily overwrite the MBR in the parent device.
126107956Sphk		 */
127107956Sphk		return(EBUSY);
128107956Sphk	}
129107956Sphk	for (i = 0; i < NDOSPART; i++) {
130107956Sphk		/*
131107956Sphk		 * A Protective MBR (PMBR) has a single partition of
132107956Sphk		 * type 0xEE spanning the whole disk. Such a MBR
133107956Sphk		 * protects a GPT on the disk from MBR tools that
134107956Sphk		 * don't know anything about GPT. We're interpreting
135107956Sphk		 * it a bit more loosely: any partition of type 0xEE
136107956Sphk		 * is to be skipped as it doesn't contain any data
137107956Sphk		 * that we should care about. We still allow other
138107956Sphk		 * partitions to be present in the MBR. A PMBR will
139107956Sphk		 * be handled correctly anyway.
140107956Sphk		 */
141113030Sphk		if (dp[i].dp_typ == DOSPTYP_PMBR)
142107956Sphk			l[i] = 0;
143107956Sphk		else if (dp[i].dp_flag != 0 && dp[i].dp_flag != 0x80)
144107956Sphk			l[i] = 0;
145107956Sphk		else if (dp[i].dp_typ == 0)
146107956Sphk			l[i] = 0;
147107956Sphk		else
148109101Sphk			l[i] = (off_t)dp[i].dp_size * ms->sectorsize;
149107956Sphk		error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
150109101Sphk		    (off_t)dp[i].dp_start * ms->sectorsize, l[i],
151109101Sphk		    ms->sectorsize, "%ss%d", gp->name, 1 + i);
152107956Sphk		if (error)
153107956Sphk			return (error);
154107956Sphk	}
155107956Sphk	for (i = 0; i < NDOSPART; i++) {
156107956Sphk		ms->type[i] = dp[i].dp_typ;
157107956Sphk		g_slice_config(gp, i, G_SLICE_CONFIG_SET,
158109101Sphk		    (off_t)dp[i].dp_start * ms->sectorsize, l[i],
159109101Sphk		    ms->sectorsize, "%ss%d", gp->name, 1 + i);
160107956Sphk	}
161108393Sphk	bcopy(sec0, ms->sec0, 512);
162140532Spjd
163140532Spjd	/*
164140532Spjd	 * Calculate MD5 from the first sector and use it for avoiding
165140532Spjd	 * recursive slices creation.
166140532Spjd	 */
167140532Spjd	MD5Init(&md5sum);
168140532Spjd	MD5Update(&md5sum, ms->sec0, sizeof(ms->sec0));
169140532Spjd	MD5Final(ms->slicesum, &md5sum);
170140532Spjd
171107956Sphk	return (0);
172107956Sphk}
173107956Sphk
174119660Sphkstatic int
175138732Sphkg_mbr_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
176108393Sphk{
177108393Sphk	struct g_geom *gp;
178119660Sphk	struct g_mbr_softc *ms;
179108393Sphk	struct g_slicer *gsp;
180108393Sphk	struct g_consumer *cp;
181138171Sphk	int error, opened;
182108393Sphk
183119660Sphk	gp = pp->geom;
184108393Sphk	gsp = gp->softc;
185108393Sphk	ms = gsp->softc;
186108393Sphk
187138171Sphk	opened = 0;
188138171Sphk	error = 0;
189119660Sphk	switch(cmd) {
190119660Sphk	case DIOCSMBR: {
191138732Sphk		if (!(fflag & FWRITE))
192138732Sphk			return (EPERM);
193119660Sphk		DROP_GIANT();
194119660Sphk		g_topology_lock();
195119660Sphk		cp = LIST_FIRST(&gp->consumer);
196138171Sphk		if (cp->acw == 0) {
197138171Sphk			error = g_access(cp, 0, 1, 0);
198138171Sphk			if (error == 0)
199138171Sphk				opened = 1;
200138171Sphk		}
201138171Sphk		if (!error)
202148034Sphk			error = g_mbr_modify(gp, ms, data, 512);
203138171Sphk		if (!error)
204138171Sphk			error = g_write_data(cp, 0, data, 512);
205138171Sphk		if (opened)
206138171Sphk			g_access(cp, 0, -1 , 0);
207119660Sphk		g_topology_unlock();
208119660Sphk		PICKUP_GIANT();
209119660Sphk		return(error);
210108393Sphk	}
211119660Sphk	default:
212119660Sphk		return (ENOIOCTL);
213119660Sphk	}
214108393Sphk}
215108393Sphk
216107956Sphkstatic int
21792108Sphkg_mbr_start(struct bio *bp)
21892108Sphk{
21992108Sphk	struct g_provider *pp;
22092108Sphk	struct g_geom *gp;
22192108Sphk	struct g_mbr_softc *mp;
22292108Sphk	struct g_slicer *gsp;
223119660Sphk	int idx;
22492108Sphk
22592108Sphk	pp = bp->bio_to;
226107953Sphk	idx = pp->index;
22792108Sphk	gp = pp->geom;
22892108Sphk	gsp = gp->softc;
22992108Sphk	mp = gsp->softc;
23092108Sphk	if (bp->bio_cmd == BIO_GETATTR) {
231107953Sphk		if (g_handleattr_int(bp, "MBR::type", mp->type[idx]))
23292108Sphk			return (1);
233106076Sphk		if (g_handleattr_off_t(bp, "MBR::offset",
234107953Sphk		    gsp->slices[idx].offset))
235106076Sphk			return (1);
236140532Spjd		if (g_handleattr(bp, "MBR::slicesum", mp->slicesum,
237140532Spjd		    sizeof(mp->slicesum)))
238140532Spjd			return (1);
23992108Sphk	}
240108393Sphk
241119660Sphk	return (0);
24292108Sphk}
24392108Sphk
24492108Sphkstatic void
245107953Sphkg_mbr_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp)
24692108Sphk{
24792108Sphk	struct g_mbr_softc *mp;
24892108Sphk	struct g_slicer *gsp;
24992108Sphk
25092108Sphk	gsp = gp->softc;
25192108Sphk	mp = gsp->softc;
252106076Sphk	g_slice_dumpconf(sb, indent, gp, cp, pp);
25392108Sphk	if (pp != NULL) {
254106341Smarcel		if (indent == NULL)
255106341Smarcel			sbuf_printf(sb, " ty %d", mp->type[pp->index]);
256106341Smarcel		else
257106341Smarcel			sbuf_printf(sb, "%s<type>%d</type>\n", indent,
258106341Smarcel			    mp->type[pp->index]);
25992108Sphk	}
26092108Sphk}
26192108Sphk
26292108Sphkstatic struct g_geom *
26393250Sphkg_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist)
26492108Sphk{
26592108Sphk	struct g_geom *gp;
26692108Sphk	struct g_consumer *cp;
267108393Sphk	int error;
26892108Sphk	struct g_mbr_softc *ms;
26994287Sphk	u_int fwsectors, sectorsize;
27092108Sphk	u_char *buf;
271140532Spjd	u_char hash[16];
272140532Spjd	MD5_CTX md5sum;
27392108Sphk
27492108Sphk	g_trace(G_T_TOPOLOGY, "mbr_taste(%s,%s)", mp->name, pp->name);
27592108Sphk	g_topology_assert();
276143590Sphk	if (!strcmp(pp->geom->class->name, MBR_CLASS_NAME))
277143590Sphk		return (NULL);
27892108Sphk	gp = g_slice_new(mp, NDOSPART, pp, &cp, &ms, sizeof *ms, g_mbr_start);
27992108Sphk	if (gp == NULL)
28092108Sphk		return (NULL);
28192108Sphk	g_topology_unlock();
282113285Sphk	do {
28394287Sphk		error = g_getattr("GEOM::fwsectors", cp, &fwsectors);
28494287Sphk		if (error)
28594287Sphk			fwsectors = 17;
286105551Sphk		sectorsize = cp->provider->sectorsize;
287109101Sphk		if (sectorsize < 512)
28894287Sphk			break;
289109101Sphk		ms->sectorsize = sectorsize;
290152971Ssobomax		buf = g_read_data(cp, 0, sectorsize, NULL);
291152967Ssobomax		if (buf == NULL)
29292108Sphk			break;
293140532Spjd
294140532Spjd		/*
295140532Spjd		 * Calculate MD5 from the first sector and use it for avoiding
296140532Spjd		 * recursive slices creation.
297140532Spjd		 */
298140532Spjd		bcopy(buf, ms->sec0, 512);
299140532Spjd		MD5Init(&md5sum);
300140532Spjd		MD5Update(&md5sum, ms->sec0, sizeof(ms->sec0));
301140532Spjd		MD5Final(ms->slicesum, &md5sum);
302140532Spjd
303140532Spjd		error = g_getattr("MBR::slicesum", cp, &hash);
304140532Spjd		if (!error && !bcmp(ms->slicesum, hash, sizeof(hash))) {
305140532Spjd			g_free(buf);
306140532Spjd			break;
307140532Spjd		}
308140532Spjd
309107968Sphk		g_topology_lock();
310148034Sphk		g_mbr_modify(gp, ms, buf, 512);
311107968Sphk		g_topology_unlock();
312108393Sphk		g_free(buf);
31392108Sphk		break;
314113285Sphk	} while (0);
31592108Sphk	g_topology_lock();
316125755Sphk	g_access(cp, -1, 0, 0);
317107956Sphk	if (LIST_EMPTY(&gp->provider)) {
318114517Sphk		g_slice_spoiled(cp);
319107956Sphk		return (NULL);
32092108Sphk	}
321107956Sphk	return (gp);
32292108Sphk}
32392108Sphk
324148034Sphkstatic void
325148034Sphkg_mbr_config(struct gctl_req *req, struct g_class *mp, const char *verb)
326148034Sphk{
327148034Sphk	struct g_geom *gp;
328148034Sphk	struct g_consumer *cp;
329148034Sphk	struct g_mbr_softc *ms;
330148034Sphk	struct g_slicer *gsp;
331148034Sphk	int opened = 0, error = 0;
332148034Sphk	void *data;
333148034Sphk	int len;
334148034Sphk
335148034Sphk	g_topology_assert();
336148034Sphk	gp = gctl_get_geom(req, mp, "geom");
337148034Sphk	if (gp == NULL)
338148034Sphk		return;
339148034Sphk	if (strcmp(verb, "write MBR")) {
340148034Sphk		gctl_error(req, "Unknown verb");
341148034Sphk		return;
342148034Sphk	}
343148034Sphk	gsp = gp->softc;
344148034Sphk	ms = gsp->softc;
345148034Sphk	data = gctl_get_param(req, "data", &len);
346148034Sphk	if (data == NULL)
347148034Sphk		return;
348148034Sphk	if (len < 512 || (len % 512)) {
349148034Sphk		gctl_error(req, "Wrong request length");
350148034Sphk		return;
351148034Sphk	}
352148034Sphk	cp = LIST_FIRST(&gp->consumer);
353148034Sphk	if (cp->acw == 0) {
354148034Sphk		error = g_access(cp, 0, 1, 0);
355148034Sphk		if (error == 0)
356148034Sphk			opened = 1;
357148034Sphk	}
358148034Sphk	if (!error)
359148034Sphk		error = g_mbr_modify(gp, ms, data, len);
360148034Sphk	if (error)
361148034Sphk		gctl_error(req, "conflict with open slices");
362148034Sphk	if (!error)
363148034Sphk		error = g_write_data(cp, 0, data, len);
364148034Sphk	if (error)
365148034Sphk		gctl_error(req, "sector zero write failed");
366148034Sphk	if (opened)
367148034Sphk		g_access(cp, 0, -1 , 0);
368148034Sphk	return;
369148034Sphk}
370148034Sphk
37193248Sphkstatic struct g_class g_mbr_class	= {
372112552Sphk	.name = MBR_CLASS_NAME,
373133318Sphk	.version = G_VERSION,
374112552Sphk	.taste = g_mbr_taste,
375133314Sphk	.dumpconf = g_mbr_dumpconf,
376148034Sphk	.ctlreq = g_mbr_config,
377133314Sphk	.ioctl = g_mbr_ioctl,
37892108Sphk};
37992108Sphk
38093248SphkDECLARE_GEOM_CLASS(g_mbr_class, g_mbr);
38193090Sphk
38293090Sphk#define NDOSEXTPART		32
38393090Sphkstruct g_mbrext_softc {
38493090Sphk	int		type [NDOSEXTPART];
38593090Sphk};
38693090Sphk
38793090Sphkstatic int
38893090Sphkg_mbrext_start(struct bio *bp)
38993090Sphk{
39093090Sphk	struct g_provider *pp;
39193090Sphk	struct g_geom *gp;
39293090Sphk	struct g_mbrext_softc *mp;
39393090Sphk	struct g_slicer *gsp;
394107953Sphk	int idx;
39593090Sphk
39693090Sphk	pp = bp->bio_to;
397107953Sphk	idx = pp->index;
39893090Sphk	gp = pp->geom;
39993090Sphk	gsp = gp->softc;
40093090Sphk	mp = gsp->softc;
40193090Sphk	if (bp->bio_cmd == BIO_GETATTR) {
402107953Sphk		if (g_handleattr_int(bp, "MBR::type", mp->type[idx]))
40393090Sphk			return (1);
40493090Sphk	}
40593090Sphk	return (0);
40693090Sphk}
40793090Sphk
40893090Sphkstatic void
409107953Sphkg_mbrext_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp __unused, struct g_provider *pp)
41093090Sphk{
41193090Sphk	struct g_mbrext_softc *mp;
41293090Sphk	struct g_slicer *gsp;
41393090Sphk
41493090Sphk	g_slice_dumpconf(sb, indent, gp, cp, pp);
41593090Sphk	gsp = gp->softc;
41693090Sphk	mp = gsp->softc;
41793090Sphk	if (pp != NULL) {
418106341Smarcel		if (indent == NULL)
419106341Smarcel			sbuf_printf(sb, " ty %d", mp->type[pp->index]);
420106341Smarcel		else
421106341Smarcel			sbuf_printf(sb, "%s<type>%d</type>\n", indent,
422106341Smarcel			    mp->type[pp->index]);
42393090Sphk	}
42493090Sphk}
42593090Sphk
42693090Sphkstatic struct g_geom *
42793250Sphkg_mbrext_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
42893090Sphk{
42993090Sphk	struct g_geom *gp;
43093090Sphk	struct g_consumer *cp;
43194287Sphk	int error, i, slice;
43293090Sphk	struct g_mbrext_softc *ms;
43393090Sphk	off_t off;
43493090Sphk	u_char *buf;
43593090Sphk	struct dos_partition dp[4];
43694287Sphk	u_int fwsectors, sectorsize;
43793090Sphk
43893090Sphk	g_trace(G_T_TOPOLOGY, "g_mbrext_taste(%s,%s)", mp->name, pp->name);
43993090Sphk	g_topology_assert();
44093248Sphk	if (strcmp(pp->geom->class->name, MBR_CLASS_NAME))
44193090Sphk		return (NULL);
442110706Sphk	gp = g_slice_new(mp, NDOSEXTPART, pp, &cp, &ms, sizeof *ms,
443110706Sphk	    g_mbrext_start);
44493090Sphk	if (gp == NULL)
44593090Sphk		return (NULL);
44693090Sphk	g_topology_unlock();
44793090Sphk	off = 0;
44893090Sphk	slice = 0;
449113285Sphk	do {
45094287Sphk		error = g_getattr("MBR::type", cp, &i);
451103100Sphk		if (error || (i != DOSPTYP_EXT && i != DOSPTYP_EXTLBA))
45293090Sphk			break;
45394287Sphk		error = g_getattr("GEOM::fwsectors", cp, &fwsectors);
45494287Sphk		if (error)
45594287Sphk			fwsectors = 17;
456105551Sphk		sectorsize = cp->provider->sectorsize;
457104087Sphk		if (sectorsize != 512)
45894287Sphk			break;
45993090Sphk		for (;;) {
460152971Ssobomax			buf = g_read_data(cp, off, sectorsize, NULL);
461152967Ssobomax			if (buf == NULL)
46293090Sphk				break;
463114517Sphk			if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) {
464114517Sphk				g_free(buf);
46593090Sphk				break;
466114517Sphk			}
46793090Sphk			for (i = 0; i < NDOSPART; i++)
468113389Sphk				dos_partition_dec(
469106263Sphk				    buf + DOSPARTOFF +
470106263Sphk				    i * sizeof(struct dos_partition), dp + i);
47193090Sphk			g_free(buf);
472137150Sphk			if (0 && bootverbose) {
473113294Sphk				printf("MBREXT Slice %d on %s:\n",
474113294Sphk				    slice + 5, gp->name);
475113294Sphk				g_mbr_print(0, dp);
476113294Sphk				g_mbr_print(1, dp + 1);
477113294Sphk			}
478106397Sphk			if ((dp[0].dp_flag & 0x7f) == 0 &&
479106397Sphk			     dp[0].dp_size != 0 && dp[0].dp_typ != 0) {
480108093Sphk				g_topology_lock();
481107956Sphk				g_slice_config(gp, slice, G_SLICE_CONFIG_SET,
48293090Sphk				    (((off_t)dp[0].dp_start) << 9ULL) + off,
48393090Sphk				    ((off_t)dp[0].dp_size) << 9ULL,
484105542Sphk				    sectorsize,
48593090Sphk				    "%*.*s%d",
486243333Sjh				    (int)strlen(gp->name) - 1,
487243333Sjh				    (int)strlen(gp->name) - 1,
48893090Sphk				    gp->name,
48993090Sphk				    slice + 5);
490104064Sphk				g_topology_unlock();
49193090Sphk				ms->type[slice] = dp[0].dp_typ;
49293090Sphk				slice++;
49393090Sphk			}
49493090Sphk			if (dp[1].dp_flag != 0)
49593090Sphk				break;
496118150Sphk			if (dp[1].dp_typ != DOSPTYP_EXT &&
497118150Sphk			    dp[1].dp_typ != DOSPTYP_EXTLBA)
49893090Sphk				break;
49993090Sphk			if (dp[1].dp_size == 0)
50093090Sphk				break;
50193090Sphk			off = ((off_t)dp[1].dp_start) << 9ULL;
50293090Sphk		}
50393090Sphk		break;
504113285Sphk	} while (0);
50593090Sphk	g_topology_lock();
506125755Sphk	g_access(cp, -1, 0, 0);
507107956Sphk	if (LIST_EMPTY(&gp->provider)) {
508114517Sphk		g_slice_spoiled(cp);
509107956Sphk		return (NULL);
51097078Sphk	}
511107956Sphk	return (gp);
51293090Sphk}
51393090Sphk
51493090Sphk
51593248Sphkstatic struct g_class g_mbrext_class	= {
516113031Sphk	.name = MBREXT_CLASS_NAME,
517133318Sphk	.version = G_VERSION,
518113031Sphk	.taste = g_mbrext_taste,
519133314Sphk	.dumpconf = g_mbrext_dumpconf,
52093090Sphk};
52193090Sphk
52293248SphkDECLARE_GEOM_CLASS(g_mbrext_class, g_mbrext);
523