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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 * 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 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