]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
fdisk: add new functions for work with fdisk_parttype
authorKarel Zak <kzak@redhat.com>
Tue, 25 Sep 2012 08:23:36 +0000 (10:23 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 27 Sep 2012 11:38:13 +0000 (13:38 +0200)
 - add flags to fdisk_parttype to store more information about the types
 - function for conversion from code to fdisk_parttype
 - function for conversion from string to fdisk_parttype
 - function for conversion from user input to fdisk_parttype
 - support for unknown complex types (e.g. unknown UUIDs)

Signed-off-by: Karel Zak <kzak@redhat.com>
fdisks/fdisk.c
fdisks/fdisk.h
fdisks/fdiskbsdlabel.c
fdisks/fdiskdoslabel.c
fdisks/fdisksgilabel.c
fdisks/fdisksunlabel.c
fdisks/utils.c

index b7e350f75583c0edd22d08c0f034f54a83551b60..12ddf54b53e9e4db9702ba3353123bb347b0f879 100644 (file)
@@ -228,19 +228,6 @@ get_sysid(struct fdisk_context *cxt, int i) {
                ptes[i].part_table->sys_ind);
 }
 
-
-char *partition_type(struct fdisk_context *cxt, unsigned char type)
-{
-       int i;
-       struct fdisk_parttype *types = cxt->label->parttypes;
-
-       for (i=0; types[i].name; i++)
-               if (types[i].type == type)
-                       return _(types[i].name);
-
-       return NULL;
-}
-
 void list_partition_types(struct fdisk_context *cxt)
 {
        struct fdisk_parttype *types;
@@ -581,27 +568,34 @@ read_chars(char *mesg)
        return *line_ptr;
 }
 
-int
-read_hex(struct fdisk_context *cxt)
+struct fdisk_parttype *read_partition_type(struct fdisk_context *cxt)
 {
-        int hex;
-
-        while (1)
-        {
-           read_char(_("Hex code (type L to list codes): "));
-           if (tolower(*line_ptr) == 'l')
-               list_partition_types(cxt);
-          else if (isxdigit (*line_ptr))
-          {
-             hex = 0;
-             do
-                hex = hex << 4 | hex_val(*line_ptr++);
-             while (isxdigit(*line_ptr));
-             return hex;
-          }
-        }
+       if (!cxt || !cxt->label || !cxt->label->nparttypes)
+               return NULL;
+
+        do {
+               size_t sz;
+
+               if (cxt->label->parttypes[0].typestr)
+                       read_chars(_("Partition type (type L to list all types): "));
+               else
+                       read_chars(_("Hex code (type L to list all codes): "));
+
+               sz = strlen(line_ptr);
+               if (!sz || line_ptr[sz - 1] != '\n' || sz == 1)
+                       continue;
+               line_ptr[sz - 1] = '\0';
+
+               if (tolower(*line_ptr) == 'l')
+                       list_partition_types(cxt);
+               else
+                       return fdisk_parse_parttype(cxt, line_ptr);
+        } while (1);
+
+       return NULL;
 }
 
+
 unsigned int
 read_int_with_suffix(struct fdisk_context *cxt,
        unsigned int low, unsigned int dflt, unsigned int high,
@@ -862,8 +856,8 @@ static void delete_partition(struct fdisk_context *cxt, int partnum)
 
 static void change_sysid(struct fdisk_context *cxt)
 {
-       const char *temp;
-       int i, sys, origsys;
+       int i;
+       struct fdisk_parttype *t, *org_t;
        struct partition *p;
 
        i = get_existing_partition(cxt, 0, partitions);
@@ -871,16 +865,18 @@ static void change_sysid(struct fdisk_context *cxt)
        if (i == -1)
                return;
        p = ptes[i].part_table;
-       origsys = sys = get_sysid(cxt, i);
+
+       /* TODO: add get_partition_type(xt, partn) to API */
+       org_t = t = fdisk_get_parttype_from_code(cxt, get_sysid(cxt, i));
 
        /* if changing types T to 0 is allowed, then
           the reverse change must be allowed, too */
-       if (!sys && disklabel != SGI_LABEL && disklabel != SUN_LABEL && !get_nr_sects(p))
+       if (!t && disklabel != SGI_LABEL && disklabel != SUN_LABEL && !get_nr_sects(p))
                 printf(_("Partition %d does not exist yet!\n"), i + 1);
         else while (1) {
-               sys = read_hex (cxt);
+               t = read_partition_type(cxt);
 
-               if (!sys && disklabel != SGI_LABEL && disklabel != SUN_LABEL) {
+               if (!t && disklabel != SGI_LABEL && disklabel != SUN_LABEL) {
                        printf(_("Type 0 means free space to many systems\n"
                               "(but not to Linux). Having partitions of\n"
                               "type 0 is probably unwise. You can delete\n"
@@ -888,8 +884,11 @@ static void change_sysid(struct fdisk_context *cxt)
                        /* break; */
                }
 
+               if (!t)
+                       continue;
+
                if (disklabel != SGI_LABEL && disklabel != SUN_LABEL) {
-                       if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
+                       if (IS_EXTENDED (t->type) != IS_EXTENDED (p->sys_ind)) {
                                printf(_("You cannot change a partition into"
                                       " an extended one or vice versa\n"
                                       "Delete it first.\n"));
@@ -897,42 +896,51 @@ static void change_sysid(struct fdisk_context *cxt)
                        }
                }
 
-                if (sys < 256) {
-                       if (disklabel == SUN_LABEL && i == 2 && sys != SUN_TAG_BACKUP)
+               /* TODO: add set_partition_type(cxt, npart, type) API */
+                if (t->type < 256) {
+                       if (disklabel == SUN_LABEL && i == 2 && t->type != SUN_TAG_BACKUP)
                                printf(_("Consider leaving partition 3 "
                                       "as Whole disk (5),\n"
                                       "as SunOS/Solaris expects it and "
                                       "even Linux likes it.\n\n"));
-                       if (disklabel == SGI_LABEL && ((i == 10 && sys != ENTIRE_DISK)
-                                         || (i == 8 && sys != 0)))
+                       if (disklabel == SGI_LABEL && ((i == 10 && t->type != ENTIRE_DISK)
+                                         || (i == 8 && t->type != 0)))
                                printf(_("Consider leaving partition 9 "
                                       "as volume header (0),\nand "
                                       "partition 11 as entire volume (6), "
                                       "as IRIX expects it.\n\n"));
-                        if (sys == origsys)
-                               break;
+                        if (t == org_t)
+                               goto nochange;
+
                        if (disklabel == SUN_LABEL) {
-                               ptes[i].changed = sun_change_sysid(cxt, i, sys);
+                               ptes[i].changed = sun_change_sysid(cxt, i, t->type);
                        } else
                        if (disklabel == SGI_LABEL) {
-                               ptes[i].changed = sgi_change_sysid(cxt, i, sys);
+                               ptes[i].changed = sgi_change_sysid(cxt, i, t->type);
                        } else {
-                               p->sys_ind = sys;
+                               p->sys_ind = t->type;
                                ptes[i].changed = 1;
                        }
-                       temp = partition_type(cxt, sys) ? : _("Unknown");
+
                        if (ptes[i].changed)
-                               printf (_("Changed system type of partition %d "
-                                       "to %x (%s)\n"), i + 1, sys, temp);
-                       else
-                               printf (_("System type of partition %d is unchanged: "
-                                       "%x (%s)\n"), i + 1, sys, temp);
-                       if (is_dos_partition(origsys) ||
-                           is_dos_partition(sys))
+                               printf (_("Changed type of partition '%s' to '%s'\n"),
+                                       org_t ? org_t->name : _("Unknown"),
+                                           t ?     t->name : _("Unknown"));
+                       else {
+nochange:
+                               printf (_("Type of partition %d is unchanged: %s\n"),
+                                       i + 1,
+                                       org_t ? org_t->name : _("Unknown"));
+                       }
+
+                       if (is_dos_partition(t->type) || is_dos_partition(t->type))
                                dos_changed = 1;
                         break;
                 }
         }
+
+       fdisk_free_parttype(t);
+       fdisk_free_parttype(org_t);
 }
 
 /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
@@ -1180,7 +1188,6 @@ fix_partition_table_order(void) {
 static void
 list_table(struct fdisk_context *cxt, int xtra) {
        struct partition *p;
-       char *type;
        int i, w;
 
        if (disklabel == SUN_LABEL) {
@@ -1225,6 +1232,8 @@ list_table(struct fdisk_context *cxt, int xtra) {
                        unsigned int psects = get_nr_sects(p);
                        unsigned int pblocks = psects;
                        unsigned int podd = 0;
+                       struct fdisk_parttype *type =
+                                       fdisk_get_parttype_from_code(cxt, p->sys_ind);
 
                        if (cxt->sector_size < 1024) {
                                pblocks /= (1024 / cxt->sector_size);
@@ -1242,8 +1251,7 @@ list_table(struct fdisk_context *cxt, int xtra) {
                                - (psects ? 1 : 0)),
 /* odd flag on end */  (unsigned long) pblocks, podd ? '+' : ' ',
 /* type id */          p->sys_ind,
-/* type name */                (type = partition_type(cxt, p->sys_ind)) ?
-                       type : _("Unknown"));
+/* type name */                type ? type->name : _("Unknown"));
                        check_consistency(cxt, p, i);
                        check_alignment(cxt, get_partition_start(pe), i);
                }
@@ -1344,7 +1352,10 @@ void print_partition_size(struct fdisk_context *cxt,
 {
        char *str = size_to_human_string(SIZE_SUFFIX_3LETTER | SIZE_SUFFIX_SPACE,
                                     (uint64_t)(stop - start + 1) * cxt->sector_size);
-       printf(_("Partition %d of type %s and of size %s is set\n"), num, partition_type(cxt, sysid), str);
+       struct fdisk_parttype *t = fdisk_get_parttype_from_code(cxt, sysid);
+
+       printf(_("Partition %d of type %s and of size %s is set\n"),
+                       num, t ? t->name : _("Unknown"), str);
        free(str);
 }
 
index 631c47fc8d8d127e1c36fabcc8c3e8bd38c255e2..03fb2c43a0a958aeecdec40bbf1fb9341c09ffaa 100644 (file)
@@ -104,10 +104,22 @@ typedef unsigned long long sector_t;
  */
 struct fdisk_parttype {
        unsigned int    type;           /* type as number or zero */
-       char            *name;          /* description */
+       const char      *name;          /* description */
        char            *typestr;       /* type as string or NULL */
+
+       unsigned int    flags;          /* FDISK_PARTTYPE_* flags */
+};
+
+enum {
+       FDISK_PARTTYPE_UNKNOWN          = (1 << 1),
+       FDISK_PARTTYPE_INVISIBLE        = (1 << 2),
+       FDISK_PARTTYPE_ALLOCATED        = (1 << 3)
 };
 
+#define fdisk_parttype_is_unknown(_x)  ((_x) && ((_x)->flags & FDISK_PARTTYPE_UNKNONW))
+#define fdisk_parttype_is_invisible(_x)        ((_x) && ((_x)->flags & FDISK_PARTTYPE_INVISIBLE))
+#define fdisk_parttype_is_allocated(_x)        ((_x) && ((_x)->flags & FDISK_PARTTYPE_ALLOCATED))
+
 /*
  * Legacy CHS based geometry
  */
@@ -148,6 +160,7 @@ struct fdisk_label {
 
        /* array with partition types */
        struct fdisk_parttype   *parttypes;
+       size_t                  nparttypes;     /* number of items in parttypes[] */
 
        /* probe disk label */
        int (*probe)(struct fdisk_context *cxt);
@@ -189,6 +202,15 @@ extern int fdisk_write_disklabel(struct fdisk_context *cxt);
 extern int fdisk_verify_disklabel(struct fdisk_context *cxt);
 extern int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name);
 
+extern size_t fdisk_get_nparttypes(struct fdisk_context *cxt);
+extern struct fdisk_parttype *fdisk_get_parttype_from_code(struct fdisk_context *cxt,
+                                unsigned int code);
+extern struct fdisk_parttype *fdisk_get_parttype_from_string(struct fdisk_context *cxt,
+                                const char *str);
+extern struct fdisk_parttype *fdisk_parse_parttype(struct fdisk_context *cxt, const char *str);
+
+extern void fdisk_free_parttype(struct fdisk_parttype *type);
+
 /* prototypes for fdisk.c */
 extern char *line_ptr;
 extern int partitions;
@@ -204,7 +226,7 @@ extern int  get_partition(struct fdisk_context *cxt, int warn, int max);
 extern void list_partition_types(struct fdisk_context *cxt);
 extern int read_line (int *asked);
 extern char read_char(char *mesg);
-extern int read_hex(struct fdisk_context *cxt);
+extern struct fdisk_parttype *read_partition_type(struct fdisk_context *cxt);
 extern void reread_partition_table(struct fdisk_context *cxt, int leave);
 extern struct partition *get_part_table(int);
 extern unsigned int read_int(struct fdisk_context *cxt,
index adcdc2f23cce3566514e5901f4ab1972650711dd..81fb682a1b79079452a64bb6ffa2d0f262b3ae3d 100644 (file)
@@ -562,9 +562,15 @@ static void
 xbsd_change_fstype (struct fdisk_context *cxt)
 {
   int i;
+  struct fdisk_parttype *t;
 
   i = xbsd_get_part_index (xbsd_dlabel.d_npartitions);
-  xbsd_dlabel.d_partitions[i].p_fstype = read_hex (cxt);
+  t = read_partition_type(cxt);
+
+  if (t) {
+    xbsd_dlabel.d_partitions[i].p_fstype = t->type;
+    fdisk_free_parttype(t);
+  }
 }
 
 static int
@@ -841,6 +847,7 @@ const struct fdisk_label bsd_label =
 {
        .name = "bsd",
        .parttypes = xbsd_fstypes,
+       .nparttypes = ARRAY_SIZE(xbsd_fstypes),
 
        .probe = osf_probe_label,
        .write = xbsd_write_disklabel,
index 9c08b98697c72f8aaaa1f6cc4058b2c33bfd60dc..e32e30c2121365e1a56ac0afaecb2f8590b59a59 100644 (file)
@@ -829,6 +829,8 @@ const struct fdisk_label dos_label =
 {
        .name = "dos",
        .parttypes = dos_parttypes,
+       .nparttypes = ARRAY_SIZE(dos_parttypes),
+
        .probe = dos_probe_label,
        .write = dos_write_disklabel,
        .verify = dos_verify_disklabel,
index d8aabd05db964c1e07e980a68b23211f03dc48bf..04bccbb3b5800991f6021c0e9ecf6ff53902d73f 100644 (file)
@@ -164,7 +164,6 @@ void
 sgi_list_table(struct fdisk_context *cxt, int xtra) {
        int i, w;
        int kpi = 0;            /* kernel partition ID */
-       char *type;
 
        w = strlen(cxt->dev_path);
 
@@ -195,6 +194,9 @@ sgi_list_table(struct fdisk_context *cxt, int xtra) {
                if (sgi_get_num_sectors(cxt, i) || debug) {
                        uint32_t start = sgi_get_start_sector(cxt, i);
                        uint32_t len = sgi_get_num_sectors(cxt, i);
+                       struct fdisk_parttype *t =
+                                       fdisk_get_parttype_from_code(cxt, sgi_get_sysid(cxt, i));
+
                        kpi++;          /* only count nonempty partitions */
                        printf(
                                "%2d: %s %4s %9ld %9ld %9ld  %2x  %s\n",
@@ -205,9 +207,8 @@ sgi_list_table(struct fdisk_context *cxt, int xtra) {
 /* start */               (long) scround(start),
 /* end */                 (long) scround(start+len)-1,
 /* no odd flag on end */  (long) len,
-/* type id */             sgi_get_sysid(cxt, i),
-/* type name */           (type = partition_type(cxt, sgi_get_sysid(cxt, i)))
-                               ? type : _("Unknown"));
+/* type id */             t ? t->type : sgi_get_sysid(cxt, i),
+/* type name */           t ? t->name : _("Unknown"));
                }
        }
        printf(_("----- Bootinfo -----\nBootfile: %s\n"
@@ -899,6 +900,7 @@ const struct fdisk_label sgi_label =
 {
        .name = "sgi",
        .parttypes = sgi_parttypes,
+       .nparttypes = ARRAY_SIZE(sgi_parttypes),
 
        .probe = sgi_probe_label,
        .write = sgi_write_disklabel,
index 7ec2d5783a71e7194a0ef5a2e4c0167b6b7df83e..acc28084243192fe2bb855d0e5f600b54a35043d 100644 (file)
@@ -538,7 +538,6 @@ int sun_change_sysid(struct fdisk_context *cxt, int i, uint16_t sys)
 void sun_list_table(struct fdisk_context *cxt, int xtra)
 {
        int i, w;
-       char *type;
 
        w = strlen(cxt->dev_path);
        if (xtra)
@@ -573,6 +572,8 @@ void sun_list_table(struct fdisk_context *cxt, int xtra)
                if (part->num_sectors) {
                        uint32_t start = SSWAP32(part->start_cylinder) * cxt->geom.heads * cxt->geom.sectors;
                        uint32_t len = SSWAP32(part->num_sectors);
+                       struct fdisk_parttype *t = fdisk_get_parttype_from_code(cxt, SSWAP16(tag->tag));
+
                        printf(
                            "%s %c%c %9lu %9lu %9lu%c  %2x  %s\n",
 /* device */             partname(cxt->dev_path, i+1, w),
@@ -582,8 +583,7 @@ void sun_list_table(struct fdisk_context *cxt, int xtra)
 /* end */                (unsigned long) scround(start+len),
 /* odd flag on end */    (unsigned long) len / 2, len & 1 ? '+' : ' ',
 /* type id */            SSWAP16(tag->tag),
-/* type name */                  (type = partition_type(cxt, SSWAP16(tag->tag)))
-                               ? type : _("Unknown"));
+/* type name */                  t ? t->name : _("Unknown"));
                }
        }
 }
@@ -653,6 +653,7 @@ const struct fdisk_label sun_label =
 {
        .name = "sun",
        .parttypes = sun_parttypes,
+       .nparttypes = ARRAY_SIZE(sun_parttypes),
 
        .probe = sun_probe_label,
        .write = sun_write_disklabel,
index 85e09c5807434a3bd363798c8e98a82d8a3da904..8e26375dcbafd490df8e718d20f54aa530fc8857 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <ctype.h>
 #ifdef HAVE_LIBBLKID
 #include <blkid.h>
 #endif
@@ -521,3 +522,134 @@ void fdisk_free_context(struct fdisk_context *cxt)
        free(cxt->firstsector);
        free(cxt);
 }
+
+/*
+ * fdisk_get_nparttypes:
+ *
+ * Returns: number of partition types supported by the current label
+ */
+size_t fdisk_get_nparttypes(struct fdisk_context *cxt)
+{
+       if (!cxt || !cxt->label)
+               return 0;
+
+       return cxt->label->nparttypes;
+}
+struct fdisk_parttype *fdisk_get_parttype_from_code(
+                               struct fdisk_context *cxt,
+                               unsigned int code)
+{
+       size_t i;
+
+       if (!fdisk_get_nparttypes(cxt))
+               return NULL;
+
+       for (i = 0; i < cxt->label->nparttypes; i++)
+               if (cxt->label->parttypes[i].type == code)
+                       return &cxt->label->parttypes[i];
+
+       return NULL;
+}
+
+struct fdisk_parttype *fdisk_get_parttype_from_string(
+                               struct fdisk_context *cxt,
+                               const char *str)
+{
+       size_t i;
+
+       if (!fdisk_get_nparttypes(cxt))
+               return NULL;
+
+       for (i = 0; i < cxt->label->nparttypes; i++)
+               if (cxt->label->parttypes[i].typestr
+                   &&strcasecmp(cxt->label->parttypes[i].typestr, str) == 0)
+                       return &cxt->label->parttypes[i];
+
+       return NULL;
+}
+
+static struct fdisk_parttype *mk_unknown_partype(unsigned int type, const char *typestr)
+{
+       struct fdisk_parttype *t;
+
+       t = calloc(1, sizeof(*t));
+       if (!t)
+               return NULL;
+
+       if (typestr) {
+               t->typestr = strdup(typestr);
+               if (!t->typestr) {
+                       free(t);
+                       return NULL;
+               }
+       }
+       t->name = _("unknown");
+       t->type = type;
+       t->flags |= FDISK_PARTTYPE_UNKNOWN | FDISK_PARTTYPE_ALLOCATED;
+
+       return t;
+}
+
+/*
+ * fdisk_parse_parttype
+ * @cxt: fdisk context
+ * @str: string
+ *
+ * Returns pointer to static table of the partition types, or newly allocated
+ * partition type if @unknown is not NULL and partition type in @str is
+ * unknown, or NULL in case of error.
+ */
+struct fdisk_parttype *fdisk_parse_parttype(
+                               struct fdisk_context *cxt,
+                               const char *str)
+{
+       struct fdisk_parttype *types, *ret;
+       unsigned int code = 0;
+       char *typestr = NULL, *end = NULL;
+
+       if (!fdisk_get_nparttypes(cxt))
+               return NULL;
+
+       types = cxt->label->parttypes;
+
+       if (types[0].typestr == NULL && isxdigit(*str)) {
+
+               errno = 0;
+               code = strtol(str, &end, 16);
+
+               if (errno || *end != '\0')
+                       return NULL;
+
+               ret = fdisk_get_parttype_from_code(cxt, code);
+               if (ret)
+                       return ret;
+       } else {
+               int i;
+
+               /* maybe specified by type string (e.g. UUID) */
+               ret = fdisk_get_parttype_from_string(cxt, str);
+               if (ret)
+                       return ret;
+
+               /* maybe specified by order number */
+               errno = 0;
+               i = strtol(str, &end, 0);
+               if (errno == 0 && *end == '\0' && i < (int) fdisk_get_nparttypes(cxt))
+                       return &types[i];
+       }
+
+       return mk_unknown_partype(code, typestr);
+}
+
+/*
+ * fdisk_free_parttype:
+ *
+ * Free the @type.
+ */
+void fdisk_free_parttype(struct fdisk_parttype *t)
+{
+       if (t && (t->flags & FDISK_PARTTYPE_ALLOCATED)) {
+               free(t->typestr);
+               free(t);
+       }
+}