From: Karel Zak Date: Fri, 29 Nov 2013 20:55:53 +0000 (+0100) Subject: libfdisk: use partition template X-Git-Tag: v2.25-rc1~520 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=77d6a70ac40aaaf693eb9c71d01ebac41218e9b3;p=thirdparty%2Futil-linux.git libfdisk: use partition template Signed-off-by: Karel Zak --- diff --git a/libfdisk/src/bsd.c b/libfdisk/src/bsd.c index fc7786892c..4ee31b6dd5 100644 --- a/libfdisk/src/bsd.c +++ b/libfdisk/src/bsd.c @@ -85,9 +85,7 @@ static int bsd_list_disklabel(struct fdisk_context *cxt); static int bsd_initlabel(struct fdisk_context *cxt); static int bsd_readlabel(struct fdisk_context *cxt); static void sync_disks(struct fdisk_context *cxt); - -#define bsd_cround(c, n) \ - (fdisk_context_use_cylinders(c) ? ((n)/self_disklabel(c)->d_secpercyl) + 1 : (n)) +static int bsd_set_parttype(struct fdisk_context *cxt, size_t partnum, struct fdisk_parttype *t); static inline struct fdisk_bsd_label *self_label(struct fdisk_context *cxt) { @@ -195,80 +193,97 @@ static int bsd_probe_label(struct fdisk_context *cxt) return 0; /* not found */ } -static int bsd_add_part (struct fdisk_context *cxt, - size_t i, - struct fdisk_parttype *t __attribute__((__unused__))) +static int bsd_add_partition(struct fdisk_context *cxt, + struct fdisk_partition *pa) { struct fdisk_bsd_label *l = self_label(cxt); struct bsd_disklabel *d = self_disklabel(cxt); - struct fdisk_ask *ask; + size_t i; unsigned int begin = 0, end; - int rc; + int rc = 0; + rc = fdisk_partition_next_partno(cxt, pa, &i); + if (rc) + return rc; if (i >= BSD_MAXPARTITIONS) - return -EINVAL; - + return -ERANGE; if (l->dos_part) { begin = dos_partition_get_start(l->dos_part); end = begin + dos_partition_get_size(l->dos_part) - 1; } else end = d->d_secperunit - 1; - ask = fdisk_new_ask(); - /* * First sector */ - if (fdisk_context_use_cylinders(cxt)) - fdisk_ask_set_query(ask, _("First cylinder")); - else - fdisk_ask_set_query(ask, _("First sector")); - - fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); - fdisk_ask_number_set_low(ask, bsd_cround(cxt, begin)); - fdisk_ask_number_set_default(ask, bsd_cround(cxt, begin)); - fdisk_ask_number_set_high(ask, bsd_cround(cxt, end)); - - rc = fdisk_do_ask(cxt, ask); - if (rc) { + if (pa && pa->start_follow_default) + ; + else if (pa && pa->start) { + if (pa->start < begin || pa->start > end) + return -ERANGE; + begin = pa->start; + } else { + struct fdisk_ask *ask = fdisk_new_ask(); + + if (!ask) + return -ENOMEM; + fdisk_ask_set_query(ask, + fdisk_context_use_cylinders(cxt) ? + _("First cylinder") : _("First sector")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, begin)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end)); + + rc = fdisk_do_ask(cxt, ask); + begin = fdisk_ask_number_get_result(ask); fdisk_free_ask(ask); - return rc; + if (rc) + return rc; + if (fdisk_context_use_cylinders(cxt)) + begin = (begin - 1) * d->d_secpercyl; } - begin = fdisk_ask_number_get_result(ask); - - if (fdisk_context_use_cylinders(cxt)) - begin = (begin - 1) * d->d_secpercyl; - - fdisk_reset_ask(ask); /* * Last sector */ - fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); - - if (fdisk_context_use_cylinders(cxt)) { - fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}")); - fdisk_ask_number_set_unit(ask, - cxt->sector_size * - fdisk_context_get_units_per_sector(cxt)); + if (pa && pa->end_follow_default) + ; + else if (pa && pa->size) { + if (begin + pa->size > end) + return -ERANGE; + end = begin + pa->size; } else { - fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); - fdisk_ask_number_set_unit(ask,cxt->sector_size); - } - - fdisk_ask_number_set_low(ask, bsd_cround(cxt, begin)); - fdisk_ask_number_set_default(ask, bsd_cround(cxt, end)); - fdisk_ask_number_set_high(ask, bsd_cround(cxt, end)); - fdisk_ask_number_set_base(ask, bsd_cround(cxt, begin)); + /* ask user by dialog */ + struct fdisk_ask *ask = fdisk_new_ask(); + + if (!ask) + return -ENOMEM; + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + + if (fdisk_context_use_cylinders(cxt)) { + fdisk_ask_set_query(ask, _("Last cylinder, +cylinders or +size{K,M,G,T,P}")); + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_context_get_units_per_sector(cxt)); + } else { + fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); + fdisk_ask_number_set_unit(ask,cxt->sector_size); + } - rc = fdisk_do_ask(cxt, ask); - end = fdisk_ask_number_get_result(ask); - fdisk_free_ask(ask); - if (rc) - return rc; + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, begin)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, end)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, end)); + fdisk_ask_number_set_base(ask, fdisk_cround(cxt, begin)); - if (fdisk_context_use_cylinders(cxt)) - end = end * d->d_secpercyl - 1; + rc = fdisk_do_ask(cxt, ask); + end = fdisk_ask_number_get_result(ask); + fdisk_free_ask(ask); + if (rc) + return rc; + if (fdisk_context_use_cylinders(cxt)) + end = end * d->d_secpercyl - 1; + } d->d_partitions[i].p_size = end - begin + 1; d->d_partitions[i].p_offset = begin; @@ -278,6 +293,9 @@ static int bsd_add_part (struct fdisk_context *cxt, d->d_npartitions = i + 1; cxt->label->nparts_cur = d->d_npartitions; + if (pa && pa->type) + bsd_set_parttype(cxt, i, pa->type); + fdisk_label_set_changed(cxt->label, 1); return 0; } @@ -403,17 +421,11 @@ static int bsd_get_partition(struct fdisk_context *cxt, size_t n, return 0; if (fdisk_context_use_cylinders(cxt) && d->d_secpercyl) { - pa->start = p->p_offset / d->d_secpercyl + 1; pa->start_post = p->p_offset % d->d_secpercyl ? '*' : ' '; - - pa->end = (p->p_offset + p->p_size + d->d_secpercyl - 1) / d->d_secpercyl; pa->end_post = (p->p_offset + p->p_size) % d->d_secpercyl ? '*' : ' '; - } else { - pa->start = p->p_offset; - pa->end = p->p_offset + p->p_size - 1; } - pa->size = p->p_size * cxt->sector_size; + pa->size = p->p_size; pa->type = bsd_partition_parttype(cxt, p); if (p->p_fstype == BSD_FS_UNUSED || p->p_fstype == BSD_FS_BSDFFS) { @@ -697,6 +709,11 @@ static int bsd_readlabel(struct fdisk_context *cxt) fdisk_warnx(cxt, ("Too many partitions (%d, maximum is %d)."), d->d_npartitions, BSD_MAXPARTITIONS); + /* let's follow in-PT geometry */ + cxt->geom.sectors = d->d_nsectors; + cxt->geom.heads = d->d_ntracks; + cxt->geom.cylinders = d->d_ncylinders; + cxt->label->nparts_cur = d->d_npartitions; cxt->label->nparts_max = BSD_MAXPARTITIONS; DBG(LABEL, dbgprint("read BSD label")); @@ -848,10 +865,10 @@ static const struct fdisk_label_operations bsd_operations = .list = bsd_list_disklabel, .write = bsd_write_disklabel, .create = bsd_create_disklabel, - .part_add = bsd_add_part, .part_delete = bsd_delete_part, .get_part = bsd_get_partition, + .add_part = bsd_add_partition, .part_set_type = bsd_set_parttype, .part_is_used = bsd_partition_is_used, diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c index 7daf467e17..e23470f655 100644 --- a/libfdisk/src/dos.c +++ b/libfdisk/src/dos.c @@ -173,15 +173,15 @@ static int is_cleared_partition(struct dos_partition *p) dos_partition_get_start(p) || dos_partition_get_size(p)); } -static int get_partition_unused_primary(struct fdisk_context *cxt) +static int get_partition_unused_primary(struct fdisk_context *cxt, + struct fdisk_partition *pa) { - size_t orgmax = cxt->label->nparts_max; - size_t n; + size_t org = cxt->label->nparts_max, n; int rc; cxt->label->nparts_max = 4; - rc = fdisk_ask_partnum(cxt, &n, TRUE); - cxt->label->nparts_max = orgmax; + rc = fdisk_partition_next_partno(cxt, pa, &n); + cxt->label->nparts_max = org; switch (rc) { case 1: @@ -812,9 +812,58 @@ static void fill_bounds(struct fdisk_context *cxt, } } -static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_parttype *t) +static int get_start_from_user( struct fdisk_context *cxt, + sector_t *start, + sector_t low, + sector_t dflt, + sector_t limit, + struct fdisk_partition *pa) { - int sys, read = 0, rc; + assert(start); + + /* try to use tepmlate from 'pa' */ + if (pa && pa->start_follow_default) + *start = dflt; + + else if (pa && pa->start) { + *start = pa->start; + if (*start < low || *start > limit) + return -ERANGE; + } else { + /* ask user by dialog */ + struct fdisk_ask *ask = fdisk_new_ask(); + int rc; + + if (!ask) + return -ENOMEM; + fdisk_ask_set_query(ask, + fdisk_context_use_cylinders(cxt) ? + _("First cylinder") : _("First sector")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, low)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, dflt)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, limit)); + + rc = fdisk_do_ask(cxt, ask); + *start = fdisk_ask_number_get_result(ask); + fdisk_free_ask(ask); + if (rc) + return rc; + if (fdisk_context_use_cylinders(cxt)) { + *start = (*start - 1) + * fdisk_context_get_units_per_sector(cxt); + if (*start < low) + *start = low; + } + } + + return 0; +} + +static int add_partition(struct fdisk_context *cxt, size_t n, + struct fdisk_partition *pa) +{ + int sys, read = 0, rc, isrel = 0; size_t i; struct fdisk_dos_label *l = self_label(cxt); struct dos_partition *p = self_partition(cxt, n); @@ -826,7 +875,7 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt DBG(LABEL, dbgprint("DOS: adding partition %zu", n)); - sys = t ? t->type : MBR_LINUX_DATA_PARTITION; + sys = pa ? pa->type->type : MBR_LINUX_DATA_PARTITION; if (is_used_partition(p)) { fdisk_warnx(cxt, _("Partition %zu is already defined. " @@ -861,7 +910,7 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt } if (fdisk_context_use_cylinders(cxt)) for (i = 0; i < cxt->label->nparts_max; i++) { - first[i] = (cround(cxt, first[i]) - 1) + first[i] = (fdisk_cround(cxt, first[i]) - 1) * fdisk_context_get_units_per_sector(cxt); } @@ -893,32 +942,9 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt } if (!read && start == temp) { - sector_t j = start; - struct fdisk_ask *ask = fdisk_new_ask(); - - if (fdisk_context_use_cylinders(cxt)) - fdisk_ask_set_query(ask, _("First cylinder")); - else - fdisk_ask_set_query(ask, _("First sector")); - - fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); - fdisk_ask_number_set_low(ask, cround(cxt, j)); - fdisk_ask_number_set_default(ask, cround(cxt, dflt)); - fdisk_ask_number_set_high(ask, cround(cxt, limit)); - - rc = fdisk_do_ask(cxt, ask); - if (!rc) - start = fdisk_ask_number_get_result(ask); - fdisk_free_ask(ask); + rc = get_start_from_user(cxt, &start, temp, dflt, limit, pa); if (rc) return rc; - - if (fdisk_context_use_cylinders(cxt)) { - start = (start - 1) - * fdisk_context_get_units_per_sector(cxt); - if (start < j) - start = j; - } read = 1; } } while (start != temp || !read); @@ -948,14 +974,25 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt cxt->label->nparts_max--; return -ENOSPC; } - if (cround(cxt, start) == cround(cxt, limit)) { + + /* + * Ask for last sector + */ + if (fdisk_cround(cxt, start) == fdisk_cround(cxt, limit)) + stop = limit; + else if (pa && pa->end_follow_default) stop = limit; + else if (pa && pa->size) { + stop = start + pa->size; + if (stop > limit) + return -ERANGE; + isrel = 1; } else { - /* - * Ask for last sector - */ + /* ask user by dialog */ struct fdisk_ask *ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); if (fdisk_context_use_cylinders(cxt)) { @@ -968,26 +1005,29 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt fdisk_ask_number_set_unit(ask,cxt->sector_size); } - fdisk_ask_number_set_low(ask, cround(cxt, start)); - fdisk_ask_number_set_default(ask, cround(cxt, limit)); - fdisk_ask_number_set_high(ask, cround(cxt, limit)); - fdisk_ask_number_set_base(ask, cround(cxt, start)); /* base for relative input */ + fdisk_ask_number_set_low(ask, fdisk_cround(cxt, start)); + fdisk_ask_number_set_default(ask, fdisk_cround(cxt, limit)); + fdisk_ask_number_set_high(ask, fdisk_cround(cxt, limit)); + fdisk_ask_number_set_base(ask, fdisk_cround(cxt, start)); /* base for relative input */ rc = fdisk_do_ask(cxt, ask); - if (rc) { - fdisk_free_ask(ask); - return rc; - } - stop = fdisk_ask_number_get_result(ask); - + isrel = fdisk_ask_number_is_relative(ask); + fdisk_free_ask(ask); + if (rc) + return rc; if (fdisk_context_use_cylinders(cxt)) { stop = stop * fdisk_context_get_units_per_sector(cxt) - 1; - if (stop >limit) - stop = limit; + if (stop >limit) + stop = limit; } - if (fdisk_ask_number_is_relative(ask) - && alignment_required(cxt)) { + } + + if (stop > limit) + stop = limit; + + if (stop < limit) { + if (isrel && alignment_required(cxt)) { /* the last sector has not been exactly requested (but * defined by +size{K,M,G} convention), so be smart and * align the end of the partition. The next partition @@ -997,7 +1037,6 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt if (stop > limit) stop = limit; } - fdisk_free_ask(ask); } set_partition(cxt, n, 0, start, stop, sys); @@ -1030,7 +1069,7 @@ static int add_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partt return 0; } -static int add_logical(struct fdisk_context *cxt) +static int add_logical(struct fdisk_context *cxt, struct fdisk_partition *pa) { struct dos_partition *p4 = self_partition(cxt, 4); @@ -1054,7 +1093,7 @@ static int add_logical(struct fdisk_context *cxt) } fdisk_info(cxt, _("Adding logical partition %zu"), cxt->label->nparts_max); - return add_partition(cxt, cxt->label->nparts_max - 1, NULL); + return add_partition(cxt, cxt->label->nparts_max - 1, pa); } static void check(struct fdisk_context *cxt, size_t n, @@ -1246,10 +1285,8 @@ static int dos_verify_disklabel(struct fdisk_context *cxt) * * API callback. */ -static int dos_add_partition( - struct fdisk_context *cxt, - size_t partnum __attribute__ ((__unused__)), - struct fdisk_parttype *t) +static int dos_add_partition(struct fdisk_context *cxt, + struct fdisk_partition *pa) { size_t i, free_primary = 0; int rc = 0; @@ -1274,7 +1311,7 @@ static int dos_add_partition( if (!free_primary) { if (l->ext_offset) { fdisk_info(cxt, _("All primary partitions are in use.")); - rc = add_logical(cxt); + rc = add_logical(cxt, pa); } else fdisk_info(cxt, _("If you want to create more than " "four partitions, you must replace a " @@ -1286,9 +1323,9 @@ static int dos_add_partition( fdisk_info(cxt, _("All logical partitions are in use. " "Adding a primary partition.")); - j = get_partition_unused_primary(cxt); + j = get_partition_unused_primary(cxt, pa); if (j >= 0) - rc = add_partition(cxt, j, t); + rc = add_partition(cxt, j, pa); } else { char *buf; char c, prompt[BUFSIZ]; @@ -1317,19 +1354,25 @@ static int dos_add_partition( free(buf); if (c == 'p') { - int j = get_partition_unused_primary(cxt); + int j = get_partition_unused_primary(cxt, pa); if (j >= 0) - rc = add_partition(cxt, j, t); + rc = add_partition(cxt, j, pa); goto done; } else if (c == 'l' && l->ext_offset) { - rc = add_logical(cxt); + rc = add_logical(cxt, pa); goto done; } else if (c == 'e' && !l->ext_offset) { - int j = get_partition_unused_primary(cxt); + int j = get_partition_unused_primary(cxt, pa); if (j >= 0) { + struct fdisk_partition xpa = { .type = NULL }; + struct fdisk_parttype *t; + t = fdisk_get_parttype_from_code(cxt, MBR_DOS_EXTENDED_PARTITION); - rc = add_partition(cxt, j, t); + if (!pa) + pa = &xpa; + fdisk_partition_set_type(pa, t); + rc = add_partition(cxt, j, pa); } goto done; } else @@ -1622,9 +1665,9 @@ static int dos_get_partition(struct fdisk_context *cxt, size_t n, pa->type = dos_partition_parttype(cxt, p); pa->boot = p->boot_ind ? p->boot_ind == ACTIVE_FLAG ? '*' : '?' : ' '; - pa->start = cround(cxt, get_abs_partition_start(pe)); - pa->end = cround(cxt, get_abs_partition_start(pe) + psects - (psects ? 1 : 0)); - pa->size = psects * cxt->sector_size; + pa->start = get_abs_partition_start(pe); + pa->end = get_abs_partition_start(pe) + psects - (psects ? 1 : 0); + pa->size = psects; if (asprintf(&pa->attrs, "%02x", p->boot_ind) < 0) return -ENOMEM; @@ -1901,8 +1944,8 @@ static const struct fdisk_label_operations dos_operations = .set_id = dos_set_disklabel_id, .get_part = dos_get_partition, + .add_part = dos_add_partition, - .part_add = dos_add_partition, .part_delete = dos_delete_partition, .part_set_type = dos_set_parttype, @@ -1938,8 +1981,6 @@ struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) lb->columns = dos_columns; lb->ncolumns = ARRAY_SIZE(dos_columns); - lb->flags |= FDISK_LABEL_FL_ADDPART_NOPARTNO; - return lb; } diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h index a948fb571a..fbeaf7ee20 100644 --- a/libfdisk/src/fdiskP.h +++ b/libfdisk/src/fdiskP.h @@ -153,11 +153,15 @@ struct fdisk_partition { char *start_addr; char *end_addr; - unsigned int nested : 1, /* logical partition */ + unsigned int partno_follow_default : 1, + start_follow_default : 1, + end_follow_default : 1, + nested : 1, /* logical partition */ used : 1, /* partition used */ endrel : 1; /* end is specified as relative number */ }; +#define FDISK_EMPTY_PARTNO ((size_t) -1) /* * Legacy CHS based geometry @@ -191,9 +195,8 @@ struct fdisk_label_operations { int (*set_id)(struct fdisk_context *cxt); /* new partition */ - int (*part_add)(struct fdisk_context *cxt, - size_t partnum, - struct fdisk_parttype *t); + int (*add_part)(struct fdisk_context *cxt, struct fdisk_partition *pa); + /* delete partition */ int (*part_delete)(struct fdisk_context *cxt, size_t partnum); @@ -269,7 +272,6 @@ struct fdisk_label { /* label driver flags */ enum { - FDISK_LABEL_FL_ADDPART_NOPARTNO = (1 << 1), FDISK_LABEL_FL_REQUIRE_GEOMETRY = (1 << 2), FDISK_LABEL_FL_INCHARS_PARTNO = (1 << 3) }; diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c index ebfc0162b0..14aafc4724 100644 --- a/libfdisk/src/gpt.c +++ b/libfdisk/src/gpt.c @@ -1301,7 +1301,7 @@ static int gpt_get_partition(struct fdisk_context *cxt, size_t n, pa->start = gpt_partition_start(e); pa->end = gpt_partition_end(e); - pa->size = gpt_partition_size(e) * cxt->sector_size; + pa->size = gpt_partition_size(e); pa->type = gpt_partition_parttype(cxt, e); if (guid_to_string(&e->partition_guid, u_str)) { @@ -1713,8 +1713,7 @@ static int gpt_create_new_partition(struct fdisk_context *cxt, /* Performs logical checks to add a new partition entry */ static int gpt_add_partition( struct fdisk_context *cxt, - size_t partnum, - struct fdisk_parttype *t) + struct fdisk_partition *pa) { uint64_t user_f, user_l; /* user input ranges for first and last sectors */ uint64_t disk_f, disk_l; /* first and last available sector ranges on device*/ @@ -1724,6 +1723,7 @@ static int gpt_add_partition( struct gpt_header *pheader; struct gpt_entry *ents; struct fdisk_ask *ask = NULL; + size_t partnum; int rc; assert(cxt); @@ -1731,29 +1731,32 @@ static int gpt_add_partition( assert(fdisk_is_disklabel(cxt, GPT)); gpt = self_label(cxt); - - if (partnum >= cxt->label->nparts_max) - return -EINVAL; - pheader = gpt->pheader; ents = gpt->ents; + rc = fdisk_partition_next_partno(cxt, pa, &partnum); + if (rc) + return rc; + if (!partition_unused(&ents[partnum])) { fdisk_warnx(cxt, _("Partition %zu is already defined. " "Delete it before re-adding it."), partnum +1); - return -EINVAL; + return -ERANGE; } if (le32_to_cpu(pheader->npartition_entries) == partitions_in_use(pheader, ents)) { fdisk_warnx(cxt, _("All partitions are already in use.")); - return -EINVAL; + return -ENOSPC; } - if (!get_free_sectors(cxt, pheader, ents, NULL, NULL)) { fdisk_warnx(cxt, _("No free sectors available.")); return -ENOSPC; } + string_to_guid(pa && pa->type && pa->type->typestr ? + pa->type->typestr: + GPT_DEFAULT_ENTRY_TYPE, &typeid); + disk_f = find_first_available(pheader, ents, 0); disk_l = find_last_free_sector(pheader, ents); @@ -1764,54 +1767,79 @@ static int gpt_add_partition( /* align the default in range */ dflt_f = fdisk_align_lba_in_range(cxt, dflt_f, dflt_f, dflt_l); - string_to_guid(t && t->typestr ? t->typestr : GPT_DEFAULT_ENTRY_TYPE, &typeid); - - /* get user input for first and last sectors of the new partition */ - for (;;) { - if (!ask) - ask = fdisk_new_ask(); - else - fdisk_reset_ask(ask); - - /* First sector */ - fdisk_ask_set_query(ask, _("First sector")); - fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); - fdisk_ask_number_set_low(ask, disk_f); /* minimal */ - fdisk_ask_number_set_default(ask, dflt_f); /* default */ - fdisk_ask_number_set_high(ask, disk_l); /* maximal */ - - rc = fdisk_do_ask(cxt, ask); - if (rc) - goto done; - - user_f = fdisk_ask_number_get_result(ask); - if (user_f != find_first_available(pheader, ents, user_f)) { - fdisk_warnx(cxt, _("Sector %ju already used."), user_f); - continue; + /* first sector */ + if (pa && pa->start) { + if (pa->start != find_first_available(pheader, ents, pa->start)) { + fdisk_warnx(cxt, _("Sector %ju already used."), pa->start); + return -ERANGE; } - - fdisk_reset_ask(ask); - - /* Last sector */ - dflt_l = find_last_free(pheader, ents, user_f); - - fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); - fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); - fdisk_ask_number_set_low(ask, user_f); /* minimal */ - fdisk_ask_number_set_default(ask, dflt_l); /* default */ - fdisk_ask_number_set_high(ask, dflt_l); /* maximal */ - fdisk_ask_number_set_base(ask, user_f); /* base for relative input */ - fdisk_ask_number_set_unit(ask, cxt->sector_size); - - rc = fdisk_do_ask(cxt, ask); - if (rc) - goto done; - - user_l = fdisk_ask_number_get_result(ask); - if (fdisk_ask_number_is_relative(ask)) - user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; - if (user_l > user_f && user_l <= disk_l) + user_f = pa->start; + } else if (pa && pa->start_follow_default) { + user_f = dflt_f; + } else { + /* ask by dialog */ + for (;;) { + if (!ask) + ask = fdisk_new_ask(); + else + fdisk_reset_ask(ask); + + /* First sector */ + fdisk_ask_set_query(ask, _("First sector")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + fdisk_ask_number_set_low(ask, disk_f); /* minimal */ + fdisk_ask_number_set_default(ask, dflt_f); /* default */ + fdisk_ask_number_set_high(ask, disk_l); /* maximal */ + + rc = fdisk_do_ask(cxt, ask); + if (rc) + goto done; + + user_f = fdisk_ask_number_get_result(ask); + if (user_f != find_first_available(pheader, ents, user_f)) { + fdisk_warnx(cxt, _("Sector %ju already used."), user_f); + continue; + } break; + } + } + + /* Last sector */ + dflt_l = find_last_free(pheader, ents, user_f); + + if (pa && pa->size) { + if (pa->size + user_f > dflt_l) + return -ERANGE; + user_l = user_f + pa->size; + user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; + + } else if (pa && pa->end_follow_default) { + user_l = dflt_l; + } else { + for (;;) { + if (!ask) + ask = fdisk_new_ask(); + else + fdisk_reset_ask(ask); + + fdisk_ask_set_query(ask, _("Last sector, +sectors or +size{K,M,G,T,P}")); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + fdisk_ask_number_set_low(ask, user_f); /* minimal */ + fdisk_ask_number_set_default(ask, dflt_l); /* default */ + fdisk_ask_number_set_high(ask, dflt_l); /* maximal */ + fdisk_ask_number_set_base(ask, user_f); /* base for relative input */ + fdisk_ask_number_set_unit(ask, cxt->sector_size); + + rc = fdisk_do_ask(cxt, ask); + if (rc) + goto done; + + user_l = fdisk_ask_number_get_result(ask); + if (fdisk_ask_number_is_relative(ask)) + user_l = fdisk_align_lba_in_range(cxt, user_l, user_f, dflt_l) - 1; + if (user_l > user_f && user_l <= disk_l) + break; + } } if (gpt_create_new_partition(cxt, partnum, @@ -2223,8 +2251,8 @@ static const struct fdisk_label_operations gpt_operations = .set_id = gpt_set_disklabel_id, .get_part = gpt_get_partition, + .add_part = gpt_add_partition, - .part_add = gpt_add_partition, .part_delete = gpt_delete_partition, .part_is_used = gpt_part_is_used, diff --git a/libfdisk/src/label.c b/libfdisk/src/label.c index bf2542a167..358162c57e 100644 --- a/libfdisk/src/label.c +++ b/libfdisk/src/label.c @@ -305,7 +305,11 @@ int fdisk_list_partitions(struct fdisk_context *cxt, int *cols, size_t ncols) col = fdisk_label_get_column(cxt->label, cols[j]); if (!col) continue; - tt_define_column(tb, col->name, col->width, col->tt_flags); + tt_define_column(tb, + col->id == FDISK_COL_SECTORS && + fdisk_context_use_cylinders(cxt) ? + _("Cylinders") : col->name, + col->width, col->tt_flags); } /* generate per-partition lines into table */ @@ -324,11 +328,17 @@ int fdisk_list_partitions(struct fdisk_context *cxt, int *cols, size_t ncols) /* set data for the columns */ for (j = 0; j < ncols; j++) { char *data = NULL; + int id; col = fdisk_label_get_column(cxt->label, cols[j]); if (!col) continue; - rc = fdisk_partition_to_string(pa, col->id, &data); + id = (col->id == FDISK_COL_SECTORS && + fdisk_context_use_cylinders(cxt)) ? + FDISK_COL_CYLINDERS : + col->id; + + rc = fdisk_partition_to_string(pa, id, &data); if (rc) continue; tt_line_set_data(ln, j, data); @@ -350,35 +360,30 @@ done: /** * fdisk_add_partition: * @cxt: fdisk context - * @t: partition type to create or NULL for label-specific default + * @pa: template for the partition + * + * If @pa is not specified or any @pa item is missiong the libfdisk will ask by + * fdisk_ask_ API. * - * Creates a new partition with type @parttype. + * Creates a new partition. * * Returns 0. */ int fdisk_add_partition(struct fdisk_context *cxt, - struct fdisk_parttype *t) + struct fdisk_partition *pa) { - size_t partnum = 0; - assert(cxt); assert(cxt->label); if (!cxt || !cxt->label) return -EINVAL; - if (!cxt->label->op->part_add) + if (!cxt->label->op->add_part) return -ENOSYS; if (fdisk_missing_geometry(cxt)) return -EINVAL; - if (!(cxt->label->flags & FDISK_LABEL_FL_ADDPART_NOPARTNO)) { - int rc = fdisk_ask_partnum(cxt, &partnum, 1); - if (rc) - return rc; - } - - DBG(LABEL, dbgprint("adding new partition number %zd", partnum)); - cxt->label->op->part_add(cxt, partnum, t); + DBG(LABEL, dbgprint("adding new partition")); + cxt->label->op->add_part(cxt, pa); return 0; } diff --git a/libfdisk/src/libfdisk.h b/libfdisk/src/libfdisk.h index d3b646007e..f493774718 100644 --- a/libfdisk/src/libfdisk.h +++ b/libfdisk/src/libfdisk.h @@ -120,6 +120,7 @@ enum { FDISK_COL_START, FDISK_COL_END, FDISK_COL_SECTORS, + FDISK_COL_CYLINDERS, FDISK_COL_SIZE, FDISK_COL_TYPE, FDISK_COL_TYPEID, @@ -155,7 +156,7 @@ extern int fdisk_set_disklabel_id(struct fdisk_context *cxt); extern int fdisk_get_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition **pa); -extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_parttype *t); +extern int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa); extern int fdisk_delete_partition(struct fdisk_context *cxt, size_t partnum); extern int fdisk_set_partition_type(struct fdisk_context *cxt, size_t partnum, @@ -197,6 +198,9 @@ extern int fdisk_partition_is_nested(struct fdisk_partition *pa); extern int fdisk_partition_is_used(struct fdisk_partition *pa); extern int fdisk_partition_to_string(struct fdisk_partition *pa, int id, char **data); +extern int fdisk_partition_next_partno( struct fdisk_context *cxt, + struct fdisk_partition *pa, size_t *n); + /* alignment.c */ extern int fdisk_reset_alignment(struct fdisk_context *cxt); extern int fdisk_reset_device_properties(struct fdisk_context *cxt); diff --git a/libfdisk/src/partition.c b/libfdisk/src/partition.c index add505fba4..65cdc9f484 100644 --- a/libfdisk/src/partition.c +++ b/libfdisk/src/partition.c @@ -8,6 +8,7 @@ struct fdisk_partition *fdisk_new_partition(void) { struct fdisk_partition *pa = calloc(1, sizeof(*pa)); + pa->partno = FDISK_EMPTY_PARTNO; DBG(PART, dbgprint("new %p", pa)); return pa; } @@ -21,6 +22,7 @@ void fdisk_reset_partition(struct fdisk_partition *pa) free(pa->uuid); free(pa->attrs); memset(pa, 0, sizeof(*pa)); + pa->partno = FDISK_EMPTY_PARTNO; } void fdisk_free_partition(struct fdisk_partition *pa) @@ -168,6 +170,32 @@ int fdisk_partition_is_used(struct fdisk_partition *pa) return pa && pa->used; } +int fdisk_partition_next_partno( + struct fdisk_context *cxt, + struct fdisk_partition *pa, + size_t *n) +{ + assert(cxt); + assert(n); + + if (pa && pa->partno_follow_default) { + size_t i; + + for (i = 0; i < pa->cxt->label->nparts_max; i++) { + if (!fdisk_is_partition_used(cxt, i)) { + *n = i; + break; + } + } + } else if (pa && pa->partno != FDISK_EMPTY_PARTNO) { + if (pa->partno >= pa->cxt->label->nparts_max) + return -ERANGE; + *n = pa->partno; + } else + return fdisk_ask_partnum(cxt, n, 1); + + return 0; +} /** * fdisk_partition_to_string: @@ -198,6 +226,7 @@ int fdisk_partition_to_string(struct fdisk_partition *pa, { char *p = NULL; int rc = 0; + uint64_t x; if (!pa || !pa->cxt) return -EINVAL; @@ -213,28 +242,38 @@ int fdisk_partition_to_string(struct fdisk_partition *pa, rc = asprintf(&p, "%c", pa->boot); break; case FDISK_COL_START: + x = fdisk_cround(pa->cxt, pa->start); rc = pa->start_post ? - asprintf(&p, "%ju%c", pa->start, pa->start_post) : - asprintf(&p, "%ju", pa->start); + asprintf(&p, "%ju%c", x, pa->start_post) : + asprintf(&p, "%ju", x); break; case FDISK_COL_END: + x = fdisk_cround(pa->cxt, pa->end); rc = pa->end_post ? - asprintf(&p, "%ju%c", pa->end, pa->end_post) : - asprintf(&p, "%ju", pa->end); + asprintf(&p, "%ju%c", x, pa->end_post) : + asprintf(&p, "%ju", x); break; case FDISK_COL_SIZE: + { + uint64_t sz = pa->size * pa->cxt->sector_size; + if (fdisk_context_display_details(pa->cxt)) { rc = pa->size_post ? - asprintf(&p, "%ju%c", pa->size, pa->size_post) : - asprintf(&p, "%ju", pa->size); + asprintf(&p, "%ju%c", sz, pa->size_post) : + asprintf(&p, "%ju", sz); } else { - p = size_to_human_string(SIZE_SUFFIX_1LETTER, pa->size); + p = size_to_human_string(SIZE_SUFFIX_1LETTER, sz); if (!p) rc = -ENOMEM; } break; + } + case FDISK_COL_CYLINDERS: + rc = asprintf(&p, "%ju", (uintmax_t) + fdisk_cround(pa->cxt, pa->size)); + break; case FDISK_COL_SECTORS: - rc = asprintf(&p, "%ju", pa->size / pa->cxt->sector_size); + rc = asprintf(&p, "%ju", pa->size); break; case FDISK_COL_BSIZE: rc = asprintf(&p, "%ju", pa->bsize); diff --git a/libfdisk/src/sgi.c b/libfdisk/src/sgi.c index 7e3b03f1fd..aa03d0319a 100644 --- a/libfdisk/src/sgi.c +++ b/libfdisk/src/sgi.c @@ -369,9 +369,9 @@ static int sgi_get_partition(struct fdisk_context *cxt, size_t n, struct fdisk_p len = sgi_get_num_sectors(cxt, n); pa->type = sgi_get_parttype(cxt, n); - pa->size = len * cxt->sector_size; - pa->start = fdisk_scround(cxt, start); - pa->end = fdisk_scround(cxt, start + len) - 1; + pa->size = len; + pa->start = start; + pa->end = start + len - (len ? 1 : 0); pa->attrs = sgi_get_swappartition(cxt) == (int) n ? "swap" : sgi_get_bootpartition(cxt) == (int) n ? "boot" : NULL; @@ -799,20 +799,23 @@ static int sgi_delete_partition(struct fdisk_context *cxt, size_t partnum) } static int sgi_add_partition(struct fdisk_context *cxt, - size_t n, - struct fdisk_parttype *t) + struct fdisk_partition *pa) { struct fdisk_sgi_label *sgi; char mesg[256]; unsigned int first = 0, last = 0; struct fdisk_ask *ask; - int sys = t ? t->type : SGI_TYPE_XFS; + int sys = pa && pa->type ? pa->type->type : SGI_TYPE_XFS; int rc; + size_t n; assert(cxt); assert(cxt->label); assert(fdisk_is_disklabel(cxt, SGI)); + rc = fdisk_partition_next_partno(cxt, pa, &n); + if (rc) + return rc; if (n == 10) sys = SGI_TYPE_ENTIRE_DISK; else if (n == 8) @@ -839,9 +842,26 @@ static int sgi_add_partition(struct fdisk_context *cxt, return -EINVAL; } - snprintf(mesg, sizeof(mesg), _("First %s"), - fdisk_context_get_unit(cxt, SINGULAR)); - for (;;) { + if (sys == SGI_TYPE_ENTIRE_DISK) { + first = 0; + last = sgi_get_lastblock(cxt); + } else { + first = sgi->freelist[0].first; + last = sgi->freelist[0].last; + } + + /* first sector */ + if (pa && pa->start_follow_default) + ; + else if (pa && pa->start) { + first = pa->start; + last = is_in_freelist(cxt, first); + + if (sys != SGI_TYPE_ENTIRE_DISK && !last) + return -ERANGE; + } else { + snprintf(mesg, sizeof(mesg), _("First %s"), + fdisk_context_get_unit(cxt, SINGULAR)); ask = fdisk_new_ask(); if (!ask) return -ENOMEM; @@ -849,76 +869,68 @@ static int sgi_add_partition(struct fdisk_context *cxt, fdisk_ask_set_query(ask, mesg); fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); - if (sys == SGI_TYPE_ENTIRE_DISK) { - last = sgi_get_lastblock(cxt); - fdisk_ask_number_set_low(ask, 0); /* minimal */ - fdisk_ask_number_set_default(ask, 0); /* default */ - fdisk_ask_number_set_high(ask, last - 1); /* maximal */ - } else { - first = sgi->freelist[0].first; - last = sgi->freelist[0].last; - fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ - fdisk_ask_number_set_default(ask, fdisk_scround(cxt, first)); /* default */ - fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1); /* maximal */ - } + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, first)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1); /* maximal */ + rc = fdisk_do_ask(cxt, ask); first = fdisk_ask_number_get_result(ask); fdisk_free_ask(ask); if (rc) return rc; - - if (first && sys == SGI_TYPE_ENTIRE_DISK) - fdisk_info(cxt, _("It is highly recommended that the " - "eleventh partition covers the entire " - "disk and is of type 'SGI volume'.")); - if (fdisk_context_use_cylinders(cxt)) first *= fdisk_context_get_units_per_sector(cxt); - /*else - first = first; * align to cylinder if you know how ... */ - if (!last) - last = is_in_freelist(cxt, first); - if (last == 0) - fdisk_warnx(cxt, _("You will get a partition overlap " - "on the disk. Fix it first!")); - else - break; } - snprintf(mesg, sizeof(mesg), - _("Last %s or +%s or +size{K,M,G,T,P}"), - fdisk_context_get_unit(cxt, SINGULAR), - fdisk_context_get_unit(cxt, PLURAL)); - - ask = fdisk_new_ask(); - if (!ask) - return -ENOMEM; + if (first && sys == SGI_TYPE_ENTIRE_DISK) + fdisk_info(cxt, _("It is highly recommended that the " + "eleventh partition covers the entire " + "disk and is of type 'SGI volume'.")); + if (!last) + last = is_in_freelist(cxt, first); + + /* last sector */ + if (pa && pa->end_follow_default) + last -= 1; + else if (pa && pa->size) { + if (first + pa->size > last) + return -ERANGE; + last = first + pa->size; + } else { + snprintf(mesg, sizeof(mesg), + _("Last %s or +%s or +size{K,M,G,T,P}"), + fdisk_context_get_unit(cxt, SINGULAR), + fdisk_context_get_unit(cxt, PLURAL)); - fdisk_ask_set_query(ask, mesg); - fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; - fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ - fdisk_ask_number_set_default(ask, fdisk_scround(cxt, last) - 1);/* default */ - fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1);/* maximal */ - fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); - if (fdisk_context_use_cylinders(cxt)) - fdisk_ask_number_set_unit(ask, - cxt->sector_size * - fdisk_context_get_units_per_sector(cxt)); - else - fdisk_ask_number_set_unit(ask,cxt->sector_size); + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, last) - 1);/* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, last) - 1);/* maximal */ + fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); - rc = fdisk_do_ask(cxt, ask); - last = fdisk_ask_number_get_result(ask) + 1; + if (fdisk_context_use_cylinders(cxt)) + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_context_get_units_per_sector(cxt)); + else + fdisk_ask_number_set_unit(ask,cxt->sector_size); - fdisk_free_ask(ask); - if (rc) - return rc; + rc = fdisk_do_ask(cxt, ask); + last = fdisk_ask_number_get_result(ask) + 1; - if (fdisk_context_use_cylinders(cxt)) - last *= fdisk_context_get_units_per_sector(cxt); + fdisk_free_ask(ask); + if (rc) + return rc; + if (fdisk_context_use_cylinders(cxt)) + last *= fdisk_context_get_units_per_sector(cxt); + } if (sys == SGI_TYPE_ENTIRE_DISK && (first != 0 || last != sgi_get_lastblock(cxt))) @@ -1126,8 +1138,8 @@ static const struct fdisk_label_operations sgi_operations = .list = sgi_list_table, .get_part = sgi_get_partition, + .add_part = sgi_add_partition, - .part_add = sgi_add_partition, .part_delete = sgi_delete_partition, .part_set_type = sgi_set_parttype, diff --git a/libfdisk/src/sun.c b/libfdisk/src/sun.c index b15fd58730..f7e07b46ff 100644 --- a/libfdisk/src/sun.c +++ b/libfdisk/src/sun.c @@ -448,24 +448,45 @@ static int sun_verify_disklabel(struct fdisk_context *cxt) return 0; } + +static int is_free_sector(struct fdisk_context *cxt, + sector_t s, uint32_t starts[], uint32_t lens[]) +{ + size_t i; + + for (i = 0; i < cxt->label->nparts_max; i++) { + if (lens[i] && starts[i] <= s + && starts[i] + lens[i] > s) + return 0; + } + return 1; +} + static int sun_add_partition( struct fdisk_context *cxt, - size_t n, - struct fdisk_parttype *t) + struct fdisk_partition *pa) { struct sun_disklabel *sunlabel = self_disklabel(cxt); uint32_t starts[SUN_MAXPARTITIONS], lens[SUN_MAXPARTITIONS]; - struct sun_partition *part = &sunlabel->partitions[n]; - struct sun_info *info = &sunlabel->vtoc.infos[n]; + struct sun_partition *part; + struct sun_info *info; uint32_t start, stop, stop2; - int whole_disk = 0, sys = t ? t->type : SUN_TAG_LINUX_NATIVE; - struct fdisk_ask *ask; + int whole_disk = 0; + int sys = pa && pa->type ? pa->type->type : SUN_TAG_LINUX_NATIVE; int rc; + size_t n; char mesg[256]; size_t i; unsigned int first, last; + rc = fdisk_partition_next_partno(cxt, pa, &n); + if (rc) + return rc; + + part = &sunlabel->partitions[n]; + info = &sunlabel->vtoc.infos[n]; + if (part->num_sectors && be16_to_cpu(info->id) != SUN_TAG_UNASSIGNED) { fdisk_info(cxt, _("Partition %zu is already defined. Delete " "it before re-adding it."), n + 1); @@ -483,130 +504,151 @@ static int sun_add_partition( return -EINVAL; } } - snprintf(mesg, sizeof(mesg), _("First %s"), - fdisk_context_get_unit(cxt, SINGULAR)); - for (;;) { - ask = fdisk_new_ask(); - if (!ask) - return -ENOMEM; - fdisk_ask_set_query(ask, mesg); - fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + if (pa && pa->start_follow_default) + first = start; + else if (pa && pa->start) { + first = pa->start; - if (whole_disk) { - fdisk_ask_number_set_low(ask, 0); /* minimal */ - fdisk_ask_number_set_default(ask, 0); /* default */ - fdisk_ask_number_set_high(ask, 0); /* maximal */ - } else { - fdisk_ask_number_set_low(ask, fdisk_scround(cxt, start)); /* minimal */ - fdisk_ask_number_set_default(ask, fdisk_scround(cxt, start)); /* default */ - fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */ + if (!whole_disk && !is_free_sector(cxt, first, starts, lens)) + return -ERANGE; + } else { + struct fdisk_ask *ask; + + snprintf(mesg, sizeof(mesg), _("First %s"), + fdisk_context_get_unit(cxt, SINGULAR)); + for (;;) { + ask = fdisk_new_ask(); + if (!ask) + return -ENOMEM; + + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_NUMBER); + + if (whole_disk) { + fdisk_ask_number_set_low(ask, 0); /* minimal */ + fdisk_ask_number_set_default(ask, 0); /* default */ + fdisk_ask_number_set_high(ask, 0); /* maximal */ + } else { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, start)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, start)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */ + } + rc = fdisk_do_ask(cxt, ask); + first = fdisk_ask_number_get_result(ask); + fdisk_free_ask(ask); + if (rc) + return rc; + + if (fdisk_context_use_cylinders(cxt)) + first *= fdisk_context_get_units_per_sector(cxt); + + /* ewt asks to add: "don't start a partition at cyl 0" + However, edmundo@rano.demon.co.uk writes: + "In addition to having a Sun partition table, to be able to + boot from the disc, the first partition, /dev/sdX1, must + start at cylinder 0. This means that /dev/sdX1 contains + the partition table and the boot block, as these are the + first two sectors of the disc. Therefore you must be + careful what you use /dev/sdX1 for. In particular, you must + not use a partition starting at cylinder 0 for Linux swap, + as that would overwrite the partition table and the boot + block. You may, however, use such a partition for a UFS + or EXT2 file system, as these file systems leave the first + 1024 bytes undisturbed. */ + /* On the other hand, one should not use partitions + starting at block 0 in an md, or the label will + be trashed. */ + if (!is_free_sector(cxt, first, starts, lens) && !whole_disk) { + if (n == 2 && !first) { + whole_disk = 1; + break; + } + fdisk_warnx(cxt, _("Sector %d is already allocated"), first); + } else + break; } - rc = fdisk_do_ask(cxt, ask); - first = fdisk_ask_number_get_result(ask); - fdisk_free_ask(ask); - - if (rc) - return rc; + } - if (fdisk_context_use_cylinders(cxt)) - first *= fdisk_context_get_units_per_sector(cxt); - else { - /* Starting sector has to be properly aligned */ - int cs = cxt->geom.heads * cxt->geom.sectors; - int x = first % cs; - - if (x) { - fdisk_info(cxt, _("Aligning the first sector from %u to %u " - "to be on cylinder boundary."), - first, first + cs - x); - first += cs - x; - } + if (n == 2 && first != 0) + fdisk_warnx(cxt, _("It is highly recommended that the " + "third partition covers the whole disk " + "and is of type `Whole disk'")); + + if (!fdisk_context_use_cylinders(cxt)) { + /* Starting sector has to be properly aligned */ + int cs = cxt->geom.heads * cxt->geom.sectors; + int x = first % cs; + + if (x) { + fdisk_info(cxt, _("Aligning the first sector from %u to %u " + "to be on cylinder boundary."), + first, first + cs - x); + first += cs - x; } - if (n == 2 && first != 0) - fdisk_warnx(cxt, _("It is highly recommended that the " - "third partition covers the whole disk " - "and is of type `Whole disk'")); - /* ewt asks to add: "don't start a partition at cyl 0" - However, edmundo@rano.demon.co.uk writes: - "In addition to having a Sun partition table, to be able to - boot from the disc, the first partition, /dev/sdX1, must - start at cylinder 0. This means that /dev/sdX1 contains - the partition table and the boot block, as these are the - first two sectors of the disc. Therefore you must be - careful what you use /dev/sdX1 for. In particular, you must - not use a partition starting at cylinder 0 for Linux swap, - as that would overwrite the partition table and the boot - block. You may, however, use such a partition for a UFS - or EXT2 file system, as these file systems leave the first - 1024 bytes undisturbed. */ - /* On the other hand, one should not use partitions - starting at block 0 in an md, or the label will - be trashed. */ - for (i = 0; i < cxt->label->nparts_max; i++) - if (lens[i] && starts[i] <= first - && starts[i] + lens[i] > first) - break; - if (i < cxt->label->nparts_max && !whole_disk) { - if (n == 2 && !first) { - whole_disk = 1; - break; - } - fdisk_warnx(cxt, _("Sector %d is already allocated"), first); - } else - break; } + stop = cxt->geom.cylinders * cxt->geom.heads * cxt->geom.sectors; /* ancient */ stop2 = stop; for (i = 0; i < cxt->label->nparts_max; i++) { if (starts[i] > first && starts[i] < stop) stop = starts[i]; } - snprintf(mesg, sizeof(mesg), - _("Last %s or +%s or +size{K,M,G,T,P}"), - fdisk_context_get_unit(cxt, SINGULAR), - fdisk_context_get_unit(cxt, PLURAL)); - - ask = fdisk_new_ask(); - if (!ask) - return -ENOMEM; - - fdisk_ask_set_query(ask, mesg); - fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); - - if (whole_disk) { - fdisk_ask_number_set_low(ask, fdisk_scround(cxt, stop2)); /* minimal */ - fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */ - fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */ - fdisk_ask_number_set_base(ask, 0); - } else if (n == 2 && !first) { - fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ - fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */ - fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */ - fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + + /* last */ + if (pa && pa->end_follow_default) + last = whole_disk || (n == 2 && !first) ? stop2 : stop; + else if (pa && pa->size) { + last = pa->size; + + if (!whole_disk && last > stop) + return -ERANGE; } else { - fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ - fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop)); /* default */ - fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */ - fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); - } + struct fdisk_ask *ask = fdisk_new_ask(); - if (fdisk_context_use_cylinders(cxt)) - fdisk_ask_number_set_unit(ask, - cxt->sector_size * - fdisk_context_get_units_per_sector(cxt)); - else - fdisk_ask_number_set_unit(ask, cxt->sector_size); + if (!ask) + return -ENOMEM; - rc = fdisk_do_ask(cxt, ask); - last = fdisk_ask_number_get_result(ask); + snprintf(mesg, sizeof(mesg), + _("Last %s or +%s or +size{K,M,G,T,P}"), + fdisk_context_get_unit(cxt, SINGULAR), + fdisk_context_get_unit(cxt, PLURAL)); + fdisk_ask_set_query(ask, mesg); + fdisk_ask_set_type(ask, FDISK_ASKTYPE_OFFSET); - fdisk_free_ask(ask); - if (rc) - return rc; + if (whole_disk) { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, stop2)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */ + fdisk_ask_number_set_base(ask, 0); + } else if (n == 2 && !first) { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop2)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop2)); /* maximal */ + fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + } else { + fdisk_ask_number_set_low(ask, fdisk_scround(cxt, first)); /* minimal */ + fdisk_ask_number_set_default(ask, fdisk_scround(cxt, stop)); /* default */ + fdisk_ask_number_set_high(ask, fdisk_scround(cxt, stop)); /* maximal */ + fdisk_ask_number_set_base(ask, fdisk_scround(cxt, first)); + } + + if (fdisk_context_use_cylinders(cxt)) + fdisk_ask_number_set_unit(ask, + cxt->sector_size * + fdisk_context_get_units_per_sector(cxt)); + else + fdisk_ask_number_set_unit(ask, cxt->sector_size); - if (fdisk_context_use_cylinders(cxt)) - last *= fdisk_context_get_units_per_sector(cxt); + rc = fdisk_do_ask(cxt, ask); + last = fdisk_ask_number_get_result(ask); + + fdisk_free_ask(ask); + if (rc) + return rc; + if (fdisk_context_use_cylinders(cxt)) + last *= fdisk_context_get_units_per_sector(cxt); + } if (n == 2 && !first) { if (last >= stop2) { @@ -743,9 +785,9 @@ static int sun_get_partition(struct fdisk_context *cxt, size_t n, return -ENOMEM; } - pa->start = fdisk_scround(cxt, start); - pa->end = fdisk_scround(cxt, start + len - 1); - pa->size = len * cxt->sector_size; + pa->start = start; + pa->end = start + len - (len ? 1 : 0); + pa->size = len; return 0; } @@ -961,8 +1003,8 @@ const struct fdisk_label_operations sun_operations = .list = sun_list_disklabel, .get_part = sun_get_partition, + .add_part = sun_add_partition, - .part_add = sun_add_partition, .part_delete = sun_delete_partition, .part_set_type = sun_set_parttype,