1174326Smarcel/*- 2174326Smarcel * Copyright (c) 2007 Marcel Moolenaar 3174326Smarcel * All rights reserved. 4174326Smarcel * 5174326Smarcel * Redistribution and use in source and binary forms, with or without 6174326Smarcel * modification, are permitted provided that the following conditions 7174326Smarcel * are met: 8174326Smarcel * 9174326Smarcel * 1. Redistributions of source code must retain the above copyright 10174326Smarcel * notice, this list of conditions and the following disclaimer. 11174326Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12174326Smarcel * notice, this list of conditions and the following disclaimer in the 13174326Smarcel * documentation and/or other materials provided with the distribution. 14174326Smarcel * 15174326Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16174326Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17174326Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18174326Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19174326Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20174326Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21174326Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22174326Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23174326Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24174326Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25174326Smarcel */ 26174326Smarcel 27174326Smarcel#include <sys/cdefs.h> 28174326Smarcel__FBSDID("$FreeBSD$"); 29174326Smarcel 30174326Smarcel#include <sys/param.h> 31174326Smarcel#include <sys/bio.h> 32174326Smarcel#include <sys/disklabel.h> 33174326Smarcel#include <sys/endian.h> 34174326Smarcel#include <sys/kernel.h> 35174326Smarcel#include <sys/kobj.h> 36174326Smarcel#include <sys/limits.h> 37174326Smarcel#include <sys/lock.h> 38174326Smarcel#include <sys/malloc.h> 39174326Smarcel#include <sys/mutex.h> 40174326Smarcel#include <sys/queue.h> 41174326Smarcel#include <sys/sbuf.h> 42174326Smarcel#include <sys/systm.h> 43219029Snetchild#include <sys/sysctl.h> 44174326Smarcel#include <geom/geom.h> 45174326Smarcel#include <geom/part/g_part.h> 46174326Smarcel 47174326Smarcel#include "g_part_if.h" 48174326Smarcel 49223332Sae#define BOOT1_SIZE 512 50223332Sae#define LABEL_SIZE 512 51223332Sae#define BOOT2_OFF (BOOT1_SIZE + LABEL_SIZE) 52223332Sae#define BOOT2_SIZE (BBSIZE - BOOT2_OFF) 53223332Sae 54219029SnetchildFEATURE(geom_part_bsd, "GEOM partitioning class for BSD disklabels"); 55219029Snetchild 56174326Smarcelstruct g_part_bsd_table { 57174326Smarcel struct g_part_table base; 58188893Smarcel u_char *bbarea; 59174882Smarcel uint32_t offset; 60174326Smarcel}; 61174326Smarcel 62174326Smarcelstruct g_part_bsd_entry { 63174326Smarcel struct g_part_entry base; 64174326Smarcel struct partition part; 65174326Smarcel}; 66174326Smarcel 67174326Smarcelstatic int g_part_bsd_add(struct g_part_table *, struct g_part_entry *, 68174326Smarcel struct g_part_parms *); 69188893Smarcelstatic int g_part_bsd_bootcode(struct g_part_table *, struct g_part_parms *); 70174326Smarcelstatic int g_part_bsd_create(struct g_part_table *, struct g_part_parms *); 71174326Smarcelstatic int g_part_bsd_destroy(struct g_part_table *, struct g_part_parms *); 72188303Simpstatic void g_part_bsd_dumpconf(struct g_part_table *, struct g_part_entry *, 73178444Smarcel struct sbuf *, const char *); 74174326Smarcelstatic int g_part_bsd_dumpto(struct g_part_table *, struct g_part_entry *); 75174326Smarcelstatic int g_part_bsd_modify(struct g_part_table *, struct g_part_entry *, 76174326Smarcel struct g_part_parms *); 77188303Simpstatic const char *g_part_bsd_name(struct g_part_table *, struct g_part_entry *, 78174326Smarcel char *, size_t); 79174326Smarcelstatic int g_part_bsd_probe(struct g_part_table *, struct g_consumer *); 80174326Smarcelstatic int g_part_bsd_read(struct g_part_table *, struct g_consumer *); 81174326Smarcelstatic const char *g_part_bsd_type(struct g_part_table *, struct g_part_entry *, 82174326Smarcel char *, size_t); 83174326Smarcelstatic int g_part_bsd_write(struct g_part_table *, struct g_consumer *); 84207094Smarcelstatic int g_part_bsd_resize(struct g_part_table *, struct g_part_entry *, 85207094Smarcel struct g_part_parms *); 86174326Smarcel 87174326Smarcelstatic kobj_method_t g_part_bsd_methods[] = { 88174326Smarcel KOBJMETHOD(g_part_add, g_part_bsd_add), 89188893Smarcel KOBJMETHOD(g_part_bootcode, g_part_bsd_bootcode), 90174326Smarcel KOBJMETHOD(g_part_create, g_part_bsd_create), 91174326Smarcel KOBJMETHOD(g_part_destroy, g_part_bsd_destroy), 92178444Smarcel KOBJMETHOD(g_part_dumpconf, g_part_bsd_dumpconf), 93174326Smarcel KOBJMETHOD(g_part_dumpto, g_part_bsd_dumpto), 94174326Smarcel KOBJMETHOD(g_part_modify, g_part_bsd_modify), 95207094Smarcel KOBJMETHOD(g_part_resize, g_part_bsd_resize), 96174326Smarcel KOBJMETHOD(g_part_name, g_part_bsd_name), 97174326Smarcel KOBJMETHOD(g_part_probe, g_part_bsd_probe), 98174326Smarcel KOBJMETHOD(g_part_read, g_part_bsd_read), 99174326Smarcel KOBJMETHOD(g_part_type, g_part_bsd_type), 100174326Smarcel KOBJMETHOD(g_part_write, g_part_bsd_write), 101174326Smarcel { 0, 0 } 102174326Smarcel}; 103174326Smarcel 104174326Smarcelstatic struct g_part_scheme g_part_bsd_scheme = { 105174326Smarcel "BSD", 106174326Smarcel g_part_bsd_methods, 107174326Smarcel sizeof(struct g_part_bsd_table), 108174326Smarcel .gps_entrysz = sizeof(struct g_part_bsd_entry), 109174326Smarcel .gps_minent = 8, 110216132Sivoras .gps_maxent = 20, /* Only 22 entries fit in 512 byte sectors */ 111188893Smarcel .gps_bootcodesz = BBSIZE, 112174326Smarcel}; 113177510SmarcelG_PART_SCHEME_DECLARE(g_part_bsd); 114174326Smarcel 115174326Smarcelstatic int 116174326Smarcelbsd_parse_type(const char *type, uint8_t *fstype) 117174326Smarcel{ 118174326Smarcel const char *alias; 119174326Smarcel char *endp; 120174326Smarcel long lt; 121174326Smarcel 122174326Smarcel if (type[0] == '!') { 123174326Smarcel lt = strtol(type + 1, &endp, 0); 124174326Smarcel if (type[1] == '\0' || *endp != '\0' || lt <= 0 || lt >= 256) 125174326Smarcel return (EINVAL); 126174326Smarcel *fstype = (u_int)lt; 127174326Smarcel return (0); 128174326Smarcel } 129243237Sae alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS); 130243237Sae if (!strcasecmp(type, alias)) { 131243237Sae *fstype = FS_NANDFS; 132243237Sae return (0); 133243237Sae } 134174326Smarcel alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP); 135174326Smarcel if (!strcasecmp(type, alias)) { 136174326Smarcel *fstype = FS_SWAP; 137174326Smarcel return (0); 138174326Smarcel } 139174326Smarcel alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS); 140174326Smarcel if (!strcasecmp(type, alias)) { 141174326Smarcel *fstype = FS_BSDFFS; 142174326Smarcel return (0); 143174326Smarcel } 144174326Smarcel alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM); 145174326Smarcel if (!strcasecmp(type, alias)) { 146174326Smarcel *fstype = FS_VINUM; 147174326Smarcel return (0); 148174326Smarcel } 149174437Smarcel alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS); 150174437Smarcel if (!strcasecmp(type, alias)) { 151174437Smarcel *fstype = FS_ZFS; 152174437Smarcel return (0); 153174437Smarcel } 154174326Smarcel return (EINVAL); 155174326Smarcel} 156174326Smarcel 157174326Smarcelstatic int 158174326Smarcelg_part_bsd_add(struct g_part_table *basetable, struct g_part_entry *baseentry, 159174326Smarcel struct g_part_parms *gpp) 160174326Smarcel{ 161174326Smarcel struct g_part_bsd_entry *entry; 162174326Smarcel struct g_part_bsd_table *table; 163174326Smarcel 164174326Smarcel if (gpp->gpp_parms & G_PART_PARM_LABEL) 165174326Smarcel return (EINVAL); 166174326Smarcel 167174326Smarcel entry = (struct g_part_bsd_entry *)baseentry; 168174326Smarcel table = (struct g_part_bsd_table *)basetable; 169174326Smarcel 170174882Smarcel entry->part.p_size = gpp->gpp_size; 171174882Smarcel entry->part.p_offset = gpp->gpp_start + table->offset; 172174326Smarcel entry->part.p_fsize = 0; 173174326Smarcel entry->part.p_frag = 0; 174174326Smarcel entry->part.p_cpg = 0; 175174326Smarcel return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype)); 176174326Smarcel} 177174326Smarcel 178174326Smarcelstatic int 179188893Smarcelg_part_bsd_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) 180188893Smarcel{ 181188893Smarcel struct g_part_bsd_table *table; 182188893Smarcel const u_char *codeptr; 183188893Smarcel 184223332Sae if (gpp->gpp_codesize != BOOT1_SIZE && gpp->gpp_codesize != BBSIZE) 185223332Sae return (ENODEV); 186223332Sae 187188893Smarcel table = (struct g_part_bsd_table *)basetable; 188188893Smarcel codeptr = gpp->gpp_codeptr; 189223332Sae bcopy(codeptr, table->bbarea, BOOT1_SIZE); 190223332Sae if (gpp->gpp_codesize == BBSIZE) 191223332Sae bcopy(codeptr + BOOT2_OFF, table->bbarea + BOOT2_OFF, 192223332Sae BOOT2_SIZE); 193188893Smarcel return (0); 194188893Smarcel} 195188893Smarcel 196188893Smarcelstatic int 197174326Smarcelg_part_bsd_create(struct g_part_table *basetable, struct g_part_parms *gpp) 198174326Smarcel{ 199174326Smarcel struct g_provider *pp; 200174326Smarcel struct g_part_entry *baseentry; 201174326Smarcel struct g_part_bsd_entry *entry; 202174326Smarcel struct g_part_bsd_table *table; 203174326Smarcel u_char *ptr; 204190463Smarcel uint32_t msize, ncyls, secpercyl; 205174326Smarcel 206174326Smarcel pp = gpp->gpp_provider; 207174326Smarcel 208174326Smarcel if (pp->sectorsize < sizeof(struct disklabel)) 209174326Smarcel return (ENOSPC); 210188893Smarcel if (BBSIZE % pp->sectorsize) 211188893Smarcel return (ENOTBLK); 212174326Smarcel 213221652Sae msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 214174326Smarcel secpercyl = basetable->gpt_sectors * basetable->gpt_heads; 215174326Smarcel ncyls = msize / secpercyl; 216174326Smarcel 217174326Smarcel table = (struct g_part_bsd_table *)basetable; 218188893Smarcel table->bbarea = g_malloc(BBSIZE, M_WAITOK | M_ZERO); 219188893Smarcel ptr = table->bbarea + pp->sectorsize; 220174326Smarcel 221174326Smarcel le32enc(ptr + 0, DISKMAGIC); /* d_magic */ 222174326Smarcel le32enc(ptr + 40, pp->sectorsize); /* d_secsize */ 223174326Smarcel le32enc(ptr + 44, basetable->gpt_sectors); /* d_nsectors */ 224174326Smarcel le32enc(ptr + 48, basetable->gpt_heads); /* d_ntracks */ 225174326Smarcel le32enc(ptr + 52, ncyls); /* d_ncylinders */ 226174326Smarcel le32enc(ptr + 56, secpercyl); /* d_secpercyl */ 227174882Smarcel le32enc(ptr + 60, msize); /* d_secperunit */ 228174326Smarcel le16enc(ptr + 72, 3600); /* d_rpm */ 229174326Smarcel le32enc(ptr + 132, DISKMAGIC); /* d_magic2 */ 230174326Smarcel le16enc(ptr + 138, basetable->gpt_entries); /* d_npartitions */ 231174326Smarcel le32enc(ptr + 140, BBSIZE); /* d_bbsize */ 232174326Smarcel 233174326Smarcel basetable->gpt_first = 0; 234174882Smarcel basetable->gpt_last = msize - 1; 235174326Smarcel basetable->gpt_isleaf = 1; 236174326Smarcel 237174326Smarcel baseentry = g_part_new_entry(basetable, RAW_PART + 1, 238174326Smarcel basetable->gpt_first, basetable->gpt_last); 239174326Smarcel baseentry->gpe_internal = 1; 240174326Smarcel entry = (struct g_part_bsd_entry *)baseentry; 241174326Smarcel entry->part.p_size = basetable->gpt_last + 1; 242174882Smarcel entry->part.p_offset = table->offset; 243174326Smarcel 244174326Smarcel return (0); 245174326Smarcel} 246174326Smarcel 247174326Smarcelstatic int 248174326Smarcelg_part_bsd_destroy(struct g_part_table *basetable, struct g_part_parms *gpp) 249174326Smarcel{ 250208746Smarius struct g_part_bsd_table *table; 251174326Smarcel 252208746Smarius table = (struct g_part_bsd_table *)basetable; 253208746Smarius if (table->bbarea != NULL) 254208746Smarius g_free(table->bbarea); 255208746Smarius table->bbarea = NULL; 256208746Smarius 257174326Smarcel /* Wipe the second sector to clear the partitioning. */ 258174326Smarcel basetable->gpt_smhead |= 2; 259174326Smarcel return (0); 260174326Smarcel} 261174326Smarcel 262188303Simpstatic void 263178444Smarcelg_part_bsd_dumpconf(struct g_part_table *table, struct g_part_entry *baseentry, 264178444Smarcel struct sbuf *sb, const char *indent) 265178444Smarcel{ 266178444Smarcel struct g_part_bsd_entry *entry; 267178444Smarcel 268178444Smarcel entry = (struct g_part_bsd_entry *)baseentry; 269179750Smarcel if (indent == NULL) { 270179750Smarcel /* conftxt: libdisk compatibility */ 271179750Smarcel sbuf_printf(sb, " xs BSD xt %u", entry->part.p_fstype); 272179750Smarcel } else if (entry != NULL) { 273179750Smarcel /* confxml: partition entry information */ 274179750Smarcel sbuf_printf(sb, "%s<rawtype>%u</rawtype>\n", indent, 275179750Smarcel entry->part.p_fstype); 276179750Smarcel } else { 277179750Smarcel /* confxml: scheme information */ 278179750Smarcel } 279178444Smarcel} 280178444Smarcel 281178444Smarcelstatic int 282174326Smarcelg_part_bsd_dumpto(struct g_part_table *table, struct g_part_entry *baseentry) 283174326Smarcel{ 284174326Smarcel struct g_part_bsd_entry *entry; 285174326Smarcel 286185327Smarcel /* Allow dumping to a swap partition or an unused partition. */ 287174326Smarcel entry = (struct g_part_bsd_entry *)baseentry; 288185327Smarcel return ((entry->part.p_fstype == FS_UNUSED || 289185327Smarcel entry->part.p_fstype == FS_SWAP) ? 1 : 0); 290174326Smarcel} 291174326Smarcel 292174326Smarcelstatic int 293174326Smarcelg_part_bsd_modify(struct g_part_table *basetable, 294174326Smarcel struct g_part_entry *baseentry, struct g_part_parms *gpp) 295174326Smarcel{ 296174326Smarcel struct g_part_bsd_entry *entry; 297174326Smarcel 298174326Smarcel if (gpp->gpp_parms & G_PART_PARM_LABEL) 299174326Smarcel return (EINVAL); 300174326Smarcel 301174326Smarcel entry = (struct g_part_bsd_entry *)baseentry; 302174326Smarcel if (gpp->gpp_parms & G_PART_PARM_TYPE) 303174326Smarcel return (bsd_parse_type(gpp->gpp_type, &entry->part.p_fstype)); 304174326Smarcel return (0); 305174326Smarcel} 306174326Smarcel 307207094Smarcelstatic int 308207094Smarcelg_part_bsd_resize(struct g_part_table *basetable, 309207094Smarcel struct g_part_entry *baseentry, struct g_part_parms *gpp) 310207094Smarcel{ 311207094Smarcel struct g_part_bsd_entry *entry; 312207094Smarcel 313207094Smarcel entry = (struct g_part_bsd_entry *)baseentry; 314207094Smarcel baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; 315207094Smarcel entry->part.p_size = gpp->gpp_size; 316207094Smarcel 317207094Smarcel return (0); 318207094Smarcel} 319207094Smarcel 320188303Simpstatic const char * 321174326Smarcelg_part_bsd_name(struct g_part_table *table, struct g_part_entry *baseentry, 322174326Smarcel char *buf, size_t bufsz) 323174326Smarcel{ 324174326Smarcel 325174326Smarcel snprintf(buf, bufsz, "%c", 'a' + baseentry->gpe_index - 1); 326174326Smarcel return (buf); 327174326Smarcel} 328174326Smarcel 329174326Smarcelstatic int 330174326Smarcelg_part_bsd_probe(struct g_part_table *table, struct g_consumer *cp) 331174326Smarcel{ 332174326Smarcel struct g_provider *pp; 333174326Smarcel u_char *buf; 334174326Smarcel uint32_t magic1, magic2; 335174326Smarcel int error; 336174326Smarcel 337174326Smarcel pp = cp->provider; 338174326Smarcel 339174326Smarcel /* Sanity-check the provider. */ 340174326Smarcel if (pp->sectorsize < sizeof(struct disklabel) || 341174326Smarcel pp->mediasize < BBSIZE) 342174326Smarcel return (ENOSPC); 343188893Smarcel if (BBSIZE % pp->sectorsize) 344188893Smarcel return (ENOTBLK); 345174326Smarcel 346174326Smarcel /* Check that there's a disklabel. */ 347174326Smarcel buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); 348174326Smarcel if (buf == NULL) 349174326Smarcel return (error); 350174326Smarcel magic1 = le32dec(buf + 0); 351174326Smarcel magic2 = le32dec(buf + 132); 352174326Smarcel g_free(buf); 353174326Smarcel return ((magic1 == DISKMAGIC && magic2 == DISKMAGIC) 354183455Smarcel ? G_PART_PROBE_PRI_HIGH : ENXIO); 355174326Smarcel} 356174326Smarcel 357174326Smarcelstatic int 358174326Smarcelg_part_bsd_read(struct g_part_table *basetable, struct g_consumer *cp) 359174326Smarcel{ 360174326Smarcel struct g_provider *pp; 361174326Smarcel struct g_part_bsd_table *table; 362174326Smarcel struct g_part_entry *baseentry; 363174326Smarcel struct g_part_bsd_entry *entry; 364174326Smarcel struct partition part; 365174326Smarcel u_char *buf, *p; 366174326Smarcel off_t chs, msize; 367174326Smarcel u_int sectors, heads; 368174326Smarcel int error, index; 369174326Smarcel 370174326Smarcel pp = cp->provider; 371174326Smarcel table = (struct g_part_bsd_table *)basetable; 372221652Sae msize = MIN(pp->mediasize / pp->sectorsize, UINT32_MAX); 373174326Smarcel 374188893Smarcel table->bbarea = g_read_data(cp, 0, BBSIZE, &error); 375188893Smarcel if (table->bbarea == NULL) 376174326Smarcel return (error); 377174326Smarcel 378188893Smarcel buf = table->bbarea + pp->sectorsize; 379174326Smarcel 380174326Smarcel if (le32dec(buf + 40) != pp->sectorsize) 381174326Smarcel goto invalid_label; 382174326Smarcel sectors = le32dec(buf + 44); 383183410Smarcel if (sectors < 1 || sectors > 255) 384174326Smarcel goto invalid_label; 385174882Smarcel if (sectors != basetable->gpt_sectors && !basetable->gpt_fixgeom) { 386174326Smarcel g_part_geometry_heads(msize, sectors, &chs, &heads); 387174882Smarcel if (chs != 0) { 388174882Smarcel basetable->gpt_sectors = sectors; 389174882Smarcel basetable->gpt_heads = heads; 390174882Smarcel } 391174326Smarcel } 392174326Smarcel heads = le32dec(buf + 48); 393174326Smarcel if (heads < 1 || heads > 255) 394174326Smarcel goto invalid_label; 395174882Smarcel if (heads != basetable->gpt_heads && !basetable->gpt_fixgeom) 396174326Smarcel basetable->gpt_heads = heads; 397174882Smarcel 398174882Smarcel chs = le32dec(buf + 60); 399184264Smarcel if (chs < 1) 400174326Smarcel goto invalid_label; 401184264Smarcel /* Fix-up a sysinstall bug. */ 402184264Smarcel if (chs > msize) { 403184264Smarcel chs = msize; 404184264Smarcel le32enc(buf + 60, msize); 405184264Smarcel } 406174326Smarcel 407174326Smarcel basetable->gpt_first = 0; 408174882Smarcel basetable->gpt_last = msize - 1; 409174326Smarcel basetable->gpt_isleaf = 1; 410174326Smarcel 411174326Smarcel basetable->gpt_entries = le16dec(buf + 138); 412174326Smarcel if (basetable->gpt_entries < g_part_bsd_scheme.gps_minent || 413174326Smarcel basetable->gpt_entries > g_part_bsd_scheme.gps_maxent) 414174326Smarcel goto invalid_label; 415174326Smarcel 416174882Smarcel table->offset = le32dec(buf + 148 + RAW_PART * 16 + 4); 417174326Smarcel for (index = basetable->gpt_entries - 1; index >= 0; index--) { 418174326Smarcel p = buf + 148 + index * 16; 419174326Smarcel part.p_size = le32dec(p + 0); 420174326Smarcel part.p_offset = le32dec(p + 4); 421174326Smarcel part.p_fsize = le32dec(p + 8); 422174326Smarcel part.p_fstype = p[12]; 423174326Smarcel part.p_frag = p[13]; 424174326Smarcel part.p_cpg = le16dec(p + 14); 425174326Smarcel if (part.p_size == 0) 426174326Smarcel continue; 427174882Smarcel if (part.p_offset < table->offset) 428174326Smarcel continue; 429217924Sae if (part.p_offset - table->offset > basetable->gpt_last) 430217924Sae goto invalid_label; 431174326Smarcel baseentry = g_part_new_entry(basetable, index + 1, 432174882Smarcel part.p_offset - table->offset, 433174882Smarcel part.p_offset - table->offset + part.p_size - 1); 434174326Smarcel entry = (struct g_part_bsd_entry *)baseentry; 435174326Smarcel entry->part = part; 436185048Smarcel if (index == RAW_PART) 437174326Smarcel baseentry->gpe_internal = 1; 438174326Smarcel } 439174326Smarcel 440174326Smarcel return (0); 441174326Smarcel 442174326Smarcel invalid_label: 443174326Smarcel printf("GEOM: %s: invalid disklabel.\n", pp->name); 444188893Smarcel g_free(table->bbarea); 445217924Sae table->bbarea = NULL; 446174326Smarcel return (EINVAL); 447174326Smarcel} 448174326Smarcel 449174326Smarcelstatic const char * 450174326Smarcelg_part_bsd_type(struct g_part_table *basetable, struct g_part_entry *baseentry, 451174326Smarcel char *buf, size_t bufsz) 452174326Smarcel{ 453174326Smarcel struct g_part_bsd_entry *entry; 454174326Smarcel int type; 455174326Smarcel 456174326Smarcel entry = (struct g_part_bsd_entry *)baseentry; 457174326Smarcel type = entry->part.p_fstype; 458243237Sae if (type == FS_NANDFS) 459243237Sae return (g_part_alias_name(G_PART_ALIAS_FREEBSD_NANDFS)); 460174326Smarcel if (type == FS_SWAP) 461174326Smarcel return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP)); 462174326Smarcel if (type == FS_BSDFFS) 463174326Smarcel return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS)); 464174326Smarcel if (type == FS_VINUM) 465174326Smarcel return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM)); 466174437Smarcel if (type == FS_ZFS) 467174437Smarcel return (g_part_alias_name(G_PART_ALIAS_FREEBSD_ZFS)); 468174326Smarcel snprintf(buf, bufsz, "!%d", type); 469174326Smarcel return (buf); 470174326Smarcel} 471174326Smarcel 472174326Smarcelstatic int 473174326Smarcelg_part_bsd_write(struct g_part_table *basetable, struct g_consumer *cp) 474174326Smarcel{ 475174326Smarcel struct g_provider *pp; 476174326Smarcel struct g_part_entry *baseentry; 477174326Smarcel struct g_part_bsd_entry *entry; 478174326Smarcel struct g_part_bsd_table *table; 479174326Smarcel uint16_t sum; 480188893Smarcel u_char *label, *p, *pe; 481174326Smarcel int error, index; 482174326Smarcel 483174326Smarcel pp = cp->provider; 484174326Smarcel table = (struct g_part_bsd_table *)basetable; 485174326Smarcel baseentry = LIST_FIRST(&basetable->gpt_entry); 486188893Smarcel label = table->bbarea + pp->sectorsize; 487174326Smarcel for (index = 1; index <= basetable->gpt_entries; index++) { 488188893Smarcel p = label + 148 + (index - 1) * 16; 489174326Smarcel entry = (baseentry != NULL && index == baseentry->gpe_index) 490174326Smarcel ? (struct g_part_bsd_entry *)baseentry : NULL; 491174326Smarcel if (entry != NULL && !baseentry->gpe_deleted) { 492174326Smarcel le32enc(p + 0, entry->part.p_size); 493174326Smarcel le32enc(p + 4, entry->part.p_offset); 494174326Smarcel le32enc(p + 8, entry->part.p_fsize); 495174326Smarcel p[12] = entry->part.p_fstype; 496174326Smarcel p[13] = entry->part.p_frag; 497174326Smarcel le16enc(p + 14, entry->part.p_cpg); 498174326Smarcel } else 499174326Smarcel bzero(p, 16); 500174326Smarcel 501174326Smarcel if (entry != NULL) 502174326Smarcel baseentry = LIST_NEXT(baseentry, gpe_entry); 503174326Smarcel } 504174326Smarcel 505174326Smarcel /* Calculate checksum. */ 506188893Smarcel le16enc(label + 136, 0); 507188893Smarcel pe = label + 148 + basetable->gpt_entries * 16; 508174326Smarcel sum = 0; 509188893Smarcel for (p = label; p < pe; p += 2) 510174326Smarcel sum ^= le16dec(p); 511188893Smarcel le16enc(label + 136, sum); 512174326Smarcel 513188893Smarcel error = g_write_data(cp, 0, table->bbarea, BBSIZE); 514174326Smarcel return (error); 515174326Smarcel} 516