]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - libfdisk/src/sgi.c
libfdisk: remove dependence on libsmartcols
[thirdparty/util-linux.git] / libfdisk / src / sgi.c
index d2e877832902367e62e088e3a42dd8c79485a159..8e8d3208e1357f47be6c0c7418d4f243917f4a50 100644 (file)
@@ -3,13 +3,14 @@
  * Copyright (C) 2012 Davidlohr Bueso <dave@gnu.org>
  *               2013 Karel Zak <kzak@redhat.com>
  *
- * This is re-written version for libfdisk, the original was fdisksgilabel.c
+ * This is re-written version for libfdisk, the original was fdisksgilabel.c
  * from util-linux fdisk, by:
  *
- *               Andreas Neuper, Sep 1998.
- *               Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999
- *               Phillip Kesling <pkesling@sgi.com>, Mar 2003
+ *               Andreas Neuper, Sep 1998,
+ *               Arnaldo Carvalho de Melo <acme@conectiva.com.br>, Mar 1999,
+ *               Phillip Kesling <pkesling@sgi.com>, Mar 2003.
  */
+
 #include "c.h"
 #include "nls.h"
 #include "all-io.h"
@@ -62,7 +63,7 @@ static unsigned int sgi_get_num_sectors(struct fdisk_context *cxt, int i );
 static int sgi_get_bootpartition(struct fdisk_context *cxt);
 static int sgi_get_swappartition(struct fdisk_context *cxt);
 
-/* return poiter buffer with on-disk data */
+/* Returns a pointer buffer with on-disk data. */
 static inline struct sgi_disklabel *self_disklabel(struct fdisk_context *cxt)
 {
        assert(cxt);
@@ -72,7 +73,7 @@ static inline struct sgi_disklabel *self_disklabel(struct fdisk_context *cxt)
        return ((struct fdisk_sgi_label *) cxt->label)->header;
 }
 
-/* return in-memory fdisk data */
+/* Returns in-memory fdisk data. */
 static inline struct fdisk_sgi_label *self_label(struct fdisk_context *cxt)
 {
        assert(cxt);
@@ -138,7 +139,7 @@ int fdisk_sgi_create_info(struct fdisk_context *cxt)
        sgilabel->volume[0].num_bytes = cpu_to_be32(sizeof(struct sgi_info));
        strncpy((char *) sgilabel->volume[0].name, "sgilabel", 8);
 
-       fdisk_info(cxt, _("SGI info created on second sector"));
+       fdisk_info(cxt, _("SGI info created on second sector."));
        return 0;
 }
 
@@ -238,7 +239,7 @@ static int sgi_probe_label(struct fdisk_context *cxt)
         * test for correct checksum
         */
        if (sgi_pt_checksum(sgilabel) != 0)
-               fdisk_warnx(cxt, _("Detected sgi disklabel with wrong checksum."));
+               fdisk_warnx(cxt, _("Detected an SGI disklabel with wrong checksum."));
 
        clear_freelist(cxt);
        cxt->label->nparts_max = SGI_MAXPARTITIONS;
@@ -248,15 +249,12 @@ static int sgi_probe_label(struct fdisk_context *cxt)
 
 static int sgi_list_table(struct fdisk_context *cxt)
 {
-       struct tt *tb = NULL;
        struct sgi_disklabel *sgilabel = self_disklabel(cxt);
        struct sgi_device_parameter *sgiparam = &sgilabel->devparam;
-       size_t i, used;
-       char *p;
-       int rc;
+       int rc = 0;
 
        if (fdisk_context_display_details(cxt))
-               fdisk_colon(cxt, _(
+               fdisk_info(cxt, _(
                        "Label geometry: %d heads, %llu sectors\n"
                        "                %llu cylinders, %d physical cylinders\n"
                        "                %d extra sects/cyl, interleave %d:1\n"),
@@ -264,106 +262,7 @@ static int sgi_list_table(struct fdisk_context *cxt)
                        cxt->geom.cylinders, be16_to_cpu(sgiparam->pcylcount),
                        (int) sgiparam->sparecyl, be16_to_cpu(sgiparam->ilfact));
 
-       /*
-        * Partitions
-        */
-       tb = tt_new_table(TT_FL_FREEDATA);
-       if (!tb)
-               return -ENOMEM;
-
-       tt_define_column(tb, _("Pt#"),      3, TT_FL_RIGHT);
-       tt_define_column(tb, _("Device"), 0.2, 0);
-       tt_define_column(tb, _("Info"),     2, 0);
-       tt_define_column(tb, _("Start"),    9, TT_FL_RIGHT);
-       tt_define_column(tb, _("End"),      9, TT_FL_RIGHT);
-       tt_define_column(tb, _("Sectors"),  9, TT_FL_RIGHT);
-       tt_define_column(tb, _("Id"),       2, TT_FL_RIGHT);
-       tt_define_column(tb, _("System"), 0.2, TT_FL_TRUNC);
-
-       for (i = 0, used = 1; i < cxt->label->nparts_max; i++) {
-               uint32_t start, len;
-               struct fdisk_parttype *t;
-               struct tt_line *ln;
-
-               if (sgi_get_num_sectors(cxt, i) == 0)
-                       continue;
-
-               ln = tt_add_line(tb, NULL);
-               if (!ln)
-                       continue;
-               start = sgi_get_start_sector(cxt, i);
-               len = sgi_get_num_sectors(cxt, i);
-               t = fdisk_get_partition_type(cxt, i);
-
-               if (asprintf(&p, "%zu:", i + 1) > 0)
-                       tt_line_set_data(ln, 0, p);     /* # */
-               p = fdisk_partname(cxt->dev_path, used++);
-               if (p)
-                       tt_line_set_data(ln, 1, p);     /* Device */
-
-               p = sgi_get_swappartition(cxt) == (int) i ? "swap" :
-                   sgi_get_bootpartition(cxt) == (int) i ? "boot" : NULL;
-               if (p)
-                       tt_line_set_data(ln, 2, strdup(p));     /* Info */
-
-               if (asprintf(&p, "%ju", (uintmax_t) fdisk_scround(cxt, start)) > 0)
-                       tt_line_set_data(ln, 3, p);     /* Start */
-               if (asprintf(&p, "%ju", (uintmax_t) fdisk_scround(cxt, start + len) - 1) > 0)
-                       tt_line_set_data(ln, 4, p);     /* End */
-               if (asprintf(&p, "%ju", (uintmax_t) len) > 0)
-                       tt_line_set_data(ln, 5, p);     /* Sectors*/
-               if (asprintf(&p, "%2x", t->type) > 0)
-                       tt_line_set_data(ln, 6, p);     /* type ID */
-               if (t->name)
-                       tt_line_set_data(ln, 7, strdup(t->name)); /* type Name */
-               fdisk_free_parttype(t);
-       }
-
-       rc = fdisk_print_table(cxt, tb);
-       tt_free_table(tb);
-       if (rc)
-               return rc;
-
-       /*
-        * Volumes
-        */
-       tb = tt_new_table(TT_FL_FREEDATA);
-       if (!tb)
-               return -ENOMEM;
-
-       tt_define_column(tb, _("#"),       3, TT_FL_RIGHT);
-       tt_define_column(tb, _("Name"),  0.2, 0);
-       tt_define_column(tb, _("Sector"),  2, TT_FL_RIGHT);
-       tt_define_column(tb, _("Size"),    9, TT_FL_RIGHT);
-
-       for (i = 0, used = 0; i < SGI_MAXVOLUMES; i++) {
-               struct tt_line *ln;
-               uint32_t start = be32_to_cpu(sgilabel->volume[i].block_num),
-                        len = be32_to_cpu(sgilabel->volume[i].num_bytes);
-               if (!len)
-                       continue;
-               ln = tt_add_line(tb, NULL);
-               if (!ln)
-                       continue;
-               if (asprintf(&p, "%zu:", i) > 0)
-                       tt_line_set_data(ln, 0, p);             /* # */
-               if (*sgilabel->volume[i].name)
-                       tt_line_set_data(ln, 1,
-                               strndup((char *) sgilabel->volume[i].name,
-                                       sizeof(sgilabel->volume[i].name)));     /* Name */
-               if (asprintf(&p, "%ju", (uintmax_t) start) > 0)
-                       tt_line_set_data(ln, 2, p);     /* Sector */
-               if (asprintf(&p, "%ju", (uintmax_t) len) > 0)
-                       tt_line_set_data(ln, 3, p);     /* Size */
-               used++;
-       }
-
-       if (used)
-               rc = fdisk_print_table(cxt, tb);
-       tt_free_table(tb);
-
-       fdisk_colon(cxt, _("Bootfile: %s"), sgilabel->boot_file);
-
+       fdisk_info(cxt, _("Bootfile: %s"), sgilabel->boot_file);
        return rc;
 }
 
@@ -402,6 +301,46 @@ static unsigned int sgi_get_lastblock(struct fdisk_context *cxt)
        return cxt->geom.heads * cxt->geom.sectors * cxt->geom.cylinders;
 }
 
+static struct fdisk_parttype *sgi_get_parttype(struct fdisk_context *cxt, size_t n)
+{
+       struct fdisk_parttype *t;
+
+       if (n >= cxt->label->nparts_max)
+               return NULL;
+
+       t = fdisk_get_parttype_from_code(cxt, sgi_get_sysid(cxt, n));
+       return t ? : fdisk_new_unknown_parttype(sgi_get_sysid(cxt, n), NULL);
+}
+
+/* fdisk_get_partition() backend */
+static int sgi_get_partition(struct fdisk_context *cxt, size_t n, struct fdisk_partition *pa)
+{
+       uint64_t start, len;
+
+       pa->used = sgi_get_num_sectors(cxt, n) > 0;
+       if (!pa->used)
+               return 0;
+
+       start = sgi_get_start_sector(cxt, n);
+       len = sgi_get_num_sectors(cxt, n);
+
+       pa->type = sgi_get_parttype(cxt, n);
+       pa->size = len;
+       pa->start = start;
+       pa->end = start + len - (len ? 1 : 0);
+
+       if (pa->type && pa->type->type == SGI_TYPE_ENTIRE_DISK)
+               pa->wholedisk = 1;
+
+       pa->attrs = sgi_get_swappartition(cxt) == (int) n ? "swap" :
+                   sgi_get_bootpartition(cxt) == (int) n ? "boot" : NULL;
+       if (pa->attrs)
+               pa->attrs = strdup(pa->attrs);
+
+       return 0;
+}
+
+
 static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name)
 {
        size_t sz;
@@ -411,14 +350,16 @@ static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name)
 
        if (sz < 3) {
                /* "/a\n" is minimum */
-               fdisk_warnx(cxt, _("Invalid Bootfile! "
-                        "The bootfile must be an absolute non-zero pathname,"
-                        "e.g. \"/unix\" or \"/unix.save\"."));
+               fdisk_warnx(cxt, _("Invalid bootfile!  The bootfile must "
+                                  "be an absolute non-zero pathname, "
+                                  "e.g. \"/unix\" or \"/unix.save\"."));
                return -EINVAL;
 
        } else if (sz > sizeof(sgilabel->boot_file)) {
-               fdisk_warnx(cxt, _("Name of Bootfile too long: %zu bytes maximum."),
-                               sizeof(sgilabel->boot_file));
+               fdisk_warnx(cxt, P_("Name of bootfile is too long: %zu byte maximum.",
+                                   "Name of bootfile is too long: %zu bytes maximum.",
+                                   sizeof(sgilabel->boot_file)),
+                           sizeof(sgilabel->boot_file));
                return -EINVAL;
 
        } else if (*name != '/') {
@@ -428,11 +369,10 @@ static int sgi_check_bootfile(struct fdisk_context *cxt, const char *name)
 
        if (strncmp(name, (char *) sgilabel->boot_file,
                                sizeof(sgilabel->boot_file))) {
-               fdisk_warnx(cxt, _("Be aware, that the bootfile is not checked "
-                       "for existence. SGI's default is \"/unix\" and for "
-                       "backup \"/unix.save\"."));
-               /* filename is correct and did change */
-               return 0;
+               fdisk_warnx(cxt, _("Be aware that the bootfile is not checked "
+                                  "for existence.  SGI's default is \"/unix\", "
+                                  "and for backup \"/unix.save\"."));
+               return 0;       /* filename is correct and did change */
        }
 
        return 1;       /* filename did not change */
@@ -452,7 +392,7 @@ int fdisk_sgi_set_bootfile(struct fdisk_context *cxt)
                rc = sgi_check_bootfile(cxt, name);
        if (rc) {
                if (rc == 1)
-                       fdisk_info(cxt, _("Boot file unchanged"));
+                       fdisk_info(cxt, _("Boot file is unchanged."));
                goto done;
        }
 
@@ -464,7 +404,7 @@ int fdisk_sgi_set_bootfile(struct fdisk_context *cxt)
        memcpy(sgilabel->boot_file, name, sz);
 
        fdisk_sinfo(cxt, FDISK_INFO_SUCCESS,
-                       _("Bootfile is changed to \"%s\"."), name);
+                       _("Bootfile has been changed to \"%s\"."), name);
 done:
        free(name);
        return rc;
@@ -491,8 +431,8 @@ static int sgi_write_disklabel(struct fdisk_context *cxt)
                goto err;
        if (!strncmp((char *) sgilabel->volume[0].name, "sgilabel", 8)) {
                /*
-                * keep this habit of first writing the "sgilabel".
-                * I never tested whether it works without (AN 981002).
+                * Keep this habit of first writing the "sgilabel".
+                * I never tested whether it works without. (AN 1998-10-02)
                 */
                int infostartblock
                        = be32_to_cpu(sgilabel->volume[0].block_num);
@@ -518,8 +458,8 @@ static int compare_start(struct fdisk_context *cxt,
                         const void *x, const void *y)
 {
        /*
-        * sort according to start sectors and prefers largest partition: entry
-        * zero is entire disk entry
+        * Sort according to start sectors and prefer the largest partition:
+        * entry zero is the entire-disk entry.
         */
        unsigned int i = *(int *) x;
        unsigned int j = *(int *) y;
@@ -611,7 +551,7 @@ static int verify_disklabel(struct fdisk_context *cxt, int verbose)
        }
        if (sortcount == 0) {
                if (verbose)
-                       fdisk_info(cxt, _("No partitions defined"));
+                       fdisk_info(cxt, _("No partitions defined."));
                return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
        }
 
@@ -619,23 +559,23 @@ static int verify_disklabel(struct fdisk_context *cxt, int verbose)
 
        if (sgi_get_sysid(cxt, Index[0]) == SGI_TYPE_ENTIRE_DISK) {
                if (verbose && Index[0] != 10)
-                       fdisk_info(cxt, _("IRIX likes when Partition 11 "
+                       fdisk_info(cxt, _("IRIX likes it when partition 11 "
                                          "covers the entire disk."));
 
                if (verbose && sgi_get_start_sector(cxt, Index[0]) != 0)
                        fdisk_info(cxt, _("The entire disk partition should "
-                               "start at block 0, not at diskblock %d."),
-                              sgi_get_start_sector(cxt, Index[0]));
+                                         "start at block 0, not at block %d."),
+                                  sgi_get_start_sector(cxt, Index[0]));
 
                if (verbose && sgi_get_num_sectors(cxt, Index[0]) != lastblock)
-                       DBG(LABEL, dbgprint(
+                       DBG(LABEL, ul_debug(
                                "entire disk partition=%ds, but disk=%ds",
                                sgi_get_num_sectors(cxt, Index[0]),
                                lastblock));
                lastblock = sgi_get_num_sectors(cxt, Index[0]);
        } else if (verbose) {
                fdisk_info(cxt, _("Partition 11 should cover the entire disk."));
-               DBG(LABEL, dbgprint("sysid=%d\tpartition=%d",
+               DBG(LABEL, ul_debug("sysid=%d\tpartition=%d",
                               sgi_get_sysid(cxt, Index[0]), Index[0]+1));
        }
        for (i=1, start=0; i<sortcount; i++) {
@@ -643,56 +583,63 @@ static int verify_disklabel(struct fdisk_context *cxt, int verbose)
 
                if (verbose && cylsize
                    && (sgi_get_start_sector(cxt, Index[i]) % cylsize) != 0)
-                       DBG(LABEL, dbgprint("partition %d does not start on "
+                       DBG(LABEL, ul_debug("partition %d does not start on "
                                        "cylinder boundary.", Index[i]+1));
 
                if (verbose && cylsize
                    && sgi_get_num_sectors(cxt, Index[i]) % cylsize != 0)
-                       DBG(LABEL, dbgprint("partition %d does not end on "
+                       DBG(LABEL, ul_debug("partition %d does not end on "
                                        "cylinder boundary.", Index[i]+1));
 
                /* We cannot handle several "entire disk" entries. */
                if (sgi_get_sysid(cxt, Index[i]) == SGI_TYPE_ENTIRE_DISK)
                        continue;
+
                if (start > sgi_get_start_sector(cxt, Index[i])) {
                        if (verbose)
-                               fdisk_info(cxt, _("The Partition %d and %d overlap "
-                                         "by %d sectors."),
-                                      Index[i-1]+1, Index[i]+1,
-                                      start - sgi_get_start_sector(cxt, Index[i]));
+                               fdisk_info(cxt,
+                                          P_("Partitions %d and %d overlap by %d sector.",
+                                             "Partitions %d and %d overlap by %d sectors.",
+                                             start - sgi_get_start_sector(cxt, Index[i])),
+                                          Index[i-1]+1, Index[i]+1,
+                                          start - sgi_get_start_sector(cxt, Index[i]));
                        if (gap >  0) gap = -gap;
                        if (gap == 0) gap = -1;
                }
                if (start < sgi_get_start_sector(cxt, Index[i])) {
                        if (verbose)
-                               fdisk_info(cxt, _("Unused gap of %8u sectors "
-                                           "- sectors %8u-%u"),
-                                      sgi_get_start_sector(cxt, Index[i]) - start,
-                                      start, sgi_get_start_sector(cxt, Index[i])-1);
+                               fdisk_info(cxt,
+                                          P_("Unused gap of %8u sector: sector %8u",
+                                             "Unused gap of %8u sectors: sectors %8u-%u",
+                                             sgi_get_start_sector(cxt, Index[i]) - start),
+                                          sgi_get_start_sector(cxt, Index[i]) - start,
+                                          start, sgi_get_start_sector(cxt, Index[i])-1);
                        gap += sgi_get_start_sector(cxt, Index[i]) - start;
                        add_to_freelist(cxt, start,
                                        sgi_get_start_sector(cxt, Index[i]));
                }
                start = sgi_get_start_sector(cxt, Index[i])
                        + sgi_get_num_sectors(cxt, Index[i]);
-               /* Align free space on cylinder boundary */
+               /* Align free space on cylinder boundary. */
                if (cylsize && start % cylsize)
                        start += cylsize - (start % cylsize);
 
-               DBG(LABEL, dbgprint("%2d:%12d\t%12d\t%12d", Index[i],
+               DBG(LABEL, ul_debug("%2d:%12d\t%12d\t%12d", Index[i],
                                       sgi_get_start_sector(cxt, Index[i]),
                                       sgi_get_num_sectors(cxt, Index[i]),
                                       sgi_get_sysid(cxt, Index[i])));
        }
        if (start < lastblock) {
                if (verbose)
-                       fdisk_info(cxt, _("Unused gap of %8u sectors - sectors %8u-%u"),
-                               lastblock - start, start, lastblock-1);
+                       fdisk_info(cxt, P_("Unused gap of %8u sector: sector %8u",
+                                          "Unused gap of %8u sectors: sectors %8u-%u",
+                                          lastblock - start),
+                                  lastblock - start, start, lastblock-1);
                gap += lastblock - start;
                add_to_freelist(cxt, start, lastblock);
        }
        /*
-        * Done with arithmetics. Go for details now
+        * Done with arithmetics. Go for details now.
         */
        if (verbose) {
                if (sgi_get_bootpartition(cxt) < 0
@@ -708,8 +655,7 @@ static int verify_disklabel(struct fdisk_context *cxt, int verbose)
                        fdisk_info(cxt, _("The swap partition has no swap type."));
 
                if (sgi_check_bootfile(cxt, "/unix"))
-                       fdisk_info(cxt, _("You have chosen an unusual boot "
-                                         "file name."));
+                       fdisk_info(cxt, _("You have chosen an unusual bootfile name."));
        }
 
        return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
@@ -731,7 +677,7 @@ static int sgi_gaps(struct fdisk_context *cxt)
        return verify_disklabel(cxt, 0);
 }
 
-/* returns partition index of first entry marked as entire disk */
+/* Returns partition index of first entry marked as entire disk. */
 static int sgi_entire(struct fdisk_context *cxt)
 {
        size_t i;
@@ -786,10 +732,7 @@ static void sgi_set_volhdr(struct fdisk_context *cxt)
 
        for (n = 8; n < cxt->label->nparts_max; n++) {
                if (!sgi_get_num_sectors(cxt, n)) {
-                       /*
-                        * Choose same default volume header size
-                        * as IRIX fx uses.
-                        */
+                       /* Choose same default volume header size as IRIX fx uses. */
                        if (4096 < sgi_get_lastblock(cxt))
                                sgi_set_partition(cxt, n, 0, 4096, SGI_TYPE_VOLHDR);
                        break;
@@ -815,20 +758,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(pa, cxt, &n);
+       if (rc)
+               return rc;
        if (n == 10)
                sys = SGI_TYPE_ENTIRE_DISK;
        else if (n == 8)
@@ -837,8 +783,8 @@ static int sgi_add_partition(struct fdisk_context *cxt,
        sgi = self_label(cxt);
 
        if (sgi_get_num_sectors(cxt, n)) {
-               fdisk_warnx(cxt, _("Partition %zd is already defined.  Delete "
-                        "it before re-adding it."), n + 1);
+               fdisk_warnx(cxt, _("Partition %zu is already defined.  "
+                                  "Delete it before re-adding it."), n + 1);
                return -EINVAL;
        }
        if (sgi_entire(cxt) == -1 &&  sys != SGI_TYPE_ENTIRE_DISK) {
@@ -855,9 +801,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;
@@ -865,82 +828,74 @@ 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 "
-                                       "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)))
-               fdisk_info(cxt, _("It is highly recommended that eleventh "
-                       "partition covers the entire disk and is of type "
-                       "`SGI volume'"));
+               fdisk_info(cxt, _("It is highly recommended that the "
+                                 "eleventh partition covers the entire "
+                                 "disk and is of type 'SGI volume'."));
 
        sgi_set_partition(cxt, n, first, last - first, sys);
        cxt->label->nparts_cur = count_used_partitions(cxt);
@@ -952,6 +907,7 @@ static int sgi_create_disklabel(struct fdisk_context *cxt)
 {
        struct fdisk_sgi_label *sgi;
        struct sgi_disklabel *sgilabel;
+       int rc;
 
        assert(cxt);
        assert(cxt->label);
@@ -973,14 +929,17 @@ static int sgi_create_disklabel(struct fdisk_context *cxt)
                } else {
                        /* otherwise print error and use truncated version */
                        fdisk_warnx(cxt,
-                               _("Warning:  BLKGETSIZE ioctl failed on %s. "
+                               _("BLKGETSIZE ioctl failed on %s. "
                                  "Using geometry cylinder value of %llu. "
                                  "This value may be truncated for devices "
                                  "> 33.8 GB."), cxt->dev_path, cxt->geom.cylinders);
                }
        }
 #endif
-       fdisk_zeroize_firstsector(cxt);
+       rc = fdisk_init_firstsector_buffer(cxt);
+       if (rc)
+               return rc;
+
        sgi = (struct fdisk_sgi_label *) cxt->label;
        sgi->header = (struct sgi_disklabel *) cxt->firstsector;
 
@@ -1038,19 +997,6 @@ static int sgi_create_disklabel(struct fdisk_context *cxt)
        return 0;
 }
 
-static struct fdisk_parttype *sgi_get_parttype(struct fdisk_context *cxt, size_t n)
-{
-       struct fdisk_parttype *t;
-
-       if (n >= cxt->label->nparts_max)
-               return NULL;
-
-       t = fdisk_get_parttype_from_code(cxt, sgi_get_sysid(cxt, n));
-       if (!t)
-               t = fdisk_new_unknown_parttype(sgi_get_sysid(cxt, n), NULL);
-       return t;
-}
-
 static int sgi_set_parttype(struct fdisk_context *cxt,
                size_t i,
                struct fdisk_parttype *t)
@@ -1068,8 +1014,8 @@ static int sgi_set_parttype(struct fdisk_context *cxt,
        if ((i == 10 && t->type != SGI_TYPE_ENTIRE_DISK)
            || (i == 8 && t->type != 0))
                fdisk_info(cxt, _("Consider leaving partition 9 as volume header (0), "
-                        "and partition 11 as entire volume (6), as IRIX "
-                        "expects it."));
+                                 "and partition 11 as entire volume (6), "
+                                 "as IRIX expects it."));
 
        if (((t->type != SGI_TYPE_ENTIRE_DISK) && (t->type != SGI_TYPE_VOLHDR))
            && (sgi_get_start_sector(cxt, i) < 1)) {
@@ -1090,24 +1036,16 @@ static int sgi_set_parttype(struct fdisk_context *cxt,
 }
 
 
-static int sgi_get_partition_status(
+static int sgi_partition_is_used(
                struct fdisk_context *cxt,
-               size_t i,
-               int *status)
+               size_t i)
 {
-
        assert(cxt);
        assert(fdisk_is_disklabel(cxt, SGI));
 
-       if (!status || i >= cxt->label->nparts_max)
-               return -EINVAL;
-
-       *status = FDISK_PARTSTAT_NONE;
-
-       if (sgi_get_num_sectors(cxt, i))
-               *status = FDISK_PARTSTAT_USED;
-
-       return 0;
+       if (i >= cxt->label->nparts_max)
+               return 0;
+       return sgi_get_num_sectors(cxt, i) ? 1 : 0;
 }
 
 static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsigned long flag)
@@ -1142,6 +1080,19 @@ static int sgi_toggle_partition_flag(struct fdisk_context *cxt, size_t i, unsign
        return 0;
 }
 
+static const struct fdisk_column sgi_columns[] =
+{
+       { FDISK_COL_DEVICE,     N_("Device"),    10,    0 },
+       { FDISK_COL_START,      N_("Start"),      5,    FDISK_COLFL_NUMBER },
+       { FDISK_COL_END,        N_("End"),        5,    FDISK_COLFL_NUMBER },
+       { FDISK_COL_SECTORS,    N_("Sectors"),    5,    FDISK_COLFL_NUMBER },
+       { FDISK_COL_CYLINDERS,  N_("Cylinders"),  5,    FDISK_COLFL_NUMBER },
+       { FDISK_COL_SIZE,       N_("Size"),       5,    FDISK_COLFL_NUMBER | FDISK_COLFL_EYECANDY },
+       { FDISK_COL_TYPEID,     N_("Id"),         2,    FDISK_COLFL_NUMBER },
+       { FDISK_COL_TYPE,       N_("Type"),     0.1,    FDISK_COLFL_EYECANDY },
+       { FDISK_COL_ATTR,       N_("Attrs"),      0,    FDISK_COLFL_NUMBER }
+};
+
 static const struct fdisk_label_operations sgi_operations =
 {
        .probe          = sgi_probe_label,
@@ -1149,18 +1100,18 @@ static const struct fdisk_label_operations sgi_operations =
        .verify         = sgi_verify_disklabel,
        .create         = sgi_create_disklabel,
        .list           = sgi_list_table,
-       .part_add       = sgi_add_partition,
+
+       .get_part       = sgi_get_partition,
+       .add_part       = sgi_add_partition,
+
        .part_delete    = sgi_delete_partition,
-       .part_get_type  = sgi_get_parttype,
        .part_set_type  = sgi_set_parttype,
 
-       .part_get_status = sgi_get_partition_status,
+       .part_is_used   = sgi_partition_is_used,
        .part_toggle_flag = sgi_toggle_partition_flag
 };
 
-/*
- * allocates SGI label driver
- */
+/* Allocates an SGI label driver. */
 struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt)
 {
        struct fdisk_label *lb;
@@ -1179,6 +1130,8 @@ struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt)
        lb->op = &sgi_operations;
        lb->parttypes = sgi_parttypes;
        lb->nparttypes = ARRAY_SIZE(sgi_parttypes);
+       lb->columns = sgi_columns;
+       lb->ncolumns = ARRAY_SIZE(sgi_columns);
 
        lb->flags |= FDISK_LABEL_FL_REQUIRE_GEOMETRY;