From 559d921edad8be1ec4e2837095b327eb9e297b7a Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 25 Sep 2012 10:23:36 +0200 Subject: [PATCH] fdisk: add new functions for work with fdisk_parttype - 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 --- fdisks/fdisk.c | 127 +++++++++++++++++++++------------------ fdisks/fdisk.h | 26 +++++++- fdisks/fdiskbsdlabel.c | 9 ++- fdisks/fdiskdoslabel.c | 2 + fdisks/fdisksgilabel.c | 10 ++-- fdisks/fdisksunlabel.c | 7 ++- fdisks/utils.c | 132 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 245 insertions(+), 68 deletions(-) diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c index b7e350f75..12ddf54b5 100644 --- a/fdisks/fdisk.c +++ b/fdisks/fdisk.c @@ -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; + if (!cxt || !cxt->label || !cxt->label->nparttypes) + return NULL; - 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; - } - } + 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); } diff --git a/fdisks/fdisk.h b/fdisks/fdisk.h index 631c47fc8..03fb2c43a 100644 --- a/fdisks/fdisk.h +++ b/fdisks/fdisk.h @@ -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, diff --git a/fdisks/fdiskbsdlabel.c b/fdisks/fdiskbsdlabel.c index adcdc2f23..81fb682a1 100644 --- a/fdisks/fdiskbsdlabel.c +++ b/fdisks/fdiskbsdlabel.c @@ -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, diff --git a/fdisks/fdiskdoslabel.c b/fdisks/fdiskdoslabel.c index 9c08b9869..e32e30c21 100644 --- a/fdisks/fdiskdoslabel.c +++ b/fdisks/fdiskdoslabel.c @@ -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, diff --git a/fdisks/fdisksgilabel.c b/fdisks/fdisksgilabel.c index d8aabd05d..04bccbb3b 100644 --- a/fdisks/fdisksgilabel.c +++ b/fdisks/fdisksgilabel.c @@ -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, diff --git a/fdisks/fdisksunlabel.c b/fdisks/fdisksunlabel.c index 7ec2d5783..acc280842 100644 --- a/fdisks/fdisksunlabel.c +++ b/fdisks/fdisksunlabel.c @@ -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, diff --git a/fdisks/utils.c b/fdisks/utils.c index 85e09c580..8e26375dc 100644 --- a/fdisks/utils.c +++ b/fdisks/utils.c @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef HAVE_LIBBLKID #include #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); + } +}