From owner-p4-projects Fri May 31 17:49:39 2002 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 41E3A37B400; Fri, 31 May 2002 17:48:46 -0700 (PDT) Delivered-To: perforce@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id E24EB37B405 for ; Fri, 31 May 2002 17:48:44 -0700 (PDT) Received: (from perforce@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g510miP32394 for perforce@freebsd.org; Fri, 31 May 2002 17:48:44 -0700 (PDT) (envelope-from marcel@freebsd.org) Date: Fri, 31 May 2002 17:48:44 -0700 (PDT) Message-Id: <200206010048.g510miP32394@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: perforce set sender to marcel@freebsd.org using -f From: Marcel Moolenaar Subject: PERFORCE change 12233 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://people.freebsd.org/~peter/p4db/chv.cgi?CH=12233 Change 12233 by marcel@marcel_vaio on 2002/05/31 17:48:20 Flesh it out some more. This includes: o Picked a generic usage model, similar to cvs: gpt [generic-options] [command-options] o Give each command its own source file. This probably is a bit excessive, but helps keep things clean while the tool expands. Implement the following commands: destroy clear the primary and secundary GPT sectors with the option to leave the secundairy. migrate what it did before, but less hacky. recover dummy. Next on the list. Restore primary GPT from secundairy. show Print the image map of the device. o Cleanups, renaming and other "productizing" actions. Affected files ... ... //depot/projects/ia64/sbin/gpt/Makefile#2 edit ... //depot/projects/ia64/sbin/gpt/destroy.c#1 add ... //depot/projects/ia64/sbin/gpt/gpt.c#7 edit ... //depot/projects/ia64/sbin/gpt/gpt.h#4 add ... //depot/projects/ia64/sbin/gpt/map.c#3 edit ... //depot/projects/ia64/sbin/gpt/map.h#2 edit ... //depot/projects/ia64/sbin/gpt/migrate.c#1 add ... //depot/projects/ia64/sbin/gpt/recover.c#1 add ... //depot/projects/ia64/sbin/gpt/show.c#1 add Differences ... ==== //depot/projects/ia64/sbin/gpt/Makefile#2 (text+ko) ==== @@ -1,7 +1,7 @@ # $FreeBSD$ PROG= gpt -SRCS= gpt.c map.c +SRCS= destroy.c gpt.c map.c migrate.c recover.c show.c WARNS= 4 NOMAN= not yet ==== //depot/projects/ia64/sbin/gpt/gpt.c#7 (text+ko) ==== @@ -26,29 +26,6 @@ * CRC32 code derived from work by Gary S. Brown. */ -/* - * Possible options: - * -r readonly mode (maybe default and have -w?) - * -v be verbose - * -p n make room for n partitions (default 128 - minimum) - * -f x read commands from file x. - * - * Possible usages: - * gpt da2 write device layout (media map) - * gpt /dev/ad0 migrate migrate MBR to GPT - * gpt md1 create create GPT (no partitions) - * gpt md1 add ... create partitions - * gpt ad5 relocate ... move partitions (useful?) - * gpt fd0 resize ... resize partitions (useful?) - * gpt ~/foo validate extensive validation - * - * Other random ideas: - * Have a disktab like "database" to hold UUIDs, capabilities and - * other things that we don't like to hardcode. This allows us to - * create an entry "FreeBSD" and use that instead of the UUID - * when creating a FreeBSD partition. - */ - #include __FBSDID("$FreeBSD$"); @@ -62,33 +39,15 @@ #include #include #include +#include #include #include #include #include #include "map.h" +#include "gpt.h" -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]; - uint16_t mbr_sig; -#define MBR_SIG 0xAA55 -}; - char device_name[MAXPATHLEN]; off_t mediasz; @@ -144,7 +103,7 @@ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; -static uint32_t +uint32_t crc32(const void *buf, size_t size) { const uint8_t *p; @@ -159,7 +118,7 @@ return crc ^ ~0U; } -static void +void unicode16(short *dst, const wchar_t *src, size_t len) { while (len-- && *src != 0) @@ -168,80 +127,19 @@ *dst = 0; } -static void -usage(void) +static char * +uuid_string(uuid_t *uuid) { + static char buf[48]; - fprintf(stderr, "usage: gpt [-rv] [-p nparts] device\n"); - exit(1); -} - -static int -gpt_open(const char *dev) -{ - struct stat sb; - int fd; - - if (!stat(dev, &sb)) { - strlcpy(device_name, dev, sizeof(device_name)); - goto found; - } - - snprintf(device_name, sizeof(device_name), "/dev/%s", dev); - if (!stat(device_name, &sb)) - goto found; - - strlcpy(device_name, dev, sizeof(device_name)); - return (-1); - - found: - fd = open(device_name, (readonly) ? O_RDONLY : O_RDWR|O_EXCL); - if (fd == -1) - return (-1); - - if ((sb.st_mode & S_IFMT) != S_IFREG) { - if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 || - ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) - goto close; - } else { - secsz = 512; /* Fixed size for files. */ - if (sb.st_size % secsz) { - errno = EINVAL; - goto close; - } - mediasz = sb.st_size; - } - /* - * We require an absolute minimum of 6 sectors. One for the MBR, - * 2 for the GPT header, 2 for the GPT table and one to hold some - * user data. Let's catch this extreme border case here so that - * we don't have to worry about it later. - */ - if (mediasz / secsz < 6) { - errno = ENODEV; - goto close; - } - if (verbose) - warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu", - device_name, (long long)mediasz, secsz, - (long long)(mediasz / secsz)); - - map_init(mediasz / secsz); - - return (fd); - - close: - close(fd); - return (-1); + 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; } -static void -gpt_close(int fd) -{ - /* XXX post processing? */ - close(fd); -} - static void* gpt_read(int fd, off_t lba, size_t count) { @@ -262,7 +160,7 @@ return (NULL); } -static int +int gpt_write(int fd, map_t *map) { off_t ofs; @@ -279,6 +177,7 @@ static int gpt_gpt(int fd, off_t lba) { + off_t size; struct gpt_ent *ent; struct gpt_hdr *hdr; char *p; @@ -318,15 +217,17 @@ goto fail_ent; } - if (verbose) - warnx("%s: found GPT at sector %llu", device_name, - (long long)lba); + if (verbose > 1) + warnx("%s: %s GPT at sector %llu", device_name, + (lba == 1) ? "Pri" : "Sec", (long long)lba); - m = map_add(lba, 1, (lba == 1) ? MAP_TYPE_GPT : MAP_TYPE_TPG, hdr); + m = map_add(lba, 1, (lba == 1) + ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr); if (m == NULL) return (-1); + m = map_add(hdr->hdr_lba_table, blocks, (lba == 1) - ? MAP_TYPE_GPT_TBL : MAP_TYPE_TPG_TBL, p); + ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p); if (m == NULL) return (-1); @@ -339,9 +240,15 @@ ent = (void*)(p + i * hdr->hdr_entsz); if (!memcmp(&ent->ent_type, &unused, sizeof(uuid_t))) continue; - m = map_add(ent->ent_lba_start, - ent->ent_lba_end - ent->ent_lba_start + 1LL, - MAP_TYPE_GPT_PART, NULL); + + size = ent->ent_lba_end - ent->ent_lba_start + 1LL; + + if (verbose > 2) + warnx( + "%s: GPT partition: type=%s, start=%llu, size=%llu", + device_name, uuid_string(&ent->ent_type), + (long long)ent->ent_lba_start, (long long)size); + m = map_add(ent->ent_lba_start, size, MAP_TYPE_GPT_PART, NULL); if (m == NULL) return (-1); } @@ -355,42 +262,97 @@ return (0); } -static int -gpt_map(int fd) +int +gpt_open(const char *dev) { + struct stat sb; struct mbr *mbr; map_t *m; uint32_t size, start; unsigned int i; + int fd; + + if (!stat(dev, &sb)) { + strlcpy(device_name, dev, sizeof(device_name)); + goto found; + } + + snprintf(device_name, sizeof(device_name), "/dev/%s", dev); + if (!stat(device_name, &sb)) + goto found; + + strlcpy(device_name, dev, sizeof(device_name)); + return (-1); + + found: + fd = open(device_name, (readonly) ? O_RDONLY : O_RDWR|O_EXCL); + if (fd == -1) + return (-1); + if ((sb.st_mode & S_IFMT) != S_IFREG) { + if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 || + ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) + goto close; + } else { + secsz = 512; /* Fixed size for files. */ + if (sb.st_size % secsz) { + errno = EINVAL; + goto close; + } + mediasz = sb.st_size; + } + /* + * We require an absolute minimum of 6 sectors. One for the MBR, + * 2 for the GPT header, 2 for the GPT table and one to hold some + * user data. Let's catch this extreme border case here so that + * we don't have to worry about it later. + */ + if (mediasz / secsz < 6) { + errno = ENODEV; + goto close; + } + + if (verbose) + warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu", + device_name, (long long)mediasz, secsz, + (long long)(mediasz / secsz)); + + map_init(mediasz / secsz); + + /* * MBR */ mbr = gpt_read(fd, 0LL, 1); if (mbr == NULL) - return (-1); + goto close; if (mbr->mbr_sig == MBR_SIG) { - if (verbose) - warnx("%s: found MBR at sector 0", device_name); + if (verbose > 1) + warnx("%s: MBR at sector 0", device_name); m = map_add(0LL, 1LL, MAP_TYPE_MBR, mbr); if (m == NULL) - return (-1); + goto close; for (i = 0; i < 4; i++) { start = mbr->mbr_part[i].part_start_hi; 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); m = map_add(start, size, MAP_TYPE_MBR_PART, NULL); if (m == NULL) - return (-1); + goto close; } } } else { if (verbose) - warnx("%s: no MBR on this device", device_name); + warnx("%s: MBR not found", device_name); free(mbr); } @@ -398,173 +360,74 @@ * GPT */ if (gpt_gpt(fd, 1LL) == -1) - return (-1); + goto close; if (gpt_gpt(fd, mediasz / secsz - 1LL) == -1) - return (-1); - return (0); + goto close; + + return (fd); + + close: + close(fd); + return (-1); } -static void -gpt_migrate(int fd) +void +gpt_close(int fd) { - off_t blocks, last; - map_t *gpt, *tpg; - map_t *tbl, *lbt; - map_t *map; - struct gpt_hdr *hdr; - struct gpt_ent *ent; - struct mbr *mbr; - uint32_t start, size; - unsigned int i; + /* XXX post processing? */ + close(fd); +} - last = mediasz / secsz - 1LL; +static struct { + int (*fptr)(int, char *[]); + const char *name; +} cmdsw[] = { + { NULL, "add" }, + { NULL, "create" }, + { NULL, "delete" }, + { cmd_destroy, "destroy" }, + { NULL, "help" }, + { cmd_migrate, "migrate" }, + { cmd_recover, "recover" }, + { NULL, "rename" }, + { cmd_show, "show" }, + { NULL, "verify" }, + { NULL, NULL } +}; - map = map_find(MAP_TYPE_MBR); - if (map == NULL || map_find(MAP_TYPE_MBR_PART) == NULL) { - warnx("%s: error: no partitions to convert", - device_name); - return; - } +static void +usage(void) +{ - mbr = map->map_data; + fprintf(stderr, + "usage: %s [-rv] [-p nparts] command [options] device\n", + getprogname()); + exit(1); +} - if (verbose) { - printf("\tBefore image:\n"); - map_dump(); - putchar('\n'); - } +static void +prefix(const char *cmd) +{ + char *pfx; + const char *prg; - if (map_find(MAP_TYPE_GPT) != NULL || map_find(MAP_TYPE_TPG) != NULL) { - warnx("%s: error: device already contains a GPT", device_name); + prg = getprogname(); + pfx = malloc(strlen(prg) + strlen(cmd) + 2); + /* Don't bother failing. It's not important */ + if (pfx == NULL) return; - } - /* Get the amount of free space after the MBR */ - blocks = map_unused(1LL, 0LL); - if (blocks == 0LL) { - warnx("%s: error: no room for the GPT header", device_name); - return; - } - - /* Don't create more than parts entries. */ - if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) { - blocks = (parts * sizeof(struct gpt_ent)) / secsz; - if ((parts * sizeof(struct gpt_ent)) % secsz) - blocks++; - blocks++; /* Don't forget the header itself */ - } - - /* Never cross the median of the device. */ - if ((blocks + 1LL) > ((last + 1LL) >> 1)) - blocks = ((last + 1LL) >> 1) - 1LL; - - /* - * Get the amount of free space at the end of the device and - * calculate the size for the GPT structures. - */ - map = map_last(); - if (map->map_type != MAP_TYPE_UNUSED) { - warnx("%s: error: no room for the backup header", device_name); - return; - } - - if (map->map_size < blocks) - blocks = map->map_size; - if (blocks == 1LL) { - warnx("%s: error: no room for the GPT table", device_name); - return; - } - - blocks--; /* Number of blocks in the GPT table. */ - gpt = map_add(1LL, 1LL, MAP_TYPE_GPT, calloc(1, secsz)); - tbl = map_add(2LL, blocks, MAP_TYPE_GPT_TBL, calloc(blocks, secsz)); - if (gpt == NULL || tbl == NULL) - return; - - lbt = map_add(last - blocks, blocks, MAP_TYPE_TPG_TBL, tbl->map_data); - tpg = map_add(last, 1LL, MAP_TYPE_TPG, calloc(1, secsz)); - - hdr = gpt->map_data; - memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); - hdr->hdr_revision = GPT_HDR_REVISION; - hdr->hdr_size = sizeof(struct gpt_hdr); - hdr->hdr_lba_self = gpt->map_start; - 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); - hdr->hdr_lba_table = tbl->map_start; - hdr->hdr_entries = (blocks * secsz) / sizeof(struct gpt_ent); - if (hdr->hdr_entries > parts) - hdr->hdr_entries = parts; - hdr->hdr_entsz = sizeof(struct gpt_ent); - - ent = tbl->map_data; - for (i = 0; i < hdr->hdr_entries; i++) - uuidgen(&ent[i].ent_uuid, 1); - - /* Mirror partitions. */ - for (i = 0; i < 4; i++) { - switch (mbr->mbr_part[i].part_typ) { - case 165: { /* FreeBSD */ - uuid_t freebsd = GPT_ENT_TYPE_FREEBSD; - ent->ent_type = freebsd; - unicode16(ent->ent_name, - L"FreeBSD disklabel partition", 36); - break; - } - case 239: { /* EFI */ - uuid_t efi_slice = GPT_ENT_TYPE_EFI; - ent->ent_type = efi_slice; - unicode16(ent->ent_name, L"EFI system partition", 36); - break; - } - default: - continue; - } - start = mbr->mbr_part[i].part_start_hi; - 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; - ent->ent_lba_start = start; - ent->ent_lba_end = start + size - 1LL; - ent++; - } - ent = tbl->map_data; - - hdr->hdr_crc_table = crc32(ent, hdr->hdr_entries * hdr->hdr_entsz); - hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); - - gpt_write(fd, gpt); - gpt_write(fd, tbl); - - /* - * Create backup GPT. - */ - memcpy(tpg->map_data, gpt->map_data, secsz); - hdr = tpg->map_data; - hdr->hdr_lba_self = tpg->map_start; - hdr->hdr_lba_alt = gpt->map_start; - hdr->hdr_lba_table = lbt->map_start; - hdr->hdr_crc_self = 0; /* Don't ever forget this! */ - hdr->hdr_crc_self = crc32(hdr, hdr->hdr_size); - - gpt_write(fd, lbt); - gpt_write(fd, tpg); - - if (verbose) { - printf("\tAfter image:\n"); - map_dump(); - putchar('\n'); - } + sprintf(pfx, "%s %s", prg, cmd); + setprogname(pfx); } int -main(int argc, char **argv) +main(int argc, char *argv[]) { - char *p; - int ch, fd; + char *cmd, *p; + int ch, i; + /* Get the generic options */ while ((ch = getopt(argc, argv, "p:rv")) != -1) { switch(ch) { case 'p': @@ -578,7 +441,7 @@ readonly = 1; break; case 'v': - verbose = 1; + verbose++; break; default: usage(); @@ -586,26 +449,16 @@ } if (!parts) parts = 128; - argc -= optind; - argv += optind; - if (argc != 1) + if (argc == optind) usage(); - fd = gpt_open(argv[0]); - if (fd == -1) - err(1, "unable to open device '%s'", device_name); + cmd = argv[optind++]; + for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++); - if (gpt_map(fd) == -1) - err(1, "unable to map device"); + if (cmdsw[i].fptr == NULL) + errx(1, "unknown command: %s", cmd); - /* - * XXX Must be one of many useful things we can do. Not just - * the only thing :-) - */ - gpt_migrate(fd); - - gpt_close(fd); - - return (0); + prefix(cmd); + return ((*cmdsw[i].fptr)(argc, argv)); } ==== //depot/projects/ia64/sbin/gpt/map.c#3 (text+ko) ==== @@ -33,6 +33,7 @@ #include "map.h" +static int lbawidth; static map_t *mediamap; static map_t * @@ -69,7 +70,7 @@ if (n->map_start == start && n->map_size == size) { if (n->map_type != MAP_TYPE_UNUSED) - warnx("warning: part(%llu,%llu) mirrored", + warnx("warning: partition(%llu,%llu) mirrored", (long long)start, (long long)size); n->map_type = type; n->map_data = data; @@ -77,9 +78,10 @@ } if (n->map_type != MAP_TYPE_UNUSED) { - warnx("error: part(%llu,%llu) overlaps part(%llu,%llu)", - (long long)start, (long long)size, (long long)n->map_start, - (long long)n->map_size); + warnx( + "error: partition(%llu,%llu) overlaps partition(%llu,%llu)", + (long long)start, (long long)size, + (long long)n->map_start, (long long)n->map_size); return (0); } @@ -172,38 +174,46 @@ 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_UNUSED: - printf(" (unused)\t"); - break; case MAP_TYPE_MBR: - printf("MBR\t\t"); + printf("MBR"); break; - case MAP_TYPE_GPT: - printf("GPT header\t"); + case MAP_TYPE_PRI_GPT_HDR: + printf("Pri GPT header"); break; - case MAP_TYPE_TPG: - printf("Backup header\t"); + case MAP_TYPE_SEC_GPT_HDR: + printf("Sec GPT header"); break; - case MAP_TYPE_GPT_TBL: - printf("GPT table\t"); + case MAP_TYPE_PRI_GPT_TBL: + printf("Pri GPT table"); break; - case MAP_TYPE_TPG_TBL: - printf("Backup table\t"); + case MAP_TYPE_SEC_GPT_TBL: + printf("Sec GPT table"); break; case MAP_TYPE_MBR_PART: - printf("MBR part\t"); + printf("MBR partition"); break; case MAP_TYPE_GPT_PART: - printf("GPT part\t"); + printf("GPT partition"); break; } - printf("start=%llu, blocks=%llu\n", (long long)m->map_start, - (long long)m->map_size); + putchar('\n'); m = m->map_next; } } @@ -211,5 +221,10 @@ void map_init(off_t size) { + char buf[32]; + mediamap = mkmap(0LL, size, MAP_TYPE_UNUSED); + lbawidth = sprintf(buf, "%llu", (long long)size); + if (lbawidth < 5) + lbawidth = 5; } ==== //depot/projects/ia64/sbin/gpt/map.h#2 (text+ko) ==== @@ -38,10 +38,10 @@ #define MAP_TYPE_UNUSED 0 #define MAP_TYPE_MBR 1 #define MAP_TYPE_MBR_PART 2 -#define MAP_TYPE_GPT 3 -#define MAP_TYPE_TPG 4 /* GPT mirror header. */ -#define MAP_TYPE_GPT_TBL 5 -#define MAP_TYPE_TPG_TBL 6 /* GPT mirror table. */ +#define MAP_TYPE_PRI_GPT_HDR 3 +#define MAP_TYPE_SEC_GPT_HDR 4 +#define MAP_TYPE_PRI_GPT_TBL 5 +#define MAP_TYPE_SEC_GPT_TBL 6 #define MAP_TYPE_GPT_PART 7 void *map_data; } map_t; To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message