libfdisk: add partition type aliases and shortcuts

Now, the type shortcuts are supported for sfdisk scripts only.

Unfortunately, the current implementation is not generic enough
and it's also fragile as 'E' shortcut is in collision with 0x0E
type for MBR. The another issue is 'L' which makes shortcuts useless
for fdisk where 'L' is used for another purpose in dialogs.

This patch introduces partition type aliases as extension to
shortcuts. The definition of the shortcut is part of the label
definition and it's not more hardcoded in sfdisk script code.

This patch also introduces 'Ex' shortcut as replacement for (now
deprecated) 'E'.

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2020-03-03 15:59:49 +01:00
parent 91b636b565
commit f94e753b35
7 changed files with 307 additions and 140 deletions

View File

@ -70,6 +70,18 @@ static struct fdisk_parttype dos_parttypes[] = {
#include "pt-mbr-partnames.h"
};
static const struct fdisk_shortcut dos_parttype_cuts[] =
{
{ .shortcut = "L", .alias = "linux", .data = "83" },
{ .shortcut = "S", .alias = "swap", .data = "82" },
{ .shortcut = "E", .alias = "extended", .data = "05", .deprecated = 1 }, /* collision with 0x0e type */
{ .shortcut = "Ex",.alias = "extended", .data = "05" }, /* MBR extended */
{ .shortcut = "U", .alias = "uefi", .data = "EF" }, /* UEFI system */
{ .shortcut = "R", .alias = "raid", .data = "FD" }, /* Linux RAID */
{ .shortcut = "V", .alias = "lvm", .data = "8E" }, /* LVM */
{ .shortcut = "X", .alias = "linuxex", .data = "85" } /* Linux extended */
};
#define set_hsc(h,s,c,sector) { \
s = sector % cxt->geom.sectors + 1; \
sector /= cxt->geom.sectors; \
@ -2556,8 +2568,12 @@ struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt __attribute__
lb->name = "dos";
lb->id = FDISK_DISKLABEL_DOS;
lb->op = &dos_operations;
lb->parttypes = dos_parttypes;
lb->nparttypes = ARRAY_SIZE(dos_parttypes) - 1;
lb->parttype_cuts = dos_parttype_cuts;
lb->nparttype_cuts = ARRAY_SIZE(dos_parttype_cuts);
lb->fields = dos_fields;
lb->nfields = ARRAY_SIZE(dos_fields);

View File

@ -123,6 +123,17 @@ enum {
#define fdisk_parttype_is_invisible(_x) ((_x) && ((_x)->flags & FDISK_PARTTYPE_INVISIBLE))
#define fdisk_parttype_is_allocated(_x) ((_x) && ((_x)->flags & FDISK_PARTTYPE_ALLOCATED))
/*
* Shortcut (used for partition types)
*/
struct fdisk_shortcut {
const char *shortcut; /* shortcut, usually one letter (e.h. "H") */
const char *alias; /* human readable alias (e.g. "home") */
const char *data; /* for example partition type */
unsigned int deprecated : 1;
};
struct fdisk_partition {
int refcount; /* reference counter */
@ -278,6 +289,9 @@ struct fdisk_label {
struct fdisk_parttype *parttypes; /* supported partitions types */
size_t nparttypes; /* number of items in parttypes[] */
const struct fdisk_shortcut *parttype_cuts; /* partition type shortcuts */
size_t nparttype_cuts; /* number of items in parttype_cuts */
size_t nparts_max; /* maximal number of partitions */
size_t nparts_cur; /* number of currently used partitions */
@ -519,4 +533,7 @@ int fdisk_do_wipe(struct fdisk_context *cxt);
int fdisk_has_wipe_area(struct fdisk_context *cxt, uint64_t start, uint64_t size);
int fdisk_check_collisions(struct fdisk_context *cxt);
/* parttype.c */
const char *fdisk_label_translate_type_shortcut(const struct fdisk_label *lb, char *cut);
#endif /* _LIBFDISK_PRIVATE_H */

View File

@ -156,6 +156,16 @@ static struct fdisk_parttype gpt_parttypes[] =
#include "pt-gpt-partnames.h"
};
static const struct fdisk_shortcut gpt_parttype_cuts[] =
{
{ .shortcut = "L", .alias = "linux", .data = "0FC63DAF-8483-4772-8E79-3D69D8477DE4" }, /* Linux */
{ .shortcut = "S", .alias = "swap", .data = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F" }, /* Swap */
{ .shortcut = "H", .alias = "home", .data = "933AC7E1-2EB4-4F13-B844-0E14E2AEF915" }, /* Home */
{ .shortcut = "U", .alias = "uefi", .data = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" }, /* UEFI system */
{ .shortcut = "R", .alias = "raid", .data = "A19D880F-05FC-4D3B-A006-743F0F84911E" }, /* Linux RAID */
{ .shortcut = "V", .alias = "lvm", .data = "E6D6D379-F507-44C2-A23C-238F2A3DF928" } /* LVM */
};
#define alignment_required(_x) ((_x)->grain != (_x)->sector_size)
/* gpt_entry macros */
@ -3134,8 +3144,11 @@ struct fdisk_label *fdisk_new_gpt_label(struct fdisk_context *cxt __attribute__
lb->name = "gpt";
lb->id = FDISK_DISKLABEL_GPT;
lb->op = &gpt_operations;
lb->parttypes = gpt_parttypes;
lb->nparttypes = ARRAY_SIZE(gpt_parttypes);
lb->parttype_cuts = gpt_parttype_cuts;
lb->nparttype_cuts = ARRAY_SIZE(gpt_parttype_cuts);
lb->fields = gpt_fields;
lb->nfields = ARRAY_SIZE(gpt_fields);

View File

@ -264,7 +264,13 @@ int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str);
int fdisk_parttype_set_code(struct fdisk_parttype *t, int code);
size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb);
struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n);
int fdisk_label_get_parttype_shortcut(
const struct fdisk_label *lb, size_t n,
const char **typestr,
const char **shortcut,
const char **alias);
int fdisk_label_has_code_parttypes(const struct fdisk_label *lb);
int fdisk_label_has_parttypes_shortcuts(const struct fdisk_label *lb);
struct fdisk_parttype *fdisk_label_get_parttype_from_code(
const struct fdisk_label *lb,
unsigned int code);
@ -277,6 +283,36 @@ struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type);
struct fdisk_parttype *fdisk_label_parse_parttype(
const struct fdisk_label *lb,
const char *str);
struct fdisk_parttype *fdisk_label_advparse_parttype(
const struct fdisk_label *lb,
const char *str,
int flags);
/**
* fdisk_parttype_parser_flags:
* @FDISK_PARTTYPE_PARSE_DATA: parse hex or UUID from string
* @FDISK_PARTTYPE_PARSE_DATALAST: try hex or UUID as the last possibility (don't use!)
* @FDISK_PARTTYPE_PARSE_SHORTCUT: try input interpret as type shortcut (e.g 'L' for linux partition)
* @FDISK_PARTTYPE_PARSE_ALIAS: try input interpret as type alias (e.g. 'linux' for linux partition)
* @FDISK_PARTTYPE_PARSE_DEPRECATED: accept also deprecated aliases and shortcuts
* @FDISK_PARTTYPE_PARSE_DEFAULT: recommended flags for new code
* @FDISK_PARTTYPE_PARSE_NOUNKNOWN: ignore unknown types
*/
enum fdisk_parttype_parser_flags {
FDISK_PARTTYPE_PARSE_DATA = (1 << 1),
FDISK_PARTTYPE_PARSE_DATALAST = (1 << 2),
FDISK_PARTTYPE_PARSE_SHORTCUT = (1 << 3),
FDISK_PARTTYPE_PARSE_ALIAS = (1 << 4),
FDISK_PARTTYPE_PARSE_DEPRECATED = (1 << 5),
FDISK_PARTTYPE_PARSE_NOUNKNOWN = (1 << 6),
FDISK_PARTTYPE_PARSE_SEQNUM = (1 << 7),
FDISK_PARTTYPE_PARSE_DEFAULT = (FDISK_PARTTYPE_PARSE_DATA | \
FDISK_PARTTYPE_PARSE_SHORTCUT | \
FDISK_PARTTYPE_PARSE_ALIAS | \
FDISK_PARTTYPE_PARSE_SEQNUM )
};
const char *fdisk_parttype_get_string(const struct fdisk_parttype *t);
unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t);
const char *fdisk_parttype_get_name(const struct fdisk_parttype *t);

View File

@ -312,4 +312,7 @@ FDISK_2.36 {
fdisk_set_disklabel_id_from_string;
fdisk_gpt_disable_relocation;
fdisk_gpt_enable_minimize;
fdisk_label_has_parttypes_shortcuts;
fdisk_label_advparse_parttype;
fdisk_label_get_parttype_shortcut;
} FDISK_2.35;

View File

@ -145,6 +145,41 @@ struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, si
return &lb->parttypes[n];
}
/**
* fdisk_label_get_parttype_shortcut:
* @lb: label
* @n: number
* @typestr: returns type as string
* @shortcut: returns type shortcut string
* @alias: returns type alias string
*
* Returns: return 0 on success, <0 on error, 2 for deprecated alias, 1 for @n out of range
*
* Since: v2.36
*/
int fdisk_label_get_parttype_shortcut(const struct fdisk_label *lb, size_t n,
const char **typestr, const char **shortcut, const char **alias)
{
const struct fdisk_shortcut *sc;
if (!lb)
return -EINVAL;
if (n >= lb->nparttype_cuts)
return 1;
sc = &lb->parttype_cuts[n];
if (typestr)
*typestr = sc->data;
if (shortcut)
*shortcut = sc->shortcut;
if (alias)
*alias = sc->alias;
return sc->deprecated == 1 ? 2 : 0;
}
/**
* fdisk_label_has_code_parttypes:
* @lb: label
@ -161,6 +196,20 @@ int fdisk_label_has_code_parttypes(const struct fdisk_label *lb)
return 1;
}
/**
* fdisk_label_has_parttypes_shortcuts
* @lb: label
*
* Returns: 1 if the label support shortuts/aliases for partition types or 0.
*
* Since: 2.36
*/
int fdisk_label_has_parttypes_shortcuts(const struct fdisk_label *lb)
{
assert(lb);
return lb->nparttype_cuts ? 1 : 0;
}
/**
* fdisk_label_get_parttype_from_code:
@ -266,77 +315,184 @@ struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type)
return t;
}
static struct fdisk_parttype *parttype_from_data(
const struct fdisk_label *lb,
const char *str,
unsigned int *xcode,
int use_seqnum)
{
struct fdisk_parttype *types, *ret = NULL;
char *end = NULL;
assert(lb);
assert(str);
if (xcode)
*xcode = 0;
if (!lb->nparttypes)
return NULL;
DBG(LABEL, ul_debugobj(lb, " parsing '%s' data", str));
types = lb->parttypes;
if (types[0].typestr == NULL) {
unsigned int code;
DBG(LABEL, ul_debugobj(lb, " +hex"));
errno = 0;
code = strtol(str, &end, 16);
if (errno || *end != '\0') {
DBG(LABEL, ul_debugobj(lb, " failed: %m"));
return NULL;
}
if (xcode)
*xcode = code;
ret = fdisk_label_get_parttype_from_code(lb, code);
} else {
DBG(LABEL, ul_debugobj(lb, " +string"));
/* maybe specified by type string (e.g. UUID) */
ret = fdisk_label_get_parttype_from_string(lb, str);
if (!ret) {
/* maybe specified by order number */
int i;
errno = 0;
i = strtol(str, &end, 0);
if (use_seqnum && errno == 0
&& *end == '\0' && i > 0
&& i - 1 < (int) lb->nparttypes)
ret = &types[i - 1];
}
}
if (ret)
DBG(PARTTYPE, ul_debugobj(ret, " result '%s'", ret->name));
return ret;
}
static struct fdisk_parttype *parttype_from_shortcut(
const struct fdisk_label *lb,
const char *str, int deprecated)
{
size_t i;
DBG(LABEL, ul_debugobj(lb, " parsing '%s' shortcut", str));
for (i = 0; i < lb->nparttype_cuts; i++) {
const struct fdisk_shortcut *sc = &lb->parttype_cuts[i];
if (sc->deprecated && !deprecated)
continue;
if (sc->shortcut && strcmp(sc->shortcut, str) == 0)
return parttype_from_data(lb, sc->data, NULL, 0);
}
return NULL;
}
static struct fdisk_parttype *parttype_from_alias(
const struct fdisk_label *lb,
const char *str, int deprecated)
{
size_t i;
DBG(LABEL, ul_debugobj(lb, " parsing '%s' alias", str));
for (i = 0; i < lb->nparttype_cuts; i++) {
const struct fdisk_shortcut *sc = &lb->parttype_cuts[i];
if (sc->deprecated && !deprecated)
continue;
if (sc->alias && strcmp(sc->alias, str) == 0)
return parttype_from_data(lb, sc->data, NULL, 0);
}
return NULL;
}
/**
* fdisk_label_advparse_parttype:
* @lb: label
* @str: string to parse from
* @flags: FDISK_PARTTYPE_PARSE_*
*
* This function is advanced partition types parser. It parses partition type
* from @str according to the label. The function returns a pointer to static
* table of the partition types, or newly allocated partition type for unknown
* types (see fdisk_parttype_is_unknown(). It's safe to call fdisk_unref_parttype()
* for all results.
*
* The @str may be type data (hex code or UUID), alias or shortcut. For GPT
* also sequence number of the type in the list of the supported types.
*
* Returns: pointer to type or NULL on error.
*/
struct fdisk_parttype *fdisk_label_advparse_parttype(
const struct fdisk_label *lb,
const char *str,
int flags)
{
struct fdisk_parttype *res = NULL;
unsigned int code = 0;
if (!lb->nparttypes)
return NULL;
DBG(LABEL, ul_debugobj(lb, "parsing '%s' (%s) type", str, lb->name));
if ((flags & FDISK_PARTTYPE_PARSE_DATA)
&& !(flags & FDISK_PARTTYPE_PARSE_DATALAST))
res = parttype_from_data(lb, str, &code,
flags & FDISK_PARTTYPE_PARSE_SEQNUM);
if (!res && (flags & FDISK_PARTTYPE_PARSE_ALIAS))
res = parttype_from_alias(lb, str,
flags & FDISK_PARTTYPE_PARSE_DEPRECATED);
if (!res && (flags & FDISK_PARTTYPE_PARSE_SHORTCUT))
res = parttype_from_shortcut(lb, str,
flags & FDISK_PARTTYPE_PARSE_DEPRECATED);
if (!res && (flags & FDISK_PARTTYPE_PARSE_DATA)
&& (flags & FDISK_PARTTYPE_PARSE_DATALAST))
res = parttype_from_data(lb, str, &code,
flags & FDISK_PARTTYPE_PARSE_SEQNUM);
if (!res && !(flags & FDISK_PARTTYPE_PARSE_NOUNKNOWN)) {
if (lb->parttypes[0].typestr)
res = fdisk_new_unknown_parttype(0, str);
else
res = fdisk_new_unknown_parttype(code, NULL);
}
if (res)
DBG(PARTTYPE, ul_debugobj(res, "returns parsed '%s' [%s] partition type",
res->name, res->typestr ? : ""));
return res;
}
/**
* fdisk_label_parse_parttype:
* @lb: label
* @str: string to parse from
* @str: string to parse from (type name, UUID, etc.)
*
* Parses partition type from @str according to the label. The function returns
* a pointer to static table of the partition types, or newly allocated
* partition type for unknown types (see fdisk_parttype_is_unknown(). It's
* safe to call fdisk_unref_parttype() for all results.
*
* Note that for GPT it accepts sequence number of UUID.
*
* Returns: pointer to type or NULL on error.
*/
struct fdisk_parttype *fdisk_label_parse_parttype(
const struct fdisk_label *lb,
const char *str)
{
struct fdisk_parttype *types, *ret = NULL;
char *end = NULL;
assert(lb);
if (!lb->nparttypes)
return NULL;
DBG(LABEL, ul_debugobj(lb, "parsing '%s' (%s) partition type",
str, lb->name));
types = lb->parttypes;
if (types[0].typestr == NULL) {
unsigned int code = 0;
DBG(LABEL, ul_debugobj(lb, " parsing hex"));
errno = 0;
code = strtol(str, &end, 16);
if (errno || *end != '\0') {
DBG(LABEL, ul_debugobj(lb, "parsing failed: %m"));
return NULL;
}
ret = fdisk_label_get_parttype_from_code(lb, code);
if (ret)
goto done;
ret = fdisk_new_unknown_parttype(code, NULL);
} else {
int i;
DBG(LABEL, ul_debugobj(lb, " parsing string"));
/* maybe specified by type string (e.g. UUID) */
ret = fdisk_label_get_parttype_from_string(lb, str);
if (ret)
goto done;
/* maybe specified by order number */
errno = 0;
i = strtol(str, &end, 0);
if (errno == 0 && *end == '\0' && i > 0
&& i - 1 < (int) lb->nparttypes) {
ret = &types[i - 1];
goto done;
}
ret = fdisk_new_unknown_parttype(0, str);
}
done:
DBG(PARTTYPE, ul_debugobj(ret, "returns parsed '%s' [%s] partition type",
ret->name, ret->typestr ? : ""));
return ret;
return fdisk_label_advparse_parttype(lb, str, FDISK_PARTTYPE_PARSE_DATA);
}
/**

View File

@ -61,9 +61,6 @@ struct fdisk_script {
force_label : 1; /* label: <name> specified */
};
static struct fdisk_parttype *translate_type_shortcuts(struct fdisk_script *dp, char *str);
static void fdisk_script_free_header(struct fdisk_scriptheader *fi)
{
if (!fi)
@ -969,6 +966,11 @@ static int partno_from_devname(char *s)
return pno - 1;
}
#define FDISK_SCRIPT_PARTTYPE_PARSE_FLAGS \
(FDISK_PARTTYPE_PARSE_DATA | FDISK_PARTTYPE_PARSE_DATALAST | \
FDISK_PARTTYPE_PARSE_SHORTCUT | FDISK_PARTTYPE_PARSE_ALIAS | \
FDISK_PARTTYPE_PARSE_DEPRECATED)
/* dump format
* <device>: start=<num>, size=<num>, type=<string>, ...
*/
@ -1069,19 +1071,14 @@ static int parse_line_nameval(struct fdisk_script *dp, char *s)
if (rc)
break;
pa->type = translate_type_shortcuts(dp, type);
if (!pa->type)
pa->type = fdisk_label_parse_parttype(
script_get_label(dp), type);
pa->type = fdisk_label_advparse_parttype(script_get_label(dp),
type, FDISK_SCRIPT_PARTTYPE_PARSE_FLAGS);
free(type);
if (!pa->type) {
rc = -EINVAL;
fdisk_unref_parttype(pa->type);
pa->type = NULL;
break;
}
} else {
DBG(SCRIPT, ul_debugobj(dp, "script parse error: unknown field '%s'", p));
rc = -EINVAL;
@ -1098,71 +1095,6 @@ static int parse_line_nameval(struct fdisk_script *dp, char *s)
return rc;
}
/* original sfdisk supports partition types shortcuts like 'L' = Linux native
*/
static struct fdisk_parttype *translate_type_shortcuts(struct fdisk_script *dp, char *str)
{
struct fdisk_label *lb;
const char *type = NULL;
if (strlen(str) != 1)
return NULL;
lb = script_get_label(dp);
if (!lb)
return NULL;
if (lb->id == FDISK_DISKLABEL_DOS) {
switch (*str) {
case 'L': /* Linux */
type = "83";
break;
case 'S': /* Swap */
type = "82";
break;
case 'E': /* Dos extended */
type = "05";
break;
case 'X': /* Linux extended */
type = "85";
break;
case 'U': /* UEFI system */
type = "EF";
break;
case 'R': /* Linux RAID */
type = "FD";
break;
case 'V': /* LVM */
type = "8E";
break;
}
} else if (lb->id == FDISK_DISKLABEL_GPT) {
switch (*str) {
case 'L': /* Linux */
type = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
break;
case 'S': /* Swap */
type = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F";
break;
case 'H': /* Home */
type = "933AC7E1-2EB4-4F13-B844-0E14E2AEF915";
break;
case 'U': /* UEFI system */
type = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B";
break;
case 'R': /* Linux RAID */
type = "A19D880F-05FC-4D3B-A006-743F0F84911E";
break;
case 'V': /* LVM */
type = "E6D6D379-F507-44C2-A23C-238F2A3DF928";
break;
}
}
return type ? fdisk_label_parse_parttype(lb, type) : NULL;
}
#define TK_PLUS 1
#define TK_MINUS -1
@ -1257,18 +1189,12 @@ static int parse_line_valcommas(struct fdisk_script *dp, char *s)
if (rc)
break;
pa->type = translate_type_shortcuts(dp, str);
if (!pa->type)
pa->type = fdisk_label_parse_parttype(
script_get_label(dp), str);
pa->type = fdisk_label_advparse_parttype(script_get_label(dp),
str, FDISK_SCRIPT_PARTTYPE_PARSE_FLAGS);
free(str);
if (!pa->type) {
if (!pa->type)
rc = -EINVAL;
fdisk_unref_parttype(pa->type);
pa->type = NULL;
break;
}
break;
case ITEM_BOOTABLE:
if (*p == ',' || *p == ';')