15aaa8fefSMarcel Moolenaar /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
45aaa8fefSMarcel Moolenaar * Copyright (c) 2007 Marcel Moolenaar
55aaa8fefSMarcel Moolenaar * All rights reserved.
65aaa8fefSMarcel Moolenaar *
75aaa8fefSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without
85aaa8fefSMarcel Moolenaar * modification, are permitted provided that the following conditions
95aaa8fefSMarcel Moolenaar * are met:
105aaa8fefSMarcel Moolenaar *
115aaa8fefSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright
125aaa8fefSMarcel Moolenaar * notice, this list of conditions and the following disclaimer.
135aaa8fefSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright
145aaa8fefSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the
155aaa8fefSMarcel Moolenaar * documentation and/or other materials provided with the distribution.
165aaa8fefSMarcel Moolenaar *
175aaa8fefSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185aaa8fefSMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195aaa8fefSMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205aaa8fefSMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215aaa8fefSMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225aaa8fefSMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235aaa8fefSMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245aaa8fefSMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255aaa8fefSMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265aaa8fefSMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275aaa8fefSMarcel Moolenaar */
285aaa8fefSMarcel Moolenaar
295aaa8fefSMarcel Moolenaar #include <sys/param.h>
305aaa8fefSMarcel Moolenaar #include <sys/bio.h>
315aaa8fefSMarcel Moolenaar #include <sys/disklabel.h>
325aaa8fefSMarcel Moolenaar #include <sys/endian.h>
335aaa8fefSMarcel Moolenaar #include <sys/kernel.h>
345aaa8fefSMarcel Moolenaar #include <sys/kobj.h>
355aaa8fefSMarcel Moolenaar #include <sys/limits.h>
365aaa8fefSMarcel Moolenaar #include <sys/lock.h>
375aaa8fefSMarcel Moolenaar #include <sys/malloc.h>
385aaa8fefSMarcel Moolenaar #include <sys/mutex.h>
395aaa8fefSMarcel Moolenaar #include <sys/queue.h>
405aaa8fefSMarcel Moolenaar #include <sys/sbuf.h>
415aaa8fefSMarcel Moolenaar #include <sys/systm.h>
42cb08c2ccSAlexander Leidinger #include <sys/sysctl.h>
435aaa8fefSMarcel Moolenaar #include <geom/geom.h>
445aaa8fefSMarcel Moolenaar #include <geom/part/g_part.h>
455aaa8fefSMarcel Moolenaar
465aaa8fefSMarcel Moolenaar #include "g_part_if.h"
475aaa8fefSMarcel Moolenaar
48503e6682SAndrey V. Elsukov #define BOOT1_SIZE 512
49503e6682SAndrey V. Elsukov #define LABEL_SIZE 512
50503e6682SAndrey V. Elsukov #define BOOT2_OFF (BOOT1_SIZE + LABEL_SIZE)
51503e6682SAndrey V. Elsukov #define BOOT2_SIZE (BBSIZE - BOOT2_OFF)
52503e6682SAndrey V. Elsukov
53cb08c2ccSAlexander Leidinger FEATURE(geom_part_bsd, "GEOM partitioning class for BSD disklabels");
54cb08c2ccSAlexander Leidinger
555aaa8fefSMarcel Moolenaar struct g_part_bsd_table {
565aaa8fefSMarcel Moolenaar struct g_part_table base;
574dedfc44SMarcel Moolenaar u_char *bbarea;
58392ffadeSMarcel Moolenaar uint32_t offset;
595aaa8fefSMarcel Moolenaar };
605aaa8fefSMarcel Moolenaar
615aaa8fefSMarcel Moolenaar struct g_part_bsd_entry {
625aaa8fefSMarcel Moolenaar struct g_part_entry base;
635aaa8fefSMarcel Moolenaar struct partition part;
645aaa8fefSMarcel Moolenaar };
655aaa8fefSMarcel Moolenaar
665aaa8fefSMarcel Moolenaar static int g_part_bsd_add(struct g_part_table *, struct g_part_entry *,
675aaa8fefSMarcel Moolenaar struct g_part_parms *);
684dedfc44SMarcel Moolenaar static int g_part_bsd_bootcode(struct g_part_table *, struct g_part_parms *);
695aaa8fefSMarcel Moolenaar static int g_part_bsd_create(struct g_part_table *, struct g_part_parms *);
705aaa8fefSMarcel Moolenaar static int g_part_bsd_destroy(struct g_part_table *, struct g_part_parms *);
71f4fddf53SWarner Losh static void g_part_bsd_dumpconf(struct g_part_table *, struct g_part_entry *,
725db67052SMarcel Moolenaar struct sbuf *, const char *);
735aaa8fefSMarcel Moolenaar static int g_part_bsd_dumpto(struct g_part_table *, struct g_part_entry *);
745aaa8fefSMarcel Moolenaar static int g_part_bsd_modify(struct g_part_table *, struct g_part_entry *,
755aaa8fefSMarcel Moolenaar struct g_part_parms *);
76f4fddf53SWarner Losh static const char *g_part_bsd_name(struct g_part_table *, struct g_part_entry *,
775aaa8fefSMarcel Moolenaar char *, size_t);
785aaa8fefSMarcel Moolenaar static int g_part_bsd_probe(struct g_part_table *, struct g_consumer *);
795aaa8fefSMarcel Moolenaar static int g_part_bsd_read(struct g_part_table *, struct g_consumer *);
805aaa8fefSMarcel Moolenaar static const char *g_part_bsd_type(struct g_part_table *, struct g_part_entry *,
815aaa8fefSMarcel Moolenaar char *, size_t);
825aaa8fefSMarcel Moolenaar static int g_part_bsd_write(struct g_part_table *, struct g_consumer *);
833f71c319SMarcel Moolenaar static int g_part_bsd_resize(struct g_part_table *, struct g_part_entry *,
843f71c319SMarcel Moolenaar struct g_part_parms *);
855aaa8fefSMarcel Moolenaar
865aaa8fefSMarcel Moolenaar static kobj_method_t g_part_bsd_methods[] = {
875aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_add, g_part_bsd_add),
884dedfc44SMarcel Moolenaar KOBJMETHOD(g_part_bootcode, g_part_bsd_bootcode),
895aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_create, g_part_bsd_create),
905aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_destroy, g_part_bsd_destroy),
915db67052SMarcel Moolenaar KOBJMETHOD(g_part_dumpconf, g_part_bsd_dumpconf),
925aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_dumpto, g_part_bsd_dumpto),
935aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_modify, g_part_bsd_modify),
943f71c319SMarcel Moolenaar KOBJMETHOD(g_part_resize, g_part_bsd_resize),
955aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_name, g_part_bsd_name),
965aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_probe, g_part_bsd_probe),
975aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_read, g_part_bsd_read),
985aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_type, g_part_bsd_type),
995aaa8fefSMarcel Moolenaar KOBJMETHOD(g_part_write, g_part_bsd_write),
1005aaa8fefSMarcel Moolenaar { 0, 0 }
1015aaa8fefSMarcel Moolenaar };
1025aaa8fefSMarcel Moolenaar
1035aaa8fefSMarcel Moolenaar static struct g_part_scheme g_part_bsd_scheme = {
1045aaa8fefSMarcel Moolenaar "BSD",
1055aaa8fefSMarcel Moolenaar g_part_bsd_methods,
1065aaa8fefSMarcel Moolenaar sizeof(struct g_part_bsd_table),
1075aaa8fefSMarcel Moolenaar .gps_entrysz = sizeof(struct g_part_bsd_entry),
1085aaa8fefSMarcel Moolenaar .gps_minent = 8,
10909c999b1SWarner Losh .gps_defent = 8,
110e5c723f1SIvan Voras .gps_maxent = 20, /* Only 22 entries fit in 512 byte sectors */
1114dedfc44SMarcel Moolenaar .gps_bootcodesz = BBSIZE,
1125aaa8fefSMarcel Moolenaar };
1134ffca444SMarcel Moolenaar G_PART_SCHEME_DECLARE(g_part_bsd);
11474d6c131SKyle Evans MODULE_VERSION(geom_part_bsd, 0);
1155aaa8fefSMarcel Moolenaar
1160640b71dSAndrey V. Elsukov static struct g_part_bsd_alias {
1170640b71dSAndrey V. Elsukov uint8_t type;
1180640b71dSAndrey V. Elsukov int alias;
1190640b71dSAndrey V. Elsukov } bsd_alias_match[] = {
1200640b71dSAndrey V. Elsukov { FS_BSDFFS, G_PART_ALIAS_FREEBSD_UFS },
1210640b71dSAndrey V. Elsukov { FS_SWAP, G_PART_ALIAS_FREEBSD_SWAP },
1220640b71dSAndrey V. Elsukov { FS_ZFS, G_PART_ALIAS_FREEBSD_ZFS },
1230640b71dSAndrey V. Elsukov { FS_VINUM, G_PART_ALIAS_FREEBSD_VINUM },
1240640b71dSAndrey V. Elsukov { FS_NANDFS, G_PART_ALIAS_FREEBSD_NANDFS },
1250640b71dSAndrey V. Elsukov { FS_HAMMER, G_PART_ALIAS_DFBSD_HAMMER },
1260640b71dSAndrey V. Elsukov { FS_HAMMER2, G_PART_ALIAS_DFBSD_HAMMER2 },
1270640b71dSAndrey V. Elsukov };
1280640b71dSAndrey V. Elsukov
1295aaa8fefSMarcel Moolenaar static int
bsd_parse_type(const char * type,uint8_t * fstype)1305aaa8fefSMarcel Moolenaar bsd_parse_type(const char *type, uint8_t *fstype)
1315aaa8fefSMarcel Moolenaar {
1325aaa8fefSMarcel Moolenaar const char *alias;
1335aaa8fefSMarcel Moolenaar char *endp;
1345aaa8fefSMarcel Moolenaar long lt;
1350640b71dSAndrey V. Elsukov int i;
1365aaa8fefSMarcel Moolenaar
1375aaa8fefSMarcel Moolenaar if (type[0] == '!') {
1385aaa8fefSMarcel Moolenaar lt = strtol(type + 1, &endp, 0);
139*accf7153SJose Luis Duran if (type[1] == '\0' || *endp != '\0' || lt < 0 || lt >= 256)
1405aaa8fefSMarcel Moolenaar return (EINVAL);
1415aaa8fefSMarcel Moolenaar *fstype = (u_int)lt;
1425aaa8fefSMarcel Moolenaar return (0);
1435aaa8fefSMarcel Moolenaar }
14463b6b7a7SPedro F. Giffuni for (i = 0; i < nitems(bsd_alias_match); i++) {
1450640b71dSAndrey V. Elsukov alias = g_part_alias_name(bsd_alias_match[i].alias);
1460640b71dSAndrey V. Elsukov if (strcasecmp(type, alias) == 0) {
1470640b71dSAndrey V. Elsukov *fstype = bsd_alias_match[i].type;
148f24a8224SMarcel Moolenaar return (0);
149f24a8224SMarcel Moolenaar }
150ddba2641SMarcel Moolenaar }
1515aaa8fefSMarcel Moolenaar return (EINVAL);
1525aaa8fefSMarcel Moolenaar }
1535aaa8fefSMarcel Moolenaar
1545aaa8fefSMarcel Moolenaar static int
g_part_bsd_add(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)1555aaa8fefSMarcel Moolenaar g_part_bsd_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
1565aaa8fefSMarcel Moolenaar struct g_part_parms *gpp)
1575aaa8fefSMarcel Moolenaar {
1585aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
1595aaa8fefSMarcel Moolenaar struct g_part_bsd_table *table;
1605aaa8fefSMarcel Moolenaar
1615aaa8fefSMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL)
1625aaa8fefSMarcel Moolenaar return (EINVAL);
1635aaa8fefSMarcel Moolenaar
1645aaa8fefSMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
1655aaa8fefSMarcel Moolenaar table = (struct g_part_bsd_table *)basetable;
1665aaa8fefSMarcel Moolenaar
167392ffadeSMarcel Moolenaar entry->part.p_size = gpp->gpp_size;
168392ffadeSMarcel Moolenaar entry->part.p_offset = gpp->gpp_start + table->offset;
1695aaa8fefSMarcel Moolenaar entry->part.p_fsize = 0;
1705aaa8fefSMarcel Moolenaar entry->part.p_frag = 0;
1715aaa8fefSMarcel Moolenaar entry->part.p_cpg = 0;
1725aaa8fefSMarcel Moolenaar return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype));
1735aaa8fefSMarcel Moolenaar }
1745aaa8fefSMarcel Moolenaar
1755aaa8fefSMarcel Moolenaar static int
g_part_bsd_bootcode(struct g_part_table * basetable,struct g_part_parms * gpp)1764dedfc44SMarcel Moolenaar g_part_bsd_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp)
1774dedfc44SMarcel Moolenaar {
1784dedfc44SMarcel Moolenaar struct g_part_bsd_table *table;
1794dedfc44SMarcel Moolenaar const u_char *codeptr;
1804dedfc44SMarcel Moolenaar
181503e6682SAndrey V. Elsukov if (gpp->gpp_codesize != BOOT1_SIZE && gpp->gpp_codesize != BBSIZE)
182503e6682SAndrey V. Elsukov return (ENODEV);
183503e6682SAndrey V. Elsukov
1844dedfc44SMarcel Moolenaar table = (struct g_part_bsd_table *)basetable;
1854dedfc44SMarcel Moolenaar codeptr = gpp->gpp_codeptr;
186503e6682SAndrey V. Elsukov bcopy(codeptr, table->bbarea, BOOT1_SIZE);
187503e6682SAndrey V. Elsukov if (gpp->gpp_codesize == BBSIZE)
188503e6682SAndrey V. Elsukov bcopy(codeptr + BOOT2_OFF, table->bbarea + BOOT2_OFF,
189503e6682SAndrey V. Elsukov BOOT2_SIZE);
1904dedfc44SMarcel Moolenaar return (0);
1914dedfc44SMarcel Moolenaar }
1924dedfc44SMarcel Moolenaar
1934dedfc44SMarcel Moolenaar static int
g_part_bsd_create(struct g_part_table * basetable,struct g_part_parms * gpp)1945aaa8fefSMarcel Moolenaar g_part_bsd_create(struct g_part_table *basetable, struct g_part_parms *gpp)
1955aaa8fefSMarcel Moolenaar {
1965aaa8fefSMarcel Moolenaar struct g_provider *pp;
1975aaa8fefSMarcel Moolenaar struct g_part_entry *baseentry;
1985aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
1995aaa8fefSMarcel Moolenaar struct g_part_bsd_table *table;
2005aaa8fefSMarcel Moolenaar u_char *ptr;
201ee94c7efSMarcel Moolenaar uint32_t msize, ncyls, secpercyl;
2025aaa8fefSMarcel Moolenaar
2035aaa8fefSMarcel Moolenaar pp = gpp->gpp_provider;
2045aaa8fefSMarcel Moolenaar
2055aaa8fefSMarcel Moolenaar if (pp->sectorsize < sizeof(struct disklabel))
2065aaa8fefSMarcel Moolenaar return (ENOSPC);
2074dedfc44SMarcel Moolenaar if (BBSIZE % pp->sectorsize)
2084dedfc44SMarcel Moolenaar return (ENOTBLK);
2095aaa8fefSMarcel Moolenaar
2102920db17SAndrey V. Elsukov msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
2115aaa8fefSMarcel Moolenaar secpercyl = basetable->gpt_sectors * basetable->gpt_heads;
2125aaa8fefSMarcel Moolenaar ncyls = msize / secpercyl;
2135aaa8fefSMarcel Moolenaar
2145aaa8fefSMarcel Moolenaar table = (struct g_part_bsd_table *)basetable;
2154dedfc44SMarcel Moolenaar table->bbarea = g_malloc(BBSIZE, M_WAITOK | M_ZERO);
2164dedfc44SMarcel Moolenaar ptr = table->bbarea + pp->sectorsize;
2175aaa8fefSMarcel Moolenaar
2185aaa8fefSMarcel Moolenaar le32enc(ptr + 0, DISKMAGIC); /* d_magic */
2195aaa8fefSMarcel Moolenaar le32enc(ptr + 40, pp->sectorsize); /* d_secsize */
2205aaa8fefSMarcel Moolenaar le32enc(ptr + 44, basetable->gpt_sectors); /* d_nsectors */
2215aaa8fefSMarcel Moolenaar le32enc(ptr + 48, basetable->gpt_heads); /* d_ntracks */
2225aaa8fefSMarcel Moolenaar le32enc(ptr + 52, ncyls); /* d_ncylinders */
2235aaa8fefSMarcel Moolenaar le32enc(ptr + 56, secpercyl); /* d_secpercyl */
224392ffadeSMarcel Moolenaar le32enc(ptr + 60, msize); /* d_secperunit */
2255aaa8fefSMarcel Moolenaar le16enc(ptr + 72, 3600); /* d_rpm */
2265aaa8fefSMarcel Moolenaar le32enc(ptr + 132, DISKMAGIC); /* d_magic2 */
2275aaa8fefSMarcel Moolenaar le16enc(ptr + 138, basetable->gpt_entries); /* d_npartitions */
2285aaa8fefSMarcel Moolenaar le32enc(ptr + 140, BBSIZE); /* d_bbsize */
2295aaa8fefSMarcel Moolenaar
2305aaa8fefSMarcel Moolenaar basetable->gpt_first = 0;
231392ffadeSMarcel Moolenaar basetable->gpt_last = msize - 1;
2325aaa8fefSMarcel Moolenaar basetable->gpt_isleaf = 1;
2335aaa8fefSMarcel Moolenaar
2345aaa8fefSMarcel Moolenaar baseentry = g_part_new_entry(basetable, RAW_PART + 1,
2355aaa8fefSMarcel Moolenaar basetable->gpt_first, basetable->gpt_last);
2365aaa8fefSMarcel Moolenaar baseentry->gpe_internal = 1;
2375aaa8fefSMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
2385aaa8fefSMarcel Moolenaar entry->part.p_size = basetable->gpt_last + 1;
239392ffadeSMarcel Moolenaar entry->part.p_offset = table->offset;
2405aaa8fefSMarcel Moolenaar
2415aaa8fefSMarcel Moolenaar return (0);
2425aaa8fefSMarcel Moolenaar }
2435aaa8fefSMarcel Moolenaar
2445aaa8fefSMarcel Moolenaar static int
g_part_bsd_destroy(struct g_part_table * basetable,struct g_part_parms * gpp)2455aaa8fefSMarcel Moolenaar g_part_bsd_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
2465aaa8fefSMarcel Moolenaar {
24736066952SMarius Strobl struct g_part_bsd_table *table;
24836066952SMarius Strobl
24936066952SMarius Strobl table = (struct g_part_bsd_table *)basetable;
25036066952SMarius Strobl g_free(table->bbarea);
25136066952SMarius Strobl table->bbarea = NULL;
2525aaa8fefSMarcel Moolenaar
2535aaa8fefSMarcel Moolenaar /* Wipe the second sector to clear the partitioning. */
2545aaa8fefSMarcel Moolenaar basetable->gpt_smhead |= 2;
2555aaa8fefSMarcel Moolenaar return (0);
2565aaa8fefSMarcel Moolenaar }
2575aaa8fefSMarcel Moolenaar
258f4fddf53SWarner Losh static void
g_part_bsd_dumpconf(struct g_part_table * table,struct g_part_entry * baseentry,struct sbuf * sb,const char * indent)2595db67052SMarcel Moolenaar g_part_bsd_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry,
2605db67052SMarcel Moolenaar struct sbuf *sb, const char *indent)
2615db67052SMarcel Moolenaar {
2625db67052SMarcel Moolenaar struct g_part_bsd_entry *entry;
2635db67052SMarcel Moolenaar
2645db67052SMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
26540b075d3SMarcel Moolenaar if (indent == NULL) {
26640b075d3SMarcel Moolenaar /* conftxt: libdisk compatibility */
2675db67052SMarcel Moolenaar sbuf_printf(sb, " xs BSD xt %u", entry->part.p_fstype);
26840b075d3SMarcel Moolenaar } else if (entry != NULL) {
26940b075d3SMarcel Moolenaar /* confxml: partition entry information */
27040b075d3SMarcel Moolenaar sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent,
27140b075d3SMarcel Moolenaar entry->part.p_fstype);
27240b075d3SMarcel Moolenaar } else {
27340b075d3SMarcel Moolenaar /* confxml: scheme information */
27440b075d3SMarcel Moolenaar }
2755db67052SMarcel Moolenaar }
2765db67052SMarcel Moolenaar
2775db67052SMarcel Moolenaar static int
g_part_bsd_dumpto(struct g_part_table * table,struct g_part_entry * baseentry)2785aaa8fefSMarcel Moolenaar g_part_bsd_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
2795aaa8fefSMarcel Moolenaar {
2805aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
2815aaa8fefSMarcel Moolenaar
28295fc2698SMarcel Moolenaar /* Allow dumping to a swap partition or an unused partition. */
2835aaa8fefSMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
28495fc2698SMarcel Moolenaar return ((entry->part.p_fstype == FS_UNUSED ||
28595fc2698SMarcel Moolenaar entry->part.p_fstype == FS_SWAP) ? 1 : 0);
2865aaa8fefSMarcel Moolenaar }
2875aaa8fefSMarcel Moolenaar
2885aaa8fefSMarcel Moolenaar static int
g_part_bsd_modify(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)2895aaa8fefSMarcel Moolenaar g_part_bsd_modify(struct g_part_table *basetable,
2905aaa8fefSMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp)
2915aaa8fefSMarcel Moolenaar {
2925aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
2935aaa8fefSMarcel Moolenaar
2945aaa8fefSMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_LABEL)
2955aaa8fefSMarcel Moolenaar return (EINVAL);
2965aaa8fefSMarcel Moolenaar
2975aaa8fefSMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
2985aaa8fefSMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_TYPE)
2995aaa8fefSMarcel Moolenaar return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype));
3005aaa8fefSMarcel Moolenaar return (0);
3015aaa8fefSMarcel Moolenaar }
3025aaa8fefSMarcel Moolenaar
303884c8e4fSAndrey V. Elsukov static void
bsd_set_rawsize(struct g_part_table * basetable,struct g_provider * pp)304884c8e4fSAndrey V. Elsukov bsd_set_rawsize(struct g_part_table *basetable, struct g_provider *pp)
305884c8e4fSAndrey V. Elsukov {
306884c8e4fSAndrey V. Elsukov struct g_part_bsd_table *table;
307884c8e4fSAndrey V. Elsukov struct g_part_bsd_entry *entry;
308884c8e4fSAndrey V. Elsukov struct g_part_entry *baseentry;
309884c8e4fSAndrey V. Elsukov uint32_t msize;
310884c8e4fSAndrey V. Elsukov
311884c8e4fSAndrey V. Elsukov table = (struct g_part_bsd_table *)basetable;
312884c8e4fSAndrey V. Elsukov msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
313884c8e4fSAndrey V. Elsukov le32enc(table->bbarea + pp->sectorsize + 60, msize); /* d_secperunit */
314884c8e4fSAndrey V. Elsukov basetable->gpt_last = msize - 1;
315884c8e4fSAndrey V. Elsukov LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
316884c8e4fSAndrey V. Elsukov if (baseentry->gpe_index != RAW_PART + 1)
317884c8e4fSAndrey V. Elsukov continue;
318884c8e4fSAndrey V. Elsukov baseentry->gpe_end = basetable->gpt_last;
319884c8e4fSAndrey V. Elsukov entry = (struct g_part_bsd_entry *)baseentry;
320884c8e4fSAndrey V. Elsukov entry->part.p_size = msize;
321884c8e4fSAndrey V. Elsukov return;
322884c8e4fSAndrey V. Elsukov }
323884c8e4fSAndrey V. Elsukov }
324884c8e4fSAndrey V. Elsukov
3253f71c319SMarcel Moolenaar static int
g_part_bsd_resize(struct g_part_table * basetable,struct g_part_entry * baseentry,struct g_part_parms * gpp)3263f71c319SMarcel Moolenaar g_part_bsd_resize(struct g_part_table *basetable,
3273f71c319SMarcel Moolenaar struct g_part_entry *baseentry, struct g_part_parms *gpp)
3283f71c319SMarcel Moolenaar {
3293f71c319SMarcel Moolenaar struct g_part_bsd_entry *entry;
330884c8e4fSAndrey V. Elsukov struct g_provider *pp;
3313f71c319SMarcel Moolenaar
332884c8e4fSAndrey V. Elsukov if (baseentry == NULL) {
333884c8e4fSAndrey V. Elsukov pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider;
334884c8e4fSAndrey V. Elsukov bsd_set_rawsize(basetable, pp);
335884c8e4fSAndrey V. Elsukov return (0);
336884c8e4fSAndrey V. Elsukov }
3373f71c319SMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
3383f71c319SMarcel Moolenaar baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1;
3393f71c319SMarcel Moolenaar entry->part.p_size = gpp->gpp_size;
3403f71c319SMarcel Moolenaar
3413f71c319SMarcel Moolenaar return (0);
3423f71c319SMarcel Moolenaar }
3433f71c319SMarcel Moolenaar
344f4fddf53SWarner Losh static const char *
g_part_bsd_name(struct g_part_table * table,struct g_part_entry * baseentry,char * buf,size_t bufsz)3455aaa8fefSMarcel Moolenaar g_part_bsd_name(struct g_part_table *table, struct g_part_entry *baseentry,
3465aaa8fefSMarcel Moolenaar char *buf, size_t bufsz)
3475aaa8fefSMarcel Moolenaar {
3485aaa8fefSMarcel Moolenaar
3495aaa8fefSMarcel Moolenaar snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1);
3505aaa8fefSMarcel Moolenaar return (buf);
3515aaa8fefSMarcel Moolenaar }
3525aaa8fefSMarcel Moolenaar
3535aaa8fefSMarcel Moolenaar static int
g_part_bsd_probe(struct g_part_table * table,struct g_consumer * cp)3545aaa8fefSMarcel Moolenaar g_part_bsd_probe(struct g_part_table *table, struct g_consumer *cp)
3555aaa8fefSMarcel Moolenaar {
3565aaa8fefSMarcel Moolenaar struct g_provider *pp;
3575aaa8fefSMarcel Moolenaar u_char *buf;
3585aaa8fefSMarcel Moolenaar uint32_t magic1, magic2;
3595aaa8fefSMarcel Moolenaar int error;
3605aaa8fefSMarcel Moolenaar
3615aaa8fefSMarcel Moolenaar pp = cp->provider;
3625aaa8fefSMarcel Moolenaar
3635aaa8fefSMarcel Moolenaar /* Sanity-check the provider. */
3645aaa8fefSMarcel Moolenaar if (pp->sectorsize < sizeof(struct disklabel) ||
3655aaa8fefSMarcel Moolenaar pp->mediasize < BBSIZE)
3665aaa8fefSMarcel Moolenaar return (ENOSPC);
3674dedfc44SMarcel Moolenaar if (BBSIZE % pp->sectorsize)
3684dedfc44SMarcel Moolenaar return (ENOTBLK);
3695aaa8fefSMarcel Moolenaar
3705aaa8fefSMarcel Moolenaar /* Check that there's a disklabel. */
3715aaa8fefSMarcel Moolenaar buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error);
3725aaa8fefSMarcel Moolenaar if (buf == NULL)
3735aaa8fefSMarcel Moolenaar return (error);
3745aaa8fefSMarcel Moolenaar magic1 = le32dec(buf + 0);
3755aaa8fefSMarcel Moolenaar magic2 = le32dec(buf + 132);
3765aaa8fefSMarcel Moolenaar g_free(buf);
3775aaa8fefSMarcel Moolenaar return ((magic1 == DISKMAGIC && magic2 == DISKMAGIC)
378a87faebbSMarcel Moolenaar ? G_PART_PROBE_PRI_HIGH : ENXIO);
3795aaa8fefSMarcel Moolenaar }
3805aaa8fefSMarcel Moolenaar
3815aaa8fefSMarcel Moolenaar static int
g_part_bsd_read(struct g_part_table * basetable,struct g_consumer * cp)3825aaa8fefSMarcel Moolenaar g_part_bsd_read(struct g_part_table *basetable, struct g_consumer *cp)
3835aaa8fefSMarcel Moolenaar {
3845aaa8fefSMarcel Moolenaar struct g_provider *pp;
3855aaa8fefSMarcel Moolenaar struct g_part_bsd_table *table;
3865aaa8fefSMarcel Moolenaar struct g_part_entry *baseentry;
3875aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
3885aaa8fefSMarcel Moolenaar struct partition part;
3895aaa8fefSMarcel Moolenaar u_char *buf, *p;
3905aaa8fefSMarcel Moolenaar off_t chs, msize;
3915aaa8fefSMarcel Moolenaar u_int sectors, heads;
3925aaa8fefSMarcel Moolenaar int error, index;
3935aaa8fefSMarcel Moolenaar
3945aaa8fefSMarcel Moolenaar pp = cp->provider;
3955aaa8fefSMarcel Moolenaar table = (struct g_part_bsd_table *)basetable;
3962920db17SAndrey V. Elsukov msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX);
3975aaa8fefSMarcel Moolenaar
3984dedfc44SMarcel Moolenaar table->bbarea = g_read_data(cp, 0, BBSIZE, &error);
3994dedfc44SMarcel Moolenaar if (table->bbarea == NULL)
4005aaa8fefSMarcel Moolenaar return (error);
4015aaa8fefSMarcel Moolenaar
4024dedfc44SMarcel Moolenaar buf = table->bbarea + pp->sectorsize;
4035aaa8fefSMarcel Moolenaar
4045aaa8fefSMarcel Moolenaar if (le32dec(buf + 40) != pp->sectorsize)
4055aaa8fefSMarcel Moolenaar goto invalid_label;
4065aaa8fefSMarcel Moolenaar sectors = le32dec(buf + 44);
407404cfb5eSMarcel Moolenaar if (sectors < 1 || sectors > 255)
4085aaa8fefSMarcel Moolenaar goto invalid_label;
409392ffadeSMarcel Moolenaar if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) {
4105aaa8fefSMarcel Moolenaar g_part_geometry_heads(msize, sectors, &chs, &heads);
411392ffadeSMarcel Moolenaar if (chs != 0) {
4125aaa8fefSMarcel Moolenaar basetable->gpt_sectors = sectors;
4135aaa8fefSMarcel Moolenaar basetable->gpt_heads = heads;
4145aaa8fefSMarcel Moolenaar }
415392ffadeSMarcel Moolenaar }
4165aaa8fefSMarcel Moolenaar heads = le32dec(buf + 48);
4175aaa8fefSMarcel Moolenaar if (heads < 1 || heads > 255)
4185aaa8fefSMarcel Moolenaar goto invalid_label;
419392ffadeSMarcel Moolenaar if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom)
4205aaa8fefSMarcel Moolenaar basetable->gpt_heads = heads;
421392ffadeSMarcel Moolenaar
422392ffadeSMarcel Moolenaar chs = le32dec(buf + 60);
42338a2db2eSMarcel Moolenaar if (chs < 1)
4245aaa8fefSMarcel Moolenaar goto invalid_label;
42538a2db2eSMarcel Moolenaar /* Fix-up a sysinstall bug. */
42638a2db2eSMarcel Moolenaar if (chs > msize) {
42738a2db2eSMarcel Moolenaar chs = msize;
42838a2db2eSMarcel Moolenaar le32enc(buf + 60, msize);
42938a2db2eSMarcel Moolenaar }
4305aaa8fefSMarcel Moolenaar
4315aaa8fefSMarcel Moolenaar basetable->gpt_first = 0;
432392ffadeSMarcel Moolenaar basetable->gpt_last = msize - 1;
4335aaa8fefSMarcel Moolenaar basetable->gpt_isleaf = 1;
4345aaa8fefSMarcel Moolenaar
4355aaa8fefSMarcel Moolenaar basetable->gpt_entries = le16dec(buf + 138);
4365aaa8fefSMarcel Moolenaar if (basetable->gpt_entries < g_part_bsd_scheme.gps_minent ||
4375aaa8fefSMarcel Moolenaar basetable->gpt_entries > g_part_bsd_scheme.gps_maxent)
4385aaa8fefSMarcel Moolenaar goto invalid_label;
4395aaa8fefSMarcel Moolenaar
440392ffadeSMarcel Moolenaar table->offset = le32dec(buf + 148 + RAW_PART * 16 + 4);
4415aaa8fefSMarcel Moolenaar for (index = basetable->gpt_entries - 1; index >= 0; index--) {
4425aaa8fefSMarcel Moolenaar p = buf + 148 + index * 16;
4435aaa8fefSMarcel Moolenaar part.p_size = le32dec(p + 0);
4445aaa8fefSMarcel Moolenaar part.p_offset = le32dec(p + 4);
4455aaa8fefSMarcel Moolenaar part.p_fsize = le32dec(p + 8);
4465aaa8fefSMarcel Moolenaar part.p_fstype = p[12];
4475aaa8fefSMarcel Moolenaar part.p_frag = p[13];
4485aaa8fefSMarcel Moolenaar part.p_cpg = le16dec(p + 14);
4495aaa8fefSMarcel Moolenaar if (part.p_size == 0)
4505aaa8fefSMarcel Moolenaar continue;
451392ffadeSMarcel Moolenaar if (part.p_offset < table->offset)
4525aaa8fefSMarcel Moolenaar continue;
45313131606SAndrey V. Elsukov if (part.p_offset - table->offset > basetable->gpt_last)
45413131606SAndrey V. Elsukov goto invalid_label;
4555aaa8fefSMarcel Moolenaar baseentry = g_part_new_entry(basetable, index + 1,
456392ffadeSMarcel Moolenaar part.p_offset - table->offset,
457392ffadeSMarcel Moolenaar part.p_offset - table->offset + part.p_size - 1);
4585aaa8fefSMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
4595aaa8fefSMarcel Moolenaar entry->part = part;
4601a696559SMarcel Moolenaar if (index == RAW_PART)
4615aaa8fefSMarcel Moolenaar baseentry->gpe_internal = 1;
4625aaa8fefSMarcel Moolenaar }
4635aaa8fefSMarcel Moolenaar
4645aaa8fefSMarcel Moolenaar return (0);
4655aaa8fefSMarcel Moolenaar
4665aaa8fefSMarcel Moolenaar invalid_label:
4675aaa8fefSMarcel Moolenaar printf("GEOM: %s: invalid disklabel.\n", pp->name);
4684dedfc44SMarcel Moolenaar g_free(table->bbarea);
46913131606SAndrey V. Elsukov table->bbarea = NULL;
4705aaa8fefSMarcel Moolenaar return (EINVAL);
4715aaa8fefSMarcel Moolenaar }
4725aaa8fefSMarcel Moolenaar
4735aaa8fefSMarcel Moolenaar static const char *
g_part_bsd_type(struct g_part_table * basetable,struct g_part_entry * baseentry,char * buf,size_t bufsz)4745aaa8fefSMarcel Moolenaar g_part_bsd_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
4755aaa8fefSMarcel Moolenaar char *buf, size_t bufsz)
4765aaa8fefSMarcel Moolenaar {
4775aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
4785aaa8fefSMarcel Moolenaar int type;
4795aaa8fefSMarcel Moolenaar
4805aaa8fefSMarcel Moolenaar entry = (struct g_part_bsd_entry *)baseentry;
4815aaa8fefSMarcel Moolenaar type = entry->part.p_fstype;
482f24a8224SMarcel Moolenaar if (type == FS_NANDFS)
483f24a8224SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS));
4845aaa8fefSMarcel Moolenaar if (type == FS_SWAP)
4855aaa8fefSMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
4865aaa8fefSMarcel Moolenaar if (type == FS_BSDFFS)
4875aaa8fefSMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
4885aaa8fefSMarcel Moolenaar if (type == FS_VINUM)
4895aaa8fefSMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
490ddba2641SMarcel Moolenaar if (type == FS_ZFS)
491ddba2641SMarcel Moolenaar return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS));
4925aaa8fefSMarcel Moolenaar snprintf(buf, bufsz, "!%d", type);
4935aaa8fefSMarcel Moolenaar return (buf);
4945aaa8fefSMarcel Moolenaar }
4955aaa8fefSMarcel Moolenaar
4965aaa8fefSMarcel Moolenaar static int
g_part_bsd_write(struct g_part_table * basetable,struct g_consumer * cp)4975aaa8fefSMarcel Moolenaar g_part_bsd_write(struct g_part_table *basetable, struct g_consumer *cp)
4985aaa8fefSMarcel Moolenaar {
4995aaa8fefSMarcel Moolenaar struct g_provider *pp;
5005aaa8fefSMarcel Moolenaar struct g_part_entry *baseentry;
5015aaa8fefSMarcel Moolenaar struct g_part_bsd_entry *entry;
5025aaa8fefSMarcel Moolenaar struct g_part_bsd_table *table;
5035aaa8fefSMarcel Moolenaar uint16_t sum;
5044dedfc44SMarcel Moolenaar u_char *label, *p, *pe;
5055aaa8fefSMarcel Moolenaar int error, index;
5065aaa8fefSMarcel Moolenaar
5075aaa8fefSMarcel Moolenaar pp = cp->provider;
5085aaa8fefSMarcel Moolenaar table = (struct g_part_bsd_table *)basetable;
5095aaa8fefSMarcel Moolenaar baseentry = LIST_FIRST(&basetable->gpt_entry);
5104dedfc44SMarcel Moolenaar label = table->bbarea + pp->sectorsize;
5115aaa8fefSMarcel Moolenaar for (index = 1; index <= basetable->gpt_entries; index++) {
5124dedfc44SMarcel Moolenaar p = label + 148 + (index - 1) * 16;
5135aaa8fefSMarcel Moolenaar entry = (baseentry != NULL && index == baseentry->gpe_index)
5145aaa8fefSMarcel Moolenaar ? (struct g_part_bsd_entry *)baseentry : NULL;
5155aaa8fefSMarcel Moolenaar if (entry != NULL && !baseentry->gpe_deleted) {
5165aaa8fefSMarcel Moolenaar le32enc(p + 0, entry->part.p_size);
5175aaa8fefSMarcel Moolenaar le32enc(p + 4, entry->part.p_offset);
5185aaa8fefSMarcel Moolenaar le32enc(p + 8, entry->part.p_fsize);
5195aaa8fefSMarcel Moolenaar p[12] = entry->part.p_fstype;
5205aaa8fefSMarcel Moolenaar p[13] = entry->part.p_frag;
5215aaa8fefSMarcel Moolenaar le16enc(p + 14, entry->part.p_cpg);
5225aaa8fefSMarcel Moolenaar } else
5235aaa8fefSMarcel Moolenaar bzero(p, 16);
5245aaa8fefSMarcel Moolenaar
5255aaa8fefSMarcel Moolenaar if (entry != NULL)
5265aaa8fefSMarcel Moolenaar baseentry = LIST_NEXT(baseentry, gpe_entry);
5275aaa8fefSMarcel Moolenaar }
5285aaa8fefSMarcel Moolenaar
5295aaa8fefSMarcel Moolenaar /* Calculate checksum. */
5304dedfc44SMarcel Moolenaar le16enc(label + 136, 0);
5314dedfc44SMarcel Moolenaar pe = label + 148 + basetable->gpt_entries * 16;
5325aaa8fefSMarcel Moolenaar sum = 0;
5334dedfc44SMarcel Moolenaar for (p = label; p < pe; p += 2)
5345aaa8fefSMarcel Moolenaar sum ^= le16dec(p);
5354dedfc44SMarcel Moolenaar le16enc(label + 136, sum);
5365aaa8fefSMarcel Moolenaar
5374dedfc44SMarcel Moolenaar error = g_write_data(cp, 0, table->bbarea, BBSIZE);
5385aaa8fefSMarcel Moolenaar return (error);
5395aaa8fefSMarcel Moolenaar }
540