From: krw Date: Sat, 30 Jan 2021 18:16:36 +0000 (+0000) Subject: Make editing GPT easier/safer by defaulting offet to beginning of largest X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=c2d03168cbdadc2c30b2ebdbf597ea31227b0805;p=openbsd Make editing GPT easier/safer by defaulting offet to beginning of largest free space and preventing the creation of overlapping partitions. Prompted & tested by landry@ --- diff --git a/sbin/fdisk/cmd.c b/sbin/fdisk/cmd.c index c467056e0b8..b283116a965 100644 --- a/sbin/fdisk/cmd.c +++ b/sbin/fdisk/cmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd.c,v 1.98 2017/11/13 21:00:32 krw Exp $ */ +/* $OpenBSD: cmd.c,v 1.99 2021/01/30 18:16:36 krw Exp $ */ /* * Copyright (c) 1997 Tobias Weingartner @@ -167,7 +167,6 @@ Xgedit(char *args) struct gpt_partition *gg; char *name; u_int16_t *utf; - u_int64_t bs, ns; int i, pn; pn = strtonum(args, 0, NGPTPARTITIONS - 1, &errstr); @@ -187,13 +186,11 @@ Xgedit(char *args) goto done; } - bs = getuint64("Partition offset", letoh64(gg->gp_lba_start), - letoh64(gh.gh_lba_start), letoh64(gh.gh_lba_end)); - ns = getuint64("Partition size", letoh64(gg->gp_lba_end) - bs + 1, - 1, letoh64(gh.gh_lba_end) - bs + 1); - - gg->gp_lba_start = htole64(bs); - gg->gp_lba_end = htole64(bs + ns - 1); + if (GPT_get_lba_start(pn) == -1 || + GPT_get_lba_end(pn) == -1) { + *gg = oldpart; + goto done; + } name = ask_string("Partition name", utf16le_to_string(gg->gp_name)); if (strlen(name) >= GPTPARTNAMESIZE) { diff --git a/sbin/fdisk/gpt.c b/sbin/fdisk/gpt.c index 3048e91c3ea..105035d3bbc 100644 --- a/sbin/fdisk/gpt.c +++ b/sbin/fdisk/gpt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gpt.c,v 1.11 2016/03/28 16:55:09 mestre Exp $ */ +/* $OpenBSD: gpt.c,v 1.12 2021/01/30 18:16:36 krw Exp $ */ /* * Copyright (c) 2015 Markus Muller * Copyright (c) 2015 Kenneth R Westerback @@ -42,6 +42,9 @@ struct gpt_header gh; struct gpt_partition gp[NGPTPARTITIONS]; +struct gpt_partition **sort_gpt(void); +int lba_start_cmp(const void *e1, const void *e2); + int GPT_get_header(off_t where) { @@ -456,3 +459,131 @@ GPT_write(void) return (0); } + +int +gp_lba_start_cmp(const void *e1, const void *e2) +{ + struct gpt_partition *p1 = *(struct gpt_partition **)e1; + struct gpt_partition *p2 = *(struct gpt_partition **)e2; + u_int64_t o1; + u_int64_t o2; + + o1 = letoh64(p1->gp_lba_start); + o2 = letoh64(p2->gp_lba_start); + + if (o1 < o2) + return -1; + else if (o1 > o2) + return 1; + else + return 0; +} + +struct gpt_partition ** +sort_gpt(void) +{ + static struct gpt_partition *sgp[NGPTPARTITIONS+2]; + unsigned int i, j; + + memset(sgp, 0, sizeof(sgp)); + + j = 0; + for (i = 0; i < letoh32(gh.gh_part_num); i++) { + if (letoh64(gp[i].gp_lba_start) >= letoh64(gh.gh_lba_start)) + sgp[j++] = &gp[i]; + } + + if (j > 1) { + if (mergesort(sgp, j, sizeof(sgp[0]), gp_lba_start_cmp) == -1) { + printf("unable to sort gpt by lba start\n"); + return NULL; + } + } + + return (sgp); +} + +int +GPT_get_lba_start(unsigned int pn) +{ + struct gpt_partition **sgp; + uint64_t bs, bigbs, nextbs, ns; + unsigned int i; + + bs = letoh64(gh.gh_lba_start); + + if (letoh64(gp[pn].gp_lba_start) >= bs) { + bs = letoh64(gp[pn].gp_lba_start); + } else { + sgp = sort_gpt(); + if (sgp == NULL) + return -1; + if (sgp[0] != NULL) { + bigbs = bs; + ns = 0; + for (i = 0; sgp[i] != NULL; i++) { + nextbs = letoh64(sgp[i]->gp_lba_start); + if (bs < nextbs && ns < nextbs - bs) { + ns = nextbs - bs; + bigbs = bs; + } + bs = letoh64(sgp[i]->gp_lba_end) + 1; + } + nextbs = letoh64(gh.gh_lba_end) + 1; + if (bs < nextbs && ns < nextbs - bs) { + ns = nextbs - bs; + bigbs = bs; + } + if (ns == 0) { + printf("no space for partition %u\n", pn); + return -1; + } + bs = bigbs; + } + } + + bs = getuint64("Partition offset", bs, letoh64(gh.gh_lba_start), + letoh64(gh.gh_lba_end)); + + for (i = 0; i < letoh32(gh.gh_part_num); i++) { + if (i == pn) + continue; + if (bs >= letoh64(gp[i].gp_lba_start) && + bs <= letoh64(gp[i].gp_lba_end)) { + printf("partition %u can't start inside partition %u\n", + pn, i); + return -1; + } + } + + gp[pn].gp_lba_start = htole64(bs); + + return 0; +} + +int +GPT_get_lba_end(unsigned int pn) +{ + struct gpt_partition **sgp; + uint64_t bs, nextbs, ns; + unsigned int i; + + sgp = sort_gpt(); + if (sgp == NULL) + return -1; + + bs = letoh64(gp[pn].gp_lba_start); + ns = letoh64(gh.gh_lba_end) - bs + 1; + for (i = 0; sgp[i] != NULL; i++) { + nextbs = letoh64(sgp[i]->gp_lba_start); + if (nextbs > bs) { + ns = nextbs - bs; + break; + } + } + ns = getuint64("Partition size", ns, 1, ns); + + gp[pn].gp_lba_end = htole64(bs + ns - 1); + + return 0; +} diff --git a/sbin/fdisk/gpt.h b/sbin/fdisk/gpt.h index ace4b2583c0..d6060242d5d 100644 --- a/sbin/fdisk/gpt.h +++ b/sbin/fdisk/gpt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: gpt.h,v 1.6 2016/01/09 18:10:57 krw Exp $ */ +/* $OpenBSD: gpt.h,v 1.7 2021/01/30 18:16:36 krw Exp $ */ /* * Copyright (c) 2015 Markus Muller * Copyright (c) 2015 Kenneth R Westerback @@ -16,15 +16,17 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -int GPT_get_hdr(off_t); -int GPT_get_partition_table(off_t); -void GPT_get_gpt(int); -int GPT_init(void); -int GPT_write(void); +void GPT_get_gpt(int); +int GPT_get_hdr(off_t); +int GPT_get_partition_table(off_t); +int GPT_get_lba_start(unsigned int); +int GPT_get_lba_end(unsigned int); -void GPT_print(char *, int); -void GPT_print_part(int, char *, int); -void GPT_print_parthdr(int); +int GPT_init(void); +int GPT_write(void); +void GPT_print(char *, int); +void GPT_print_part(int, char *, int); +void GPT_print_parthdr(int); extern struct gpt_header gh; extern struct gpt_partition gp[NGPTPARTITIONS];