]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: use partition template
authorKarel Zak <kzak@redhat.com>
Fri, 29 Nov 2013 20:55:53 +0000 (21:55 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 11 Mar 2014 10:35:12 +0000 (11:35 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libfdisk/src/bsd.c
libfdisk/src/dos.c
libfdisk/src/fdiskP.h
libfdisk/src/gpt.c
libfdisk/src/label.c
libfdisk/src/libfdisk.h
libfdisk/src/partition.c
libfdisk/src/sgi.c
libfdisk/src/sun.c

index fc7786892c046b6a8289c25a060fc9fed5358b01..4ee31b6dd5aa472e9fee68182143ae70bb5ceea5 100644 (file)
@@ -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,
index 7daf467e1769f0c76bd162b9ed561ad857e90291..e23470f655265f336d5dd86e514d3d8462e0ce30 100644 (file)
@@ -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;
 }
 
index a948fb571a2a5ab703b69d7d3b3e69719a85f862..fbeaf7ee209fb67b58334b4db5c0e4fede61bb5f 100644 (file)
@@ -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)
 };
index ebfc0162b06884359bd245e86a5080e1a322c3db..14aafc47246511e75f2e3cd295490eae1d7586c6 100644 (file)
@@ -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,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,
@@ -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,
index bf2542a16723763b02ad7509bbd7d3ff08715dc2..358162c57ed3cda590f59b9b4b3f6d4546e2de4c 100644 (file)
@@ -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;
 }
 
index d3b646007e735590f7e72f202ad9e592beb006ac..f493774718a2eb3e75ab31fb9fb90791cea28a34 100644 (file)
@@ -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);
index add505fba4599e75001adc6313ccbb062a5e3a57..65cdc9f48476427fa47dc4f63794ec79bb8ba917 100644 (file)
@@ -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);
index 7e3b03f1fdd4001ca7c5d56e40a616675d10cf36..aa03d0319aaf3292417b93c474c6d606f2601a83 100644 (file)
@@ -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,
 
index b15fd58730a46b4cd14fdd6605b6ef6f67ad7eb9..f7e07b46ff146dd69a40ba77074398896dd1bdc7 100644 (file)
@@ -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,