summaryrefslogtreecommitdiffstats
path: root/libfdisk/src/parttype.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfdisk/src/parttype.c')
-rw-r--r--libfdisk/src/parttype.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/libfdisk/src/parttype.c b/libfdisk/src/parttype.c
new file mode 100644
index 0000000..271b671
--- /dev/null
+++ b/libfdisk/src/parttype.c
@@ -0,0 +1,569 @@
+
+#include <ctype.h>
+
+#include "fdiskP.h"
+#include "strutils.h"
+
+/**
+ * SECTION: parttype
+ * @title: Partition types
+ * @short_description: abstraction to partition types
+ *
+ * There are two basic types of parttypes, string based (e.g. GPT)
+ * and code/hex based (e.g. MBR).
+ */
+
+/**
+ * fdisk_new_parttype:
+ *
+ * It's recommended to use fdisk_label_get_parttype_from_code() or
+ * fdisk_label_get_parttype_from_string() for well known types rather
+ * than allocate a new instance.
+ *
+ * Returns: new instance.
+ */
+struct fdisk_parttype *fdisk_new_parttype(void)
+{
+ struct fdisk_parttype *t = calloc(1, sizeof(*t));
+
+ if (!t)
+ return NULL;
+
+ t->refcount = 1;
+ t->flags = FDISK_PARTTYPE_ALLOCATED;
+ DBG(PARTTYPE, ul_debugobj(t, "alloc"));
+ return t;
+}
+
+/**
+ * fdisk_ref_parttype:
+ * @t: partition type
+ *
+ * Increments reference counter for allocated types
+ */
+void fdisk_ref_parttype(struct fdisk_parttype *t)
+{
+ if (fdisk_parttype_is_allocated(t))
+ t->refcount++;
+}
+
+/**
+ * fdisk_unref_parttype
+ * @t: partition pointer
+ *
+ * Decrements reference counter, on zero the @t is automatically
+ * deallocated.
+ */
+void fdisk_unref_parttype(struct fdisk_parttype *t)
+{
+ if (!fdisk_parttype_is_allocated(t))
+ return;
+
+ t->refcount--;
+ if (t->refcount <= 0) {
+ DBG(PARTTYPE, ul_debugobj(t, "free"));
+ free(t->typestr);
+ free(t->name);
+ free(t);
+ }
+}
+
+/**
+ * fdisk_parttype_set_name:
+ * @t: partition type
+ * @str: type name
+ *
+ * Sets type name to allocated partition type, for static types
+ * it returns -EINVAL.
+ *
+ * Return: 0 on success, <0 on error
+ */
+int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str)
+{
+ if (!t || !fdisk_parttype_is_allocated(t))
+ return -EINVAL;
+ return strdup_to_struct_member(t, name, str);
+}
+
+/**
+ * fdisk_parttype_set_typestr:
+ * @t: partition type
+ * @str: type identifier (e.g. GUID for GPT)
+ *
+ * Sets type string to allocated partition type, for static types
+ * it returns -EINVAL. Don't use this function for MBR, see
+ * fdisk_parttype_set_code().
+ *
+ * Return: 0 on success, <0 on error
+ */
+int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str)
+{
+ if (!t || !fdisk_parttype_is_allocated(t))
+ return -EINVAL;
+ return strdup_to_struct_member(t, typestr, str);
+}
+
+/**
+ * fdisk_parttype_set_code:
+ * @t: partition type
+ * @code: type identifier (e.g. MBR type codes)
+ *
+ * Sets type code to allocated partition type, for static types it returns
+ * -EINVAL. Don't use this function for GPT, see fdisk_parttype_set_typestr().
+ *
+ * Return: 0 on success, <0 on error
+ */
+int fdisk_parttype_set_code(struct fdisk_parttype *t, int code)
+{
+ if (!t || !fdisk_parttype_is_allocated(t))
+ return -EINVAL;
+ t->code = code;
+ return 0;
+}
+
+/**
+ * fdisk_label_get_nparttypes:
+ * @lb: label
+ *
+ * Returns: number of types supported by label.
+ */
+size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb)
+{
+ if (!lb)
+ return 0;
+ return lb->nparttypes;
+}
+
+/**
+ * fdisk_label_get_parttype:
+ * @lb: label
+ * @n: number
+ *
+ * Returns: return parttype
+ */
+struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n)
+{
+ if (!lb || n >= lb->nparttypes)
+ return NULL;
+ 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: 2.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
+ *
+ * Returns: 1 if the label uses code as partition type
+ * identifiers (e.g. MBR) or 0.
+ */
+int fdisk_label_has_code_parttypes(const struct fdisk_label *lb)
+{
+ assert(lb);
+
+ if (lb->parttypes && lb->parttypes[0].typestr)
+ return 0;
+ 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:
+ * @lb: label
+ * @code: code to search for
+ *
+ * Search for partition type in label-specific table. The result
+ * is pointer to static array of label types.
+ *
+ * Returns: partition type or NULL upon failure or invalid @code.
+ */
+struct fdisk_parttype *fdisk_label_get_parttype_from_code(
+ const struct fdisk_label *lb,
+ unsigned int code)
+{
+ size_t i;
+
+ assert(lb);
+
+ if (!lb->nparttypes)
+ return NULL;
+
+ for (i = 0; i < lb->nparttypes; i++)
+ if (lb->parttypes[i].code == code)
+ return &lb->parttypes[i];
+ return NULL;
+}
+
+/**
+ * fdisk_label_get_parttype_from_string:
+ * @lb: label
+ * @str: string to search for
+ *
+ * Search for partition type in label-specific table. The result
+ * is pointer to static array of label types.
+ *
+ * Returns: partition type or NULL upon failure or invalid @str.
+ */
+struct fdisk_parttype *fdisk_label_get_parttype_from_string(
+ const struct fdisk_label *lb,
+ const char *str)
+{
+ size_t i;
+
+ assert(lb);
+
+ if (!lb->nparttypes)
+ return NULL;
+
+ for (i = 0; i < lb->nparttypes; i++)
+ if (lb->parttypes[i].typestr
+ && strcasecmp(lb->parttypes[i].typestr, str) == 0)
+ return &lb->parttypes[i];
+
+ return NULL;
+}
+
+/**
+ * fdisk_new_unknown_parttype:
+ * @code: type as number
+ * @typestr: type as string
+
+ * Allocates new 'unknown' partition type. Use fdisk_unref_parttype() to
+ * deallocate.
+ *
+ * Returns: newly allocated partition type, or NULL upon failure.
+ */
+struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
+ const char *typestr)
+{
+ struct fdisk_parttype *t = fdisk_new_parttype();
+
+ if (!t)
+ return NULL;
+
+ fdisk_parttype_set_name(t, _("unknown"));
+ fdisk_parttype_set_code(t, code);
+ fdisk_parttype_set_typestr(t, typestr);
+ t->flags |= FDISK_PARTTYPE_UNKNOWN;
+
+ return t;
+}
+
+/**
+ * fdisk_copy_parttype:
+ * @type: type to copy
+ *
+ * Use fdisk_unref_parttype() to deallocate.
+ *
+ * Returns: newly allocated partition type, or NULL upon failure.
+ */
+struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type)
+{
+ struct fdisk_parttype *t = fdisk_new_parttype();
+
+ if (!t)
+ return NULL;
+
+ fdisk_parttype_set_name(t, type->name);
+ fdisk_parttype_set_code(t, type->code);
+ fdisk_parttype_set_typestr(t, type->typestr);
+
+ 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;
+}
+
+static struct fdisk_parttype *parttype_from_name(
+ const struct fdisk_label *lb,
+ const char *str)
+{
+ size_t i;
+
+ DBG(LABEL, ul_debugobj(lb, " parsing '%s' name", str));
+
+ for (i = 0; i < lb->nparttypes; i++) {
+ const char *name = lb->parttypes[i].name;
+
+ if (name && *name && ul_stralnumcmp(name, str) == 0)
+ return &lb->parttypes[i];
+ }
+
+ 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 || !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_NAME))
+ res = parttype_from_name(lb, str);
+
+ 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 (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)
+{
+ return fdisk_label_advparse_parttype(lb, str, FDISK_PARTTYPE_PARSE_DATA);
+}
+
+/**
+ * fdisk_parttype_get_string:
+ * @t: type
+ *
+ * Returns: partition type string (e.g. GUID for GPT)
+ */
+const char *fdisk_parttype_get_string(const struct fdisk_parttype *t)
+{
+ assert(t);
+ return t->typestr && *t->typestr ? t->typestr : NULL;
+}
+
+/**
+ * fdisk_parttype_get_code:
+ * @t: type
+ *
+ * Returns: partition type code (e.g. for MBR)
+ */
+unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t)
+{
+ assert(t);
+ return t->code;
+}
+
+/**
+ * fdisk_parttype_get_name:
+ * @t: type
+ *
+ * Returns: partition type human readable name
+ */
+const char *fdisk_parttype_get_name(const struct fdisk_parttype *t)
+{
+ assert(t);
+ return t->name;
+}
+
+/**
+ * fdisk_parttype_is_unknown:
+ * @t: type
+ *
+ * Checks for example result from fdisk_label_parse_parttype().
+ *
+ * Returns: 1 is type is "unknown" or 0.
+ */
+int fdisk_parttype_is_unknown(const struct fdisk_parttype *t)
+{
+ return t && (t->flags & FDISK_PARTTYPE_UNKNOWN) ? 1 : 0;
+}