15f073f2marcel/*-
2a82e3a8pfg * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3a82e3a8pfg *
45f073f2marcel * Copyright (c) 2007 Marcel Moolenaar
55f073f2marcel * All rights reserved.
65f073f2marcel *
75f073f2marcel * Redistribution and use in source and binary forms, with or without
85f073f2marcel * modification, are permitted provided that the following conditions
95f073f2marcel * are met:
105f073f2marcel *
115f073f2marcel * 1. Redistributions of source code must retain the above copyright
125f073f2marcel *    notice, this list of conditions and the following disclaimer.
135f073f2marcel * 2. Redistributions in binary form must reproduce the above copyright
145f073f2marcel *    notice, this list of conditions and the following disclaimer in the
155f073f2marcel *    documentation and/or other materials provided with the distribution.
165f073f2marcel *
175f073f2marcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185f073f2marcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195f073f2marcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205f073f2marcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215f073f2marcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225f073f2marcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235f073f2marcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245f073f2marcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255f073f2marcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265f073f2marcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275f073f2marcel */
285f073f2marcel
295f073f2marcel#include <sys/cdefs.h>
305f073f2marcel__FBSDID("$FreeBSD$");
315f073f2marcel
325f073f2marcel#include <sys/param.h>
335f073f2marcel#include <sys/bio.h>
345f073f2marcel#include <sys/disklabel.h>
355f073f2marcel#include <sys/endian.h>
365f073f2marcel#include <sys/kernel.h>
375f073f2marcel#include <sys/kobj.h>
385f073f2marcel#include <sys/limits.h>
395f073f2marcel#include <sys/lock.h>
405f073f2marcel#include <sys/malloc.h>
415f073f2marcel#include <sys/mutex.h>
425f073f2marcel#include <sys/queue.h>
435f073f2marcel#include <sys/sbuf.h>
445f073f2marcel#include <sys/systm.h>
456bf702anetchild#include <sys/sysctl.h>
465f073f2marcel#include <geom/geom.h>
475f073f2marcel#include <geom/part/g_part.h>
485f073f2marcel
495f073f2marcel#include "g_part_if.h"
505f073f2marcel
51f892d94ae#define	BOOT1_SIZE	512
52f892d94ae#define	LABEL_SIZE	512
53f892d94ae#define	BOOT2_OFF	(BOOT1_SIZE + LABEL_SIZE)
54f892d94ae#define	BOOT2_SIZE	(BBSIZE - BOOT2_OFF)
55f892d94ae
566bf702anetchildFEATURE(geom_part_bsd, "GEOM partitioning class for BSD disklabels");
576bf702anetchild
585f073f2marcelstruct g_part_bsd_table {
595f073f2marcel	struct g_part_table	base;
6042a7dd5marcel	u_char			*bbarea;
615817fa6marcel	uint32_t		offset;
625f073f2marcel};
635f073f2marcel
645f073f2marcelstruct g_part_bsd_entry {
655f073f2marcel	struct g_part_entry	base;
665f073f2marcel	struct partition	part;
675f073f2marcel};
685f073f2marcel
695f073f2marcelstatic int g_part_bsd_add(struct g_part_table *, struct g_part_entry *,
705f073f2marcel    struct g_part_parms *);
7142a7dd5marcelstatic int g_part_bsd_bootcode(struct g_part_table *, struct g_part_parms *);
725f073f2marcelstatic int g_part_bsd_create(struct g_part_table *, struct g_part_parms *);
735f073f2marcelstatic int g_part_bsd_destroy(struct g_part_table *, struct g_part_parms *);
74de04402impstatic void g_part_bsd_dumpconf(struct g_part_table *, struct g_part_entry *,
7538e8adfmarcel    struct sbuf *, const char *);
765f073f2marcelstatic int g_part_bsd_dumpto(struct g_part_table *, struct g_part_entry *);
77a69327aimpstatic int g_part_bsd_modify(struct g_part_table *, struct g_part_entry *,
785f073f2marcel    struct g_part_parms *);
79de04402impstatic const char *g_part_bsd_name(struct g_part_table *, struct g_part_entry *,
805f073f2marcel    char *, size_t);
815f073f2marcelstatic int g_part_bsd_probe(struct g_part_table *, struct g_consumer *);
825f073f2marcelstatic int g_part_bsd_read(struct g_part_table *, struct g_consumer *);
835f073f2marcelstatic const char *g_part_bsd_type(struct g_part_table *, struct g_part_entry *,
845f073f2marcel    char *, size_t);
855f073f2marcelstatic int g_part_bsd_write(struct g_part_table *, struct g_consumer *);
86be854afmarcelstatic int g_part_bsd_resize(struct g_part_table *, struct g_part_entry *,
87be854afmarcel    struct g_part_parms *);
885f073f2marcel
895f073f2marcelstatic kobj_method_t g_part_bsd_methods[] = {
905f073f2marcel	KOBJMETHOD(g_part_add,		g_part_bsd_add),
9142a7dd5marcel	KOBJMETHOD(g_part_bootcode,	g_part_bsd_bootcode),
925f073f2marcel	KOBJMETHOD(g_part_create,	g_part_bsd_create),
935f073f2marcel	KOBJMETHOD(g_part_destroy,	g_part_bsd_destroy),
9438e8adfmarcel	KOBJMETHOD(g_part_dumpconf,	g_part_bsd_dumpconf),
955f073f2marcel	KOBJMETHOD(g_part_dumpto,	g_part_bsd_dumpto),
965f073f2marcel	KOBJMETHOD(g_part_modify,	g_part_bsd_modify),
97be854afmarcel	KOBJMETHOD(g_part_resize,	g_part_bsd_resize),
985f073f2marcel	KOBJMETHOD(g_part_name,		g_part_bsd_name),
995f073f2marcel	KOBJMETHOD(g_part_probe,	g_part_bsd_probe),
1005f073f2marcel	KOBJMETHOD(g_part_read,		g_part_bsd_read),
1015f073f2marcel	KOBJMETHOD(g_part_type,		g_part_bsd_type),
1025f073f2marcel	KOBJMETHOD(g_part_write,	g_part_bsd_write),
1035f073f2marcel	{ 0, 0 }
1045f073f2marcel};
1055f073f2marcel
1065f073f2marcelstatic struct g_part_scheme g_part_bsd_scheme = {
1075f073f2marcel	"BSD",
1085f073f2marcel	g_part_bsd_methods,
1095f073f2marcel	sizeof(struct g_part_bsd_table),
1105f073f2marcel	.gps_entrysz = sizeof(struct g_part_bsd_entry),
1115f073f2marcel	.gps_minent = 8,
112904cc72ivoras	.gps_maxent = 20,	/* Only 22 entries fit in 512 byte sectors */
11342a7dd5marcel	.gps_bootcodesz = BBSIZE,
1145f073f2marcel};
115c184f6cmarcelG_PART_SCHEME_DECLARE(g_part_bsd);
116dd6f2f2kevansMODULE_VERSION(geom_part_bsd, 0);
1175f073f2marcel
118f045bddaestatic struct g_part_bsd_alias {
119f045bddae	uint8_t		type;
120f045bddae	int		alias;
121f045bddae} bsd_alias_match[] = {
122f045bddae	{ FS_BSDFFS,	G_PART_ALIAS_FREEBSD_UFS },
123f045bddae	{ FS_SWAP,	G_PART_ALIAS_FREEBSD_SWAP },
124f045bddae	{ FS_ZFS,	G_PART_ALIAS_FREEBSD_ZFS },
125f045bddae	{ FS_VINUM,	G_PART_ALIAS_FREEBSD_VINUM },
126f045bddae	{ FS_NANDFS,	G_PART_ALIAS_FREEBSD_NANDFS },
127f045bddae	{ FS_HAMMER,	G_PART_ALIAS_DFBSD_HAMMER },
128f045bddae	{ FS_HAMMER2,	G_PART_ALIAS_DFBSD_HAMMER2 },
129f045bddae};
130f045bddae
1315f073f2marcelstatic int
1325f073f2marcelbsd_parse_type(const char *type, uint8_t *fstype)
1335f073f2marcel{
1345f073f2marcel	const char *alias;
1355f073f2marcel	char *endp;
1365f073f2marcel	long lt;
137f045bddae	int i;
1385f073f2marcel
1395f073f2marcel	if (type[0] == '!') {
1405f073f2marcel		lt = strtol(type + 1, &endp, 0);
1415f073f2marcel		if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256)
1425f073f2marcel			return (EINVAL);
1435f073f2marcel		*fstype = (u_int)lt;
1445f073f2marcel		return (0);
1455f073f2marcel	}
14632dcf39pfg	for (i = 0; i < nitems(bsd_alias_match); i++) {
147f045bddae		alias = g_part_alias_name(bsd_alias_match[i].alias);
148f045bddae		if (strcasecmp(type, alias) == 0) {
149f045bddae			*fstype = bsd_alias_match[i].type;
150f045bddae			return (0);
151f045bddae		}
1527827a14marcel	}
1535f073f2marcel	return (EINVAL);
1545f073f2marcel}
1555f073f2marcel
1565f073f2marcelstatic int
1575f073f2marcelg_part_bsd_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
1585f073f2marcel    struct g_part_parms *gpp)
1595f073f2marcel{
1605f073f2marcel	struct g_part_bsd_entry *entry;
1615f073f2marcel	struct g_part_bsd_table *table;
1625f073f2marcel
1635f073f2marcel	if (gpp->gpp_parms & G_PART_PARM_LABEL)
1645f073f2marcel		return (EINVAL);
1655f073f2marcel
1665f073f2marcel	entry = (struct g_part_bsd_entry *)baseentry;
1675f073f2marcel	table = (struct g_part_bsd_table *)basetable;
1685f073f2marcel
1695817fa6marcel	entry->part.p_size = gpp->gpp_size;
1705817fa6marcel	entry->part.p_offset = gpp->gpp_start + table->offset;
1715f073f2marcel	entry->part.p_fsize = 0;
1725f073f2marcel	entry->part.p_frag = 0;
1735f073f2marcel	entry->part.p_cpg = 0;
1745f073f2marcel	return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype));
1755f073f2marcel}
1765f073f2marcel
1775f073f2marcelstatic int
17842a7dd5marcelg_part_bsd_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
17942a7dd5marcel{
18042a7dd5marcel	struct g_part_bsd_table *table;
18142a7dd5marcel	const u_char *codeptr;
18242a7dd5marcel
183f892d94ae	if (gpp->gpp_codesize != BOOT1_SIZE && gpp->gpp_codesize != BBSIZE)
184f892d94ae		return (ENODEV);
185f892d94ae
18642a7dd5marcel	table = (struct g_part_bsd_table *)basetable;
18742a7dd5marcel	codeptr = gpp->gpp_codeptr;
188f892d94ae	bcopy(codeptr, table->bbarea, BOOT1_SIZE);
189f892d94ae	if (gpp->gpp_codesize == BBSIZE)
190f892d94ae		bcopy(codeptr + BOOT2_OFF, table->bbarea + BOOT2_OFF,
191f892d94ae		    BOOT2_SIZE);
19242a7dd5marcel	return (0);
19342a7dd5marcel}
19442a7dd5marcel
19542a7dd5marcelstatic int
1965f073f2marcelg_part_bsd_create(struct g_part_table *basetable, struct g_part_parms *gpp)
1975f073f2marcel{
1985f073f2marcel	struct g_provider *pp;
1995f073f2marcel	struct g_part_entry *baseentry;
2005f073f2marcel	struct g_part_bsd_entry *entry;
2015f073f2marcel	struct g_part_bsd_table *table;
2025f073f2marcel	u_char *ptr;
2031525b2bmarcel	uint32_t msize, ncyls, secpercyl;
2045f073f2marcel
2055f073f2marcel	pp = gpp->gpp_provider;
2065f073f2marcel
2075f073f2marcel	if (pp->sectorsize < sizeof(struct disklabel))
2085f073f2marcel		return (ENOSPC);
20942a7dd5marcel	if (BBSIZE % pp->sectorsize)
21042a7dd5marcel		return (ENOTBLK);
2115f073f2marcel
212a0e3009ae	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
2135f073f2marcel	secpercyl = basetable->gpt_sectors * basetable->gpt_heads;
2145f073f2marcel	ncyls = msize / secpercyl;
2155f073f2marcel
2165f073f2marcel	table = (struct g_part_bsd_table *)basetable;
21742a7dd5marcel	table->bbarea = g_malloc(BBSIZE, M_WAITOK | M_ZERO);
21842a7dd5marcel	ptr = table->bbarea + pp->sectorsize;
2195f073f2marcel
2205f073f2marcel	le32enc(ptr + 0, DISKMAGIC);			/* d_magic */
2215f073f2marcel	le32enc(ptr + 40, pp->sectorsize);		/* d_secsize */
2225f073f2marcel	le32enc(ptr + 44, basetable->gpt_sectors);	/* d_nsectors */
2235f073f2marcel	le32enc(ptr + 48, basetable->gpt_heads);	/* d_ntracks */
2245f073f2marcel	le32enc(ptr + 52, ncyls);			/* d_ncylinders */
2255f073f2marcel	le32enc(ptr + 56, secpercyl);			/* d_secpercyl */
2265817fa6marcel	le32enc(ptr + 60, msize);			/* d_secperunit */
2275f073f2marcel	le16enc(ptr + 72, 3600);			/* d_rpm */
2285f073f2marcel	le32enc(ptr + 132, DISKMAGIC);			/* d_magic2 */
2295f073f2marcel	le16enc(ptr + 138, basetable->gpt_entries);	/* d_npartitions */
2305f073f2marcel	le32enc(ptr + 140, BBSIZE);			/* d_bbsize */
2315f073f2marcel
2325f073f2marcel	basetable->gpt_first = 0;
2335817fa6marcel	basetable->gpt_last = msize - 1;
2345f073f2marcel	basetable->gpt_isleaf = 1;
2355f073f2marcel
2365f073f2marcel	baseentry = g_part_new_entry(basetable, RAW_PART + 1,
2375f073f2marcel	    basetable->gpt_first, basetable->gpt_last);
2385f073f2marcel	baseentry->gpe_internal = 1;
2395f073f2marcel	entry = (struct g_part_bsd_entry *)baseentry;
2405f073f2marcel	entry->part.p_size = basetable->gpt_last + 1;
2415817fa6marcel	entry->part.p_offset = table->offset;
2425f073f2marcel
2435f073f2marcel	return (0);
2445f073f2marcel}
2455f073f2marcel
2465f073f2marcelstatic int
2475f073f2marcelg_part_bsd_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
2485f073f2marcel{
249f05cc30marius	struct g_part_bsd_table *table;
250f05cc30marius
251f05cc30marius	table = (struct g_part_bsd_table *)basetable;
252f05cc30marius	if (table->bbarea != NULL)
253f05cc30marius		g_free(table->bbarea);
254f05cc30marius	table->bbarea = NULL;
2555f073f2marcel
2565f073f2marcel	/* Wipe the second sector to clear the partitioning. */
2575f073f2marcel	basetable->gpt_smhead |= 2;
2585f073f2marcel	return (0);
2595f073f2marcel}
2605f073f2marcel
261de04402impstatic void
262a69327aimpg_part_bsd_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry,
26338e8adfmarcel    struct sbuf *sb, const char *indent)
26438e8adfmarcel{
26538e8adfmarcel	struct g_part_bsd_entry *entry;
26638e8adfmarcel
26738e8adfmarcel	entry = (struct g_part_bsd_entry *)baseentry;
268169adacmarcel	if (indent == NULL) {
269169adacmarcel		/* conftxt: libdisk compatibility */
270169adacmarcel		sbuf_printf(sb, " xs BSD xt %u", entry->part.p_fstype);
271169adacmarcel	} else if (entry != NULL) {
272169adacmarcel		/* confxml: partition entry information */
273169adacmarcel		sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
274169adacmarcel		    entry->part.p_fstype);
275169adacmarcel	} else {
276169adacmarcel		/* confxml: scheme information */
277169adacmarcel	}
27838e8adfmarcel}
27938e8adfmarcel
28038e8adfmarcelstatic int
281a69327aimpg_part_bsd_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
2825f073f2marcel{
2835f073f2marcel	struct g_part_bsd_entry *entry;
2845f073f2marcel
28511ca3c2marcel	/* Allow dumping to a swap partition or an unused partition. */
2865f073f2marcel	entry = (struct g_part_bsd_entry *)baseentry;
28711ca3c2marcel	return ((entry->part.p_fstype == FS_UNUSED ||
28811ca3c2marcel	    entry->part.p_fstype == FS_SWAP) ? 1 : 0);
2895f073f2marcel}
2905f073f2marcel
2915f073f2marcelstatic int
2925f073f2marcelg_part_bsd_modify(struct g_part_table *basetable,
2935f073f2marcel    struct g_part_entry *baseentry, struct g_part_parms *gpp)
2945f073f2marcel{
2955f073f2marcel	struct g_part_bsd_entry *entry;
2965f073f2marcel
2975f073f2marcel	if (gpp->gpp_parms & G_PART_PARM_LABEL)
2985f073f2marcel		return (EINVAL);
2995f073f2marcel
3005f073f2marcel	entry = (struct g_part_bsd_entry *)baseentry;
3015f073f2marcel	if (gpp->gpp_parms & G_PART_PARM_TYPE)
3025f073f2marcel		return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype));
3035f073f2marcel	return (0);
3045f073f2marcel}
3055f073f2marcel
30605ca533aestatic void
30705ca533aebsd_set_rawsize(struct g_part_table *basetable, struct g_provider *pp)
30805ca533ae{
30905ca533ae	struct g_part_bsd_table *table;
31005ca533ae	struct g_part_bsd_entry *entry;
31105ca533ae	struct g_part_entry *baseentry;
31205ca533ae	uint32_t msize;
31305ca533ae
31405ca533ae	table = (struct g_part_bsd_table *)basetable;
31505ca533ae	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
31605ca533ae	le32enc(table->bbarea + pp->sectorsize + 60, msize); /* d_secperunit */
31705ca533ae	basetable->gpt_last = msize - 1;
31805ca533ae	LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
31905ca533ae		if (baseentry->gpe_index != RAW_PART + 1)
32005ca533ae			continue;
32105ca533ae		baseentry->gpe_end = basetable->gpt_last;
32205ca533ae		entry = (struct g_part_bsd_entry *)baseentry;
32305ca533ae		entry->part.p_size = msize;
32405ca533ae		return;
32505ca533ae	}
32605ca533ae}
32705ca533ae
328be854afmarcelstatic int
329be854afmarcelg_part_bsd_resize(struct g_part_table *basetable,
330be854afmarcel    struct g_part_entry *baseentry, struct g_part_parms *gpp)
331be854afmarcel{
332be854afmarcel	struct g_part_bsd_entry *entry;
33305ca533ae	struct g_provider *pp;
334be854afmarcel
33505ca533ae	if (baseentry == NULL) {
33605ca533ae		pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
33705ca533ae		bsd_set_rawsize(basetable, pp);
33805ca533ae		return (0);
33905ca533ae	}
340be854afmarcel	entry = (struct g_part_bsd_entry *)baseentry;
341be854afmarcel	baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
342be854afmarcel	entry->part.p_size = gpp->gpp_size;
343be854afmarcel
344be854afmarcel	return (0);
345be854afmarcel}
346be854afmarcel
347de04402impstatic const char *
3485f073f2marcelg_part_bsd_name(struct g_part_table *table, struct g_part_entry *baseentry,
3495f073f2marcel    char *buf, size_t bufsz)
3505f073f2marcel{
3515f073f2marcel
3525f073f2marcel	snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
3535f073f2marcel	return (buf);
3545f073f2marcel}
3555f073f2marcel
3565f073f2marcelstatic int
3575f073f2marcelg_part_bsd_probe(struct g_part_table *table, struct g_consumer *cp)
3585f073f2marcel{
3595f073f2marcel	struct g_provider *pp;
3605f073f2marcel	u_char *buf;
3615f073f2marcel	uint32_t magic1, magic2;
3625f073f2marcel	int error;
3635f073f2marcel
3645f073f2marcel	pp = cp->provider;
3655f073f2marcel
3665f073f2marcel	/* Sanity-check the provider. */
3675f073f2marcel	if (pp->sectorsize < sizeof(struct disklabel) ||
3685f073f2marcel	    pp->mediasize < BBSIZE)
3695f073f2marcel		return (ENOSPC);
37042a7dd5marcel	if (BBSIZE % pp->sectorsize)
37142a7dd5marcel		return (ENOTBLK);
3725f073f2marcel
3735f073f2marcel	/* Check that there's a disklabel. */
3745f073f2marcel	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
3755f073f2marcel	if (buf == NULL)
3765f073f2marcel		return (error);
3775f073f2marcel	magic1 = le32dec(buf + 0);
3785f073f2marcel	magic2 = le32dec(buf + 132);
3795f073f2marcel	g_free(buf);
3805f073f2marcel	return ((magic1 == DISKMAGIC && magic2 == DISKMAGIC)
3811fe9adfmarcel	    ? G_PART_PROBE_PRI_HIGH : ENXIO);
3825f073f2marcel}
3835f073f2marcel
3845f073f2marcelstatic int
3855f073f2marcelg_part_bsd_read(struct g_part_table *basetable, struct g_consumer *cp)
3865f073f2marcel{
3875f073f2marcel	struct g_provider *pp;
3885f073f2marcel	struct g_part_bsd_table *table;
3895f073f2marcel	struct g_part_entry *baseentry;
3905f073f2marcel	struct g_part_bsd_entry *entry;
3915f073f2marcel	struct partition part;
3925f073f2marcel	u_char *buf, *p;
3935f073f2marcel	off_t chs, msize;
3945f073f2marcel	u_int sectors, heads;
3955f073f2marcel	int error, index;
3965f073f2marcel
3975f073f2marcel	pp = cp->provider;
3985f073f2marcel	table = (struct g_part_bsd_table *)basetable;
399a0e3009ae	msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
4005f073f2marcel
40142a7dd5marcel	table->bbarea = g_read_data(cp, 0, BBSIZE, &error);
40242a7dd5marcel	if (table->bbarea == NULL)
4035f073f2marcel		return (error);
4045f073f2marcel
40542a7dd5marcel	buf = table->bbarea + pp->sectorsize;
4065f073f2marcel
4075f073f2marcel	if (le32dec(buf + 40) != pp->sectorsize)
4085f073f2marcel		goto invalid_label;
4095f073f2marcel	sectors = le32dec(buf + 44);
4103177393marcel	if (sectors < 1 || sectors > 255)
4115f073f2marcel		goto invalid_label;
4125817fa6marcel	if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) {
4135f073f2marcel		g_part_geometry_heads(msize, sectors, &chs, &heads);
4145817fa6marcel		if (chs != 0) {
4155817fa6marcel			basetable->gpt_sectors = sectors;
4165817fa6marcel			basetable->gpt_heads = heads;
4175817fa6marcel		}
4185f073f2marcel	}
4195f073f2marcel	heads = le32dec(buf + 48);
4205f073f2marcel	if (heads < 1 || heads > 255)
4215f073f2marcel		goto invalid_label;
4225817fa6marcel	if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom)
4235f073f2marcel		basetable->gpt_heads = heads;
4245817fa6marcel
4255817fa6marcel	chs = le32dec(buf + 60);
4268fb9b72marcel	if (chs < 1)
4275f073f2marcel		goto invalid_label;
4288fb9b72marcel	/* Fix-up a sysinstall bug. */
4298fb9b72marcel	if (chs > msize) {
4308fb9b72marcel		chs = msize;
4318fb9b72marcel		le32enc(buf + 60, msize);
4328fb9b72marcel	}
4335f073f2marcel
4345f073f2marcel	basetable->gpt_first = 0;
4355817fa6marcel	basetable->gpt_last = msize - 1;
4365f073f2marcel	basetable->gpt_isleaf = 1;
4375f073f2marcel
4385f073f2marcel	basetable->gpt_entries = le16dec(buf + 138);
4395f073f2marcel	if (basetable->gpt_entries < g_part_bsd_scheme.gps_minent ||
4405f073f2marcel	    basetable->gpt_entries > g_part_bsd_scheme.gps_maxent)
4415f073f2marcel		goto invalid_label;
4425f073f2marcel
4435817fa6marcel	table->offset = le32dec(buf + 148 + RAW_PART * 16 + 4);
4445f073f2marcel	for (index = basetable->gpt_entries - 1; index >= 0; index--) {
4455f073f2marcel		p = buf + 148 + index * 16;
4465f073f2marcel		part.p_size = le32dec(p + 0);
4475f073f2marcel		part.p_offset = le32dec(p + 4);
4485f073f2marcel		part.p_fsize = le32dec(p + 8);
4495f073f2marcel		part.p_fstype = p[12];
4505f073f2marcel		part.p_frag = p[13];
4515f073f2marcel		part.p_cpg = le16dec(p + 14);
4525f073f2marcel		if (part.p_size == 0)
4535f073f2marcel			continue;
4545817fa6marcel		if (part.p_offset < table->offset)
4555f073f2marcel			continue;
4562586300ae		if (part.p_offset - table->offset > basetable->gpt_last)
4572586300ae			goto invalid_label;
4585f073f2marcel		baseentry = g_part_new_entry(basetable, index + 1,
4595817fa6marcel		    part.p_offset - table->offset,
4605817fa6marcel		    part.p_offset - table->offset + part.p_size - 1);
4615f073f2marcel		entry = (struct g_part_bsd_entry *)baseentry;
4625f073f2marcel		entry->part = part;
46386005b8marcel		if (index == RAW_PART)
4645f073f2marcel			baseentry->gpe_internal = 1;
4655f073f2marcel	}
4665f073f2marcel
4675f073f2marcel	return (0);
4685f073f2marcel
4695f073f2marcel invalid_label:
4705f073f2marcel	printf("GEOM: %s: invalid disklabel.\n", pp->name);
47142a7dd5marcel	g_free(table->bbarea);
4722586300ae	table->bbarea = NULL;
4735f073f2marcel	return (EINVAL);
4745f073f2marcel}
4755f073f2marcel
4765f073f2marcelstatic const char *
477a69327aimpg_part_bsd_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
4785f073f2marcel    char *buf, size_t bufsz)
4795f073f2marcel{
4805f073f2marcel	struct g_part_bsd_entry *entry;
4815f073f2marcel	int type;
4825f073f2marcel
4835f073f2marcel	entry = (struct g_part_bsd_entry *)baseentry;
4845f073f2marcel	type = entry->part.p_fstype;
4855306b1emarcel	if (type == FS_NANDFS)
4865306b1emarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS));
4875f073f2marcel	if (type == FS_SWAP)
4885f073f2marcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
4895f073f2marcel	if (type == FS_BSDFFS)
4905f073f2marcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
4915f073f2marcel	if (type == FS_VINUM)
4925f073f2marcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
4937827a14marcel	if (type == FS_ZFS)
4947827a14marcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS));
4955f073f2marcel	snprintf(buf, bufsz, "!%d", type);
4965f073f2marcel	return (buf);
4975f073f2marcel}
4985f073f2marcel
4995f073f2marcelstatic int
5005f073f2marcelg_part_bsd_write(struct g_part_table *basetable, struct g_consumer *cp)
5015f073f2marcel{
5025f073f2marcel	struct g_provider *pp;
5035f073f2marcel	struct g_part_entry *baseentry;
5045f073f2marcel	struct g_part_bsd_entry *entry;
5055f073f2marcel	struct g_part_bsd_table *table;
5065f073f2marcel	uint16_t sum;
50742a7dd5marcel	u_char *label, *p, *pe;
5085f073f2marcel	int error, index;
5095f073f2marcel
5105f073f2marcel	pp = cp->provider;
5115f073f2marcel	table = (struct g_part_bsd_table *)basetable;
5125f073f2marcel	baseentry = LIST_FIRST(&basetable->gpt_entry);
51342a7dd5marcel	label = table->bbarea + pp->sectorsize;
5145f073f2marcel	for (index = 1; index <= basetable->gpt_entries; index++) {
51542a7dd5marcel		p = label + 148 + (index - 1) * 16;
5165f073f2marcel		entry = (baseentry != NULL && index == baseentry->gpe_index)
5175f073f2marcel		    ? (struct g_part_bsd_entry *)baseentry : NULL;
5185f073f2marcel		if (entry != NULL && !baseentry->gpe_deleted) {
5195f073f2marcel			le32enc(p + 0, entry->part.p_size);
5205f073f2marcel			le32enc(p + 4, entry->part.p_offset);
5215f073f2marcel			le32enc(p + 8, entry->part.p_fsize);
5225f073f2marcel			p[12] = entry->part.p_fstype;
5235f073f2marcel			p[13] = entry->part.p_frag;
5245f073f2marcel			le16enc(p + 14, entry->part.p_cpg);
5255f073f2marcel		} else
5265f073f2marcel			bzero(p, 16);
5275f073f2marcel
5285f073f2marcel		if (entry != NULL)
5295f073f2marcel			baseentry = LIST_NEXT(baseentry, gpe_entry);
5305f073f2marcel	}
5315f073f2marcel
5325f073f2marcel	/* Calculate checksum. */
53342a7dd5marcel	le16enc(label + 136, 0);
53442a7dd5marcel	pe = label + 148 + basetable->gpt_entries * 16;
5355f073f2marcel	sum = 0;
53642a7dd5marcel	for (p = label; p < pe; p += 2)
5375f073f2marcel		sum ^= le16dec(p);
53842a7dd5marcel	le16enc(label + 136, sum);
5395f073f2marcel
54042a7dd5marcel	error = g_write_data(cp, 0, table->bbarea, BBSIZE);
5415f073f2marcel	return (error);
5425f073f2marcel}
543