diff options
-rw-r--r-- | sbin/gpt/Makefile | 2 | ||||
-rw-r--r-- | sbin/gpt/add.c | 192 | ||||
-rw-r--r-- | sbin/gpt/create.c | 6 | ||||
-rw-r--r-- | sbin/gpt/gpt.c | 104 | ||||
-rw-r--r-- | sbin/gpt/gpt.h | 42 | ||||
-rw-r--r-- | sbin/gpt/map.c | 77 | ||||
-rw-r--r-- | sbin/gpt/map.h | 6 | ||||
-rw-r--r-- | sbin/gpt/migrate.c | 6 | ||||
-rw-r--r-- | sbin/gpt/show.c | 58 |
9 files changed, 389 insertions, 104 deletions
diff --git a/sbin/gpt/Makefile b/sbin/gpt/Makefile index e6d76cb21b40..0e521976f7c1 100644 --- a/sbin/gpt/Makefile +++ b/sbin/gpt/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= gpt -SRCS= create.c destroy.c gpt.c map.c migrate.c recover.c show.c +SRCS= add.c create.c destroy.c gpt.c map.c migrate.c recover.c show.c WARNS= 4 NOMAN= not yet diff --git a/sbin/gpt/add.c b/sbin/gpt/add.c new file mode 100644 index 000000000000..3423918f9f56 --- /dev/null +++ b/sbin/gpt/add.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2002 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/disklabel.h> +#include <sys/uuid.h> +#include <sys/gpt.h> + +#include <err.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "map.h" +#include "gpt.h" + +off_t block, size; +uuid_t type; + +static void +usage_add(void) +{ + + fprintf(stderr, + "usage: %s [-bst] device\n", getprogname()); + exit(1); +} + +static void +add(int fd) +{ + map_t *gpt, *tpg; + map_t *tbl, *lbt; + map_t *map; + struct gpt_hdr *hdr; + struct gpt_ent *ent; + unsigned int i; + + gpt = map_find(MAP_TYPE_PRI_GPT_HDR); + if (gpt == NULL) { + warnx("%s: error: device does not contain a GPT", device_name); + return; + } + + tpg = map_find(MAP_TYPE_SEC_GPT_HDR); + if (tpg == NULL) { + warnx("%s: error: no secundary table; run recover", + device_name); + return; + } + + tbl = map_find(MAP_TYPE_PRI_GPT_TBL); + lbt = map_find(MAP_TYPE_SEC_GPT_TBL); + if (tbl == NULL || lbt == NULL) { + warnx("%s: error: run recover -- trust me", device_name); + return; + } + + /* Create UFS partitions by default. */ + if (uuid_is_nil(&type, NULL)) { + uuid_t ufs = GPT_ENT_TYPE_FREEBSD_UFS; + type = ufs; + } + + map = map_alloc(block, size); + if (map == NULL) { + warnx("%s: error: no space available on device", device_name); + return; + } + + /* Find empty slot in GPT table. */ + hdr = gpt->map_data; + for (i = 0; i < hdr->hdr_entries; i++) { + ent = (void*)((char*)tbl->map_data + i * hdr->hdr_entsz); + if (uuid_is_nil(&ent->ent_type, NULL)) + break; + } + if (i == hdr->hdr_entries) { + warnx("%s: error: no available table entries", device_name); + return; + } + + ent->ent_type = type; + ent->ent_lba_start = map->map_start; + ent->ent_lba_end = map->map_start + map->map_size - 1LL; + + hdr->hdr_crc_table = crc32(tbl->map_data, + hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = 0; + hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); + + gpt_write(fd, gpt); + gpt_write(fd, tbl); + + hdr = tpg->map_data; + ent = (void*)((char*)lbt->map_data + i * hdr->hdr_entsz); + + ent->ent_type = type; + ent->ent_lba_start = map->map_start; + ent->ent_lba_end = map->map_start + map->map_size - 1LL; + + hdr->hdr_crc_table = crc32(lbt->map_data, + hdr->hdr_entries * hdr->hdr_entsz); + hdr->hdr_crc_self = 0; + hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); + + gpt_write(fd, lbt); + gpt_write(fd, tpg); +} + +int +cmd_add(int argc, char *argv[]) +{ + char *p; + int ch, fd; + uint32_t status; + + /* Get the migrate options */ + while ((ch = getopt(argc, argv, "b:s:t:")) != -1) { + switch(ch) { + case 'b': + if (block > 0) + usage_add(); + block = strtol(optarg, &p, 10); + if (*p != 0 || block < 1) + usage_add(); + break; + case 's': + if (size > 0) + usage_add(); + size = strtol(optarg, &p, 10); + if (*p != 0 || size < 1) + usage_add(); + break; + case 't': + if (!uuid_is_nil(&type, NULL)) + usage_add(); + uuid_from_string(optarg, &type, &status); + if (status != uuid_s_ok) { + /* TODO: accept aliases. */ + usage_add(); + } + break; + default: + usage_add(); + } + } + + if (argc == optind) + usage_add(); + + while (optind < argc) { + fd = gpt_open(argv[optind++]); + if (fd == -1) { + warn("unable to open device '%s'", device_name); + continue; + } + + add(fd); + + gpt_close(fd); + } + + return (0); +} diff --git a/sbin/gpt/create.c b/sbin/gpt/create.c index a82970ddab79..b2904f61e968 100644 --- a/sbin/gpt/create.c +++ b/sbin/gpt/create.c @@ -69,7 +69,7 @@ create(int fd) } /* Get the amount of free space after the MBR */ - blocks = map_unused(1LL, 0LL); + blocks = map_free(1LL, 0LL); if (blocks == 0LL) { warnx("%s: error: no room for the GPT header", device_name); return; @@ -125,7 +125,7 @@ create(int fd) hdr->hdr_lba_alt = last; hdr->hdr_lba_start = tbl->map_start + blocks; hdr->hdr_lba_end = last - blocks - 1LL; - uuidgen(&hdr->hdr_uuid, 1); + uuid_create(&hdr->hdr_uuid, NULL); hdr->hdr_lba_table = tbl->map_start; hdr->hdr_entries = (blocks * secsz) / sizeof(struct gpt_ent); if (hdr->hdr_entries > parts) @@ -134,7 +134,7 @@ create(int fd) ent = tbl->map_data; for (i = 0; i < hdr->hdr_entries; i++) - uuidgen(&ent[i].ent_uuid, 1); + uuid_create(&ent[i].ent_uuid, NULL); hdr->hdr_crc_table = crc32(ent, hdr->hdr_entries * hdr->hdr_entsz); hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); diff --git a/sbin/gpt/gpt.c b/sbin/gpt/gpt.c index e3f1365ebd06..18156e8fff07 100644 --- a/sbin/gpt/gpt.c +++ b/sbin/gpt/gpt.c @@ -127,18 +127,62 @@ unicode16(short *dst, const wchar_t *src, size_t len) *dst = 0; } -static char * -uuid_string(uuid_t *uuid) +#ifdef NEED_UUID_FUNCTIONS +void +uuid_create(uuid_t *u, uint32_t *st __unused) +{ + uuidgen(u, 1); +} + +void +uuid_from_string(const char *s, uuid_t *u, uint32_t *st) { - static char buf[48]; + int n; + + *st = uuid_s_invalid_string_uuid; + + if (strlen(s) != 36 || s[8] != '-') + return; + + n = sscanf(s, + "%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", + &u->time_low, &u->time_mid, &u->time_hi_and_version, + &u->clock_seq_hi_and_reserved, &u->clock_seq_low, &u->node[0], + &u->node[1], &u->node[2], &u->node[3], &u->node[4], &u->node[5]); + + if (n != 11) + return; + + n = u->clock_seq_hi_and_reserved; + if ((n & 0x80) != 0x00 && /* variant 0? */ + (n & 0xc0) != 0x80 && /* variant 1? */ + (n & 0xe0) != 0xc0) /* variant 2? */ + *st = uuid_s_bad_version; + else + *st = uuid_s_ok; +} + +int32_t +uuid_is_nil(uuid_t *u, uint32_t *st __unused) +{ + uint32_t *p; + + p = (uint32_t*)u; + return ((p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0) ? 1 : 0); +} + +void +uuid_to_string(uuid_t *u, char **s, uint32_t *st __unused) +{ + char buf[40]; sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid->time_low, uuid->time_mid, uuid->time_hi_and_version, - uuid->clock_seq_hi_and_reserved, uuid->clock_seq_low, - uuid->node[0], uuid->node[1], uuid->node[2], uuid->node[3], - uuid->node[4], uuid->node[5]); - return buf; + u->time_low, u->time_mid, u->time_hi_and_version, + u->clock_seq_hi_and_reserved, u->clock_seq_low, u->node[0], + u->node[1], u->node[2], u->node[3], u->node[4], u->node[5]); + *s = strdup(buf); } +#endif void* gpt_read(int fd, off_t lba, size_t count) @@ -180,7 +224,7 @@ gpt_gpt(int fd, off_t lba) off_t size; struct gpt_ent *ent; struct gpt_hdr *hdr; - char *p; + char *p, *s; map_t *m; size_t blocks, tblsz; unsigned int i; @@ -235,20 +279,19 @@ gpt_gpt(int fd, off_t lba) return (0); for (i = 0; i < hdr->hdr_entries; i++) { - uuid_t unused = GPT_ENT_TYPE_UNUSED; - ent = (void*)(p + i * hdr->hdr_entsz); - if (!memcmp(&ent->ent_type, &unused, sizeof(uuid_t))) + if (uuid_is_nil(&ent->ent_type, NULL)) continue; size = ent->ent_lba_end - ent->ent_lba_start + 1LL; - - if (verbose > 2) + if (verbose > 2) { + uuid_to_string(&ent->ent_type, &s, NULL); warnx( - "%s: GPT partition: type=%s, start=%llu, size=%llu", - device_name, uuid_string(&ent->ent_type), + "%s: GPT partition: type=%s, start=%llu, size=%llu", device_name, s, (long long)ent->ent_lba_start, (long long)size); - m = map_add(ent->ent_lba_start, size, MAP_TYPE_GPT_PART, NULL); + free(s); + } + m = map_add(ent->ent_lba_start, size, MAP_TYPE_GPT_PART, ent); if (m == NULL) return (-1); } @@ -338,19 +381,18 @@ gpt_open(const char *dev) start = (start << 16) + mbr->mbr_part[i].part_start_lo; size = mbr->mbr_part[i].part_size_hi; size = (size << 16) + mbr->mbr_part[i].part_size_lo; - if (start != 0 || size != 0) { - if (verbose > 2) - warnx( - "%s: MBR partition: type=%d, start=%llu, size=%llu", device_name, - mbr->mbr_part[i].part_typ, - (long long)start, (long long)size); - if (mbr->mbr_part[i].part_typ != 0xee) { - m = map_add(start, size, - MAP_TYPE_MBR_PART, NULL); - if (m == NULL) - goto close; - } - } + if (start == 0 && size == 0) + continue; + if (verbose > 2) + warnx("%s: MBR partition: type=%d, start=%llu, size=%llu", + device_name, mbr->mbr_part[i].part_typ, + (long long)start, (long long)size); + if (mbr->mbr_part[i].part_typ == 0xee) + continue; + m = map_add(start, size, MAP_TYPE_MBR_PART, + mbr->mbr_part + i); + if (m == NULL) + goto close; } } else { if (verbose) @@ -384,7 +426,7 @@ static struct { int (*fptr)(int, char *[]); const char *name; } cmdsw[] = { - { NULL, "add" }, + { cmd_add, "add" }, { cmd_create, "create" }, { NULL, "delete" }, { cmd_destroy, "destroy" }, diff --git a/sbin/gpt/gpt.h b/sbin/gpt/gpt.h index 268abe1b4755..a670b32f3790 100644 --- a/sbin/gpt/gpt.h +++ b/sbin/gpt/gpt.h @@ -29,26 +29,39 @@ #ifndef _GPT_H_ #define _GPT_H_ +struct mbr_part { + uint8_t part_flag; /* bootstrap flags */ + uint8_t part_shd; /* starting head */ + uint8_t part_ssect; /* starting sector */ + uint8_t part_scyl; /* starting cylinder */ + uint8_t part_typ; /* partition type */ + uint8_t part_ehd; /* end head */ + uint8_t part_esect; /* end sector */ + uint8_t part_ecyl; /* end cylinder */ + uint16_t part_start_lo; /* absolute starting ... */ + uint16_t part_start_hi; /* ... sector number */ + uint16_t part_size_lo; /* partition size ... */ + uint16_t part_size_hi; /* ... in sectors */ +}; + struct mbr { uint16_t mbr_code[223]; - struct { - uint8_t part_flag; /* bootstrap flags */ - uint8_t part_shd; /* starting head */ - uint8_t part_ssect; /* starting sector */ - uint8_t part_scyl; /* starting cylinder */ - uint8_t part_typ; /* partition type */ - uint8_t part_ehd; /* end head */ - uint8_t part_esect; /* end sector */ - uint8_t part_ecyl; /* end cylinder */ - uint16_t part_start_lo; /* absolute starting ... */ - uint16_t part_start_hi; /* ... sector number */ - uint16_t part_size_lo; /* partition size ... */ - uint16_t part_size_hi; /* ... in sectors */ - } mbr_part[4]; + struct mbr_part mbr_part[4]; uint16_t mbr_sig; #define MBR_SIG 0xAA55 }; +#ifndef uuid_s_ok +#define NEED_UUID_FUNCTIONS +#define uuid_s_ok 0 +#define uuid_s_bad_version 1 +#define uuid_s_invalid_string_uuid 2 +void uuid_create(uuid_t *, uint32_t *); +void uuid_from_string(const char *, uuid_t *, uint32_t *); +int32_t uuid_is_nil(uuid_t *, uint32_t *); +void uuid_to_string(uuid_t *, char **, uint32_t *); +#endif + extern char device_name[]; extern off_t mediasz; extern u_int parts; @@ -62,6 +75,7 @@ void* gpt_read(int, off_t, size_t); int gpt_write(int, map_t *); void unicode16(short *, const wchar_t *, size_t); +int cmd_add(int, char *[]); int cmd_create(int, char *[]); int cmd_destroy(int, char *[]); int cmd_migrate(int, char *[]); diff --git a/sbin/gpt/map.c b/sbin/gpt/map.c index 5aba63cd66c9..fbce87fd9732 100644 --- a/sbin/gpt/map.c +++ b/sbin/gpt/map.c @@ -33,7 +33,8 @@ #include "map.h" -static int lbawidth; +int lbawidth; + static map_t *mediamap; static map_t * @@ -133,6 +134,31 @@ map_add(off_t start, off_t size, int type, void *data) } map_t * +map_alloc(off_t start, off_t size) +{ + off_t delta; + map_t *m; + + for (m = mediamap; m != NULL; m = m->map_next) { + if (m->map_type != MAP_TYPE_UNUSED || m->map_start < 2) + continue; + if (start != 0 && m->map_start > start) + return (NULL); + delta = (start != 0) ? start - m->map_start : 0; + if (size == 0 || m->map_size - delta >= size) { + if (m->map_size - delta <= 0) + continue; + if (size == 0) + size = m->map_size - delta; + return (map_add(m->map_start + delta, size, + MAP_TYPE_GPT_PART, NULL)); + } + } + + return (NULL); +} + +map_t * map_find(int type) { map_t *m; @@ -161,7 +187,7 @@ map_last(void) } off_t -map_unused(off_t start, off_t size) +map_free(off_t start, off_t size) { map_t *m; @@ -177,53 +203,6 @@ map_unused(off_t start, off_t size) } void -map_dump(void) -{ - off_t end; - map_t *m; - - printf(" %*s", lbawidth, "start"); - printf(" %*s", lbawidth, "end"); - printf(" %*s", lbawidth, "size"); - printf(" %s\n", "contents"); - - m = mediamap; - while (m != NULL) { - end = m->map_start + m->map_size - 1; - printf(" %*llu", lbawidth, (long long)m->map_start); - printf(" %*llu", lbawidth, (long long)end); - printf(" %*llu", lbawidth, (long long)m->map_size); - - putchar(' '); putchar(' '); - switch (m->map_type) { - case MAP_TYPE_MBR: - printf("MBR"); - break; - case MAP_TYPE_PRI_GPT_HDR: - printf("Pri GPT header"); - break; - case MAP_TYPE_SEC_GPT_HDR: - printf("Sec GPT header"); - break; - case MAP_TYPE_PRI_GPT_TBL: - printf("Pri GPT table"); - break; - case MAP_TYPE_SEC_GPT_TBL: - printf("Sec GPT table"); - break; - case MAP_TYPE_MBR_PART: - printf("MBR partition"); - break; - case MAP_TYPE_GPT_PART: - printf("GPT partition"); - break; - } - putchar('\n'); - m = m->map_next; - } -} - -void map_init(off_t size) { char buf[32]; diff --git a/sbin/gpt/map.h b/sbin/gpt/map.h index ac726e1de973..4bdc94a72e04 100644 --- a/sbin/gpt/map.h +++ b/sbin/gpt/map.h @@ -46,14 +46,16 @@ typedef struct map { void *map_data; } map_t; +extern int lbawidth; + map_t *map_add(off_t, off_t, int, void*); +map_t *map_alloc(off_t, off_t); map_t *map_find(int); map_t *map_first(void); map_t *map_last(void); -off_t map_unused(off_t, off_t); +off_t map_free(off_t, off_t); -void map_dump(void); void map_init(off_t); #endif /* _MAP_H_ */ diff --git a/sbin/gpt/migrate.c b/sbin/gpt/migrate.c index c27bff66e967..97e1f6a281fc 100644 --- a/sbin/gpt/migrate.c +++ b/sbin/gpt/migrate.c @@ -135,7 +135,7 @@ migrate(int fd) } /* Get the amount of free space after the MBR */ - blocks = map_unused(1LL, 0LL); + blocks = map_free(1LL, 0LL); if (blocks == 0LL) { warnx("%s: error: no room for the GPT header", device_name); return; @@ -193,7 +193,7 @@ migrate(int fd) hdr->hdr_lba_alt = tpg->map_start; hdr->hdr_lba_start = tbl->map_start + blocks; hdr->hdr_lba_end = lbt->map_start - 1LL; - uuidgen(&hdr->hdr_uuid, 1); + uuid_create(&hdr->hdr_uuid, NULL); hdr->hdr_lba_table = tbl->map_start; hdr->hdr_entries = (blocks * secsz) / sizeof(struct gpt_ent); if (hdr->hdr_entries > parts) @@ -202,7 +202,7 @@ migrate(int fd) ent = tbl->map_data; for (i = 0; i < hdr->hdr_entries; i++) - uuidgen(&ent[i].ent_uuid, 1); + uuid_create(&ent[i].ent_uuid, NULL); /* Mirror partitions. */ for (i = 0; i < 4; i++) { diff --git a/sbin/gpt/show.c b/sbin/gpt/show.c index 0eff2d3b6bda..8b651b7e0d40 100644 --- a/sbin/gpt/show.c +++ b/sbin/gpt/show.c @@ -49,6 +49,62 @@ usage_show(void) exit(1); } +static void +show(int fd __unused) +{ + off_t end; + map_t *m; + struct mbr_part *part; + struct gpt_ent *ent; + char *s; + + printf(" %*s", lbawidth, "start"); + printf(" %*s", lbawidth, "end"); + printf(" %*s", lbawidth, "size"); + printf(" %s\n", "contents"); + + m = map_first(); + while (m != NULL) { + end = m->map_start + m->map_size - 1; + printf(" %*llu", lbawidth, (long long)m->map_start); + printf(" %*llu", lbawidth, (long long)end); + printf(" %*llu", lbawidth, (long long)m->map_size); + + putchar(' '); putchar(' '); + switch (m->map_type) { + case MAP_TYPE_MBR: + printf("MBR"); + break; + case MAP_TYPE_PRI_GPT_HDR: + printf("Pri GPT header"); + break; + case MAP_TYPE_SEC_GPT_HDR: + printf("Sec GPT header"); + break; + case MAP_TYPE_PRI_GPT_TBL: + printf("Pri GPT table"); + break; + case MAP_TYPE_SEC_GPT_TBL: + printf("Sec GPT table"); + break; + case MAP_TYPE_MBR_PART: + printf("MBR partition: "); + part = m->map_data; + printf("type=%d", part->part_typ); + break; + case MAP_TYPE_GPT_PART: + printf("GPT partition: "); + ent = m->map_data; + uuid_to_string(&ent->ent_type, &s, NULL); + printf("type=%s", s); + free(s); + break; + } + putchar('\n'); + m = m->map_next; + } +} + int cmd_show(int argc, char *argv[]) { @@ -71,7 +127,7 @@ cmd_show(int argc, char *argv[]) continue; } - map_dump(); + show(fd); gpt_close(fd); } |