version 1.13, 2015/11/29 00:14:46 |
version 1.14, 2015/12/01 09:05:33 |
Line 37 __RCSID("$NetBSD$"); |
|
Line 37 __RCSID("$NetBSD$"); |
|
#endif |
#endif |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
#include <sys/param.h> |
|
#include <sys/stat.h> |
#include <sys/bootblock.h> |
#include <sys/bootblock.h> |
|
|
#include <err.h> |
#include <err.h> |
Line 48 __RCSID("$NetBSD$"); |
|
Line 50 __RCSID("$NetBSD$"); |
|
|
|
#include "map.h" |
#include "map.h" |
#include "gpt.h" |
#include "gpt.h" |
|
#include "gpt_private.h" |
|
|
static int force; |
static int force; |
|
static u_int parts; |
static int primary_only; |
static int primary_only; |
|
|
const char createmsg[] = "create [-fp] device ..."; |
const char createmsg[] = "create [-fP] [-p <partitions>]"; |
|
|
__dead static void |
static int |
usage_create(void) |
usage_create(void) |
{ |
{ |
|
|
fprintf(stderr, |
fprintf(stderr, |
"usage: %s %s\n", getprogname(), createmsg); |
"usage: %s %s\n", getprogname(), createmsg); |
exit(1); |
return -1; |
} |
} |
|
|
static void |
static int |
create(int fd) |
create(gpt_t gpt) |
{ |
{ |
off_t blocks, last; |
off_t blocks, last; |
map_t *gpt, *tpg; |
map_t map; |
map_t *tbl, *lbt; |
|
map_t *map; |
|
struct mbr *mbr; |
struct mbr *mbr; |
struct gpt_hdr *hdr; |
struct gpt_hdr *hdr; |
struct gpt_ent *ent; |
struct gpt_ent *ent; |
unsigned int i; |
unsigned int i; |
|
void *p; |
|
|
last = mediasz / secsz - 1LL; |
last = gpt->mediasz / gpt->secsz - 1LL; |
|
|
if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL || |
if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || |
map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) { |
map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { |
warnx("%s: error: device already contains a GPT", device_name); |
gpt_warnx(gpt, "Device already contains a GPT"); |
return; |
return -1; |
} |
} |
map = map_find(MAP_TYPE_MBR); |
map = map_find(gpt, MAP_TYPE_MBR); |
if (map != NULL) { |
if (map != NULL) { |
if (!force) { |
if (!force) { |
warnx("%s: error: device contains a MBR", device_name); |
gpt_warnx(gpt, "Device contains a MBR"); |
return; |
return -1; |
} |
} |
|
|
/* Nuke the MBR in our internal map. */ |
/* Nuke the MBR in our internal map. */ |
map->map_type = MAP_TYPE_UNUSED; |
map->map_type = MAP_TYPE_UNUSED; |
} |
} |
|
|
/* |
/* |
* Create PMBR. |
* Create PMBR. |
*/ |
*/ |
if (map_find(MAP_TYPE_PMBR) == NULL) { |
if (map_find(gpt, MAP_TYPE_PMBR) == NULL) { |
if (map_free(0LL, 1LL) == 0) { |
if (map_free(gpt, 0LL, 1LL) == 0) { |
warnx("%s: error: no room for the PMBR", device_name); |
gpt_warnx(gpt, "No room for the PMBR"); |
return; |
return -1; |
|
} |
|
mbr = gpt_read(gpt, 0LL, 1); |
|
if (mbr == NULL) { |
|
gpt_warnx(gpt, "Error reading MBR"); |
|
return -1; |
} |
} |
mbr = gpt_read(fd, 0LL, 1); |
|
memset(mbr, 0, sizeof(*mbr)); |
memset(mbr, 0, sizeof(*mbr)); |
mbr->mbr_sig = htole16(MBR_SIG); |
mbr->mbr_sig = htole16(MBR_SIG); |
mbr->mbr_part[0].part_shd = 0x00; |
gpt_create_pmbr_part(mbr->mbr_part, last); |
mbr->mbr_part[0].part_ssect = 0x02; |
|
mbr->mbr_part[0].part_scyl = 0x00; |
map = map_add(gpt, 0LL, 1LL, MAP_TYPE_PMBR, mbr); |
mbr->mbr_part[0].part_typ = MBR_PTYPE_PMBR; |
gpt_write(gpt, map); |
mbr->mbr_part[0].part_ehd = 0xfe; |
|
mbr->mbr_part[0].part_esect = 0xff; |
|
mbr->mbr_part[0].part_ecyl = 0xff; |
|
mbr->mbr_part[0].part_start_lo = htole16(1); |
|
if (last > 0xffffffff) { |
|
mbr->mbr_part[0].part_size_lo = htole16(0xffff); |
|
mbr->mbr_part[0].part_size_hi = htole16(0xffff); |
|
} else { |
|
mbr->mbr_part[0].part_size_lo = htole16(last); |
|
mbr->mbr_part[0].part_size_hi = htole16(last >> 16); |
|
} |
|
map = map_add(0LL, 1LL, MAP_TYPE_PMBR, mbr); |
|
gpt_write(fd, map); |
|
} |
} |
|
|
/* Get the amount of free space after the MBR */ |
/* Get the amount of free space after the MBR */ |
blocks = map_free(1LL, 0LL); |
blocks = map_free(gpt, 1LL, 0LL); |
if (blocks == 0LL) { |
if (blocks == 0LL) { |
warnx("%s: error: no room for the GPT header", device_name); |
gpt_warnx(gpt, "No room for the GPT header"); |
return; |
return -1; |
} |
} |
|
|
/* Don't create more than parts entries. */ |
/* Don't create more than parts entries. */ |
if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) { |
if ((uint64_t)(blocks - 1) * gpt->secsz > |
blocks = (parts * sizeof(struct gpt_ent)) / secsz; |
parts * sizeof(struct gpt_ent)) { |
if ((parts * sizeof(struct gpt_ent)) % secsz) |
blocks = (parts * sizeof(struct gpt_ent)) / gpt->secsz; |
|
if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) |
blocks++; |
blocks++; |
blocks++; /* Don't forget the header itself */ |
blocks++; /* Don't forget the header itself */ |
} |
} |
|
|
* Get the amount of free space at the end of the device and |
* Get the amount of free space at the end of the device and |
* calculate the size for the GPT structures. |
* calculate the size for the GPT structures. |
*/ |
*/ |
map = map_last(); |
map = map_last(gpt); |
if (map->map_type != MAP_TYPE_UNUSED) { |
if (map->map_type != MAP_TYPE_UNUSED) { |
warnx("%s: error: no room for the backup header", device_name); |
gpt_warnx(gpt, "No room for the backup header"); |
return; |
return -1; |
} |
} |
|
|
if (map->map_size < blocks) |
if (map->map_size < blocks) |
blocks = map->map_size; |
blocks = map->map_size; |
if (blocks == 1LL) { |
if (blocks == 1LL) { |
warnx("%s: error: no room for the GPT table", device_name); |
gpt_warnx(gpt, "No room for the GPT table"); |
return; |
return -1; |
|
} |
|
|
|
if ((p = calloc(1, gpt->secsz)) == NULL) { |
|
gpt_warnx(gpt, "Can't allocate the GPT"); |
|
return -1; |
|
} |
|
if ((gpt->gpt = map_add(gpt, 1LL, 1LL, |
|
MAP_TYPE_PRI_GPT_HDR, p)) == NULL) { |
|
free(p); |
|
gpt_warnx(gpt, "Can't add the GPT"); |
|
return -1; |
} |
} |
|
|
blocks--; /* Number of blocks in the GPT table. */ |
blocks--; /* Number of blocks in the GPT table. */ |
gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz)); |
if ((p = calloc(blocks, gpt->secsz)) == NULL) { |
tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL, |
gpt_warnx(gpt, "Can't allocate the GPT table"); |
calloc(blocks, secsz)); |
return -1; |
if (gpt == NULL || tbl == NULL) |
} |
return; |
if ((gpt->tbl = map_add(gpt, 2LL, blocks, |
|
MAP_TYPE_PRI_GPT_TBL, p)) == NULL) { |
|
free(p); |
|
gpt_warnx(gpt, "Can't add the GPT table"); |
|
return -1; |
|
} |
|
|
hdr = gpt->map_data; |
hdr = gpt->gpt->map_data; |
memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); |
memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); |
hdr->hdr_revision = htole32(GPT_HDR_REVISION); |
hdr->hdr_revision = htole32(GPT_HDR_REVISION); |
hdr->hdr_size = htole32(GPT_HDR_SIZE); |
hdr->hdr_size = htole32(GPT_HDR_SIZE); |
hdr->hdr_lba_self = htole64(gpt->map_start); |
hdr->hdr_lba_self = htole64(gpt->gpt->map_start); |
hdr->hdr_lba_alt = htole64(last); |
hdr->hdr_lba_alt = htole64(last); |
hdr->hdr_lba_start = htole64(tbl->map_start + blocks); |
hdr->hdr_lba_start = htole64(gpt->tbl->map_start + blocks); |
hdr->hdr_lba_end = htole64(last - blocks - 1LL); |
hdr->hdr_lba_end = htole64(last - blocks - 1LL); |
gpt_uuid_generate(hdr->hdr_guid); |
gpt_uuid_generate(hdr->hdr_guid); |
hdr->hdr_lba_table = htole64(tbl->map_start); |
hdr->hdr_lba_table = htole64(gpt->tbl->map_start); |
hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent)); |
hdr->hdr_entries = htole32((blocks * gpt->secsz) / |
|
sizeof(struct gpt_ent)); |
if (le32toh(hdr->hdr_entries) > parts) |
if (le32toh(hdr->hdr_entries) > parts) |
hdr->hdr_entries = htole32(parts); |
hdr->hdr_entries = htole32(parts); |
hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); |
hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); |
|
|
ent = tbl->map_data; |
ent = gpt->tbl->map_data; |
for (i = 0; i < le32toh(hdr->hdr_entries); i++) { |
for (i = 0; i < le32toh(hdr->hdr_entries); i++) { |
gpt_uuid_generate(ent[i].ent_guid); |
gpt_uuid_generate(ent[i].ent_guid); |
} |
} |
|
|
hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) * |
if (gpt_write_primary(gpt) == -1) |
le32toh(hdr->hdr_entsz))); |
return -1; |
hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); |
|
|
|
gpt_write(fd, gpt); |
|
gpt_write(fd, tbl); |
|
|
|
/* |
/* |
* Create backup GPT if the user didn't suppress it. |
* Create backup GPT if the user didn't suppress it. |
*/ |
*/ |
if (!primary_only) { |
if (!primary_only) { |
tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, |
// XXX: error checks |
calloc(1, secsz)); |
gpt->tpg = map_add(gpt, last, 1LL, MAP_TYPE_SEC_GPT_HDR, |
lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL, |
calloc(1, gpt->secsz)); |
tbl->map_data); |
gpt->lbt = map_add(gpt, last - blocks, blocks, |
memcpy(tpg->map_data, gpt->map_data, secsz); |
MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data); |
hdr = tpg->map_data; |
memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); |
hdr->hdr_lba_self = htole64(tpg->map_start); |
hdr = gpt->tpg->map_data; |
hdr->hdr_lba_alt = htole64(gpt->map_start); |
hdr->hdr_lba_self = htole64(gpt->tpg->map_start); |
hdr->hdr_lba_table = htole64(lbt->map_start); |
hdr->hdr_lba_alt = htole64(gpt->gpt->map_start); |
hdr->hdr_crc_self = 0; /* Don't ever forget this! */ |
hdr->hdr_lba_table = htole64(gpt->lbt->map_start); |
hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); |
if (gpt_write_backup(gpt) == -1) |
gpt_write(fd, lbt); |
return -1; |
gpt_write(fd, tpg); |
|
} |
} |
|
return 0; |
} |
} |
|
|
int |
int |
cmd_create(int argc, char *argv[]) |
cmd_create(gpt_t gpt, int argc, char *argv[]) |
{ |
{ |
int ch, fd; |
int ch; |
|
|
while ((ch = getopt(argc, argv, "fp")) != -1) { |
parts = 128; |
|
|
|
while ((ch = getopt(argc, argv, "fPp:")) != -1) { |
switch(ch) { |
switch(ch) { |
case 'f': |
case 'f': |
force = 1; |
force = 1; |
break; |
break; |
case 'p': |
case 'P': |
primary_only = 1; |
primary_only = 1; |
break; |
break; |
|
case 'p': |
|
parts = atoi(optarg); |
|
break; |
default: |
default: |
usage_create(); |
return usage_create(); |
} |
} |
} |
} |
|
|
if (argc == optind) |
if (argc != optind) |
usage_create(); |
return usage_create(); |
|
|
while (optind < argc) { |
|
fd = gpt_open(argv[optind++], force); |
|
if (fd == -1) |
|
continue; |
|
|
|
create(fd); |
|
|
|
gpt_close(fd); |
|
} |
|
|
|
return (0); |
return create(gpt); |
} |
} |