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)
{
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;
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;
}
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) {
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"));
.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,
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:
}
}
-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);
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. "
}
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);
}
}
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);
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)) {
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
if (stop > limit)
stop = limit;
}
- fdisk_free_ask(ask);
}
set_partition(cxt, n, 0, start, stop, sys);
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);
}
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,
*
* 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;
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 "
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];
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
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;
.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,
lb->columns = dos_columns;
lb->ncolumns = ARRAY_SIZE(dos_columns);
- lb->flags |= FDISK_LABEL_FL_ADDPART_NOPARTNO;
-
return lb;
}
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
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);
/* 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)
};
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)) {
/* 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*/
struct gpt_header *pheader;
struct gpt_entry *ents;
struct fdisk_ask *ask = NULL;
+ size_t partnum;
int rc;
assert(cxt);
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);
/* align the default in range <dflt_f,dflt_l>*/
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,
.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,
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 */
/* 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);
/**
* 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;
}
FDISK_COL_START,
FDISK_COL_END,
FDISK_COL_SECTORS,
+ FDISK_COL_CYLINDERS,
FDISK_COL_SIZE,
FDISK_COL_TYPE,
FDISK_COL_TYPEID,
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,
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);
{
struct fdisk_partition *pa = calloc(1, sizeof(*pa));
+ pa->partno = FDISK_EMPTY_PARTNO;
DBG(PART, dbgprint("new %p", pa));
return 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)
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:
{
char *p = NULL;
int rc = 0;
+ uint64_t x;
if (!pa || !pa->cxt)
return -EINVAL;
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);
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;
}
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)
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;
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)))
.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,
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);
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) {
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;
}
.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,