(root)/
util-linux-2.39/
libfdisk/
src/
parttype.c
       1  
       2  #include <ctype.h>
       3  
       4  #include "fdiskP.h"
       5  #include "strutils.h"
       6  
       7  /**
       8   * SECTION: parttype
       9   * @title: Partition types
      10   * @short_description: abstraction to partition types
      11   *
      12   * There are two basic types of parttypes, string based (e.g. GPT)
      13   * and code/hex based (e.g. MBR).
      14   */
      15  
      16  /**
      17   * fdisk_new_parttype:
      18   *
      19   * It's recommended to use fdisk_label_get_parttype_from_code() or
      20   * fdisk_label_get_parttype_from_string() for well known types rather
      21   * than allocate a new instance.
      22   *
      23   * Returns: new instance.
      24   */
      25  struct fdisk_parttype *fdisk_new_parttype(void)
      26  {
      27  	struct fdisk_parttype *t = calloc(1, sizeof(*t));
      28  
      29  	if (!t)
      30  		return NULL;
      31  
      32  	t->refcount = 1;
      33  	t->flags = FDISK_PARTTYPE_ALLOCATED;
      34  	DBG(PARTTYPE, ul_debugobj(t, "alloc"));
      35  	return t;
      36  }
      37  
      38  /**
      39   * fdisk_ref_parttype:
      40   * @t: partition type
      41   *
      42   * Increments reference counter for allocated types
      43   */
      44  void fdisk_ref_parttype(struct fdisk_parttype *t)
      45  {
      46  	if (fdisk_parttype_is_allocated(t))
      47  		t->refcount++;
      48  }
      49  
      50  /**
      51   * fdisk_unref_parttype
      52   * @t: partition pointer
      53   *
      54   * Decrements reference counter, on zero the @t is automatically
      55   * deallocated.
      56   */
      57  void fdisk_unref_parttype(struct fdisk_parttype *t)
      58  {
      59  	if (!fdisk_parttype_is_allocated(t))
      60  		return;
      61  
      62  	t->refcount--;
      63  	if (t->refcount <= 0) {
      64  		DBG(PARTTYPE, ul_debugobj(t, "free"));
      65  		free(t->typestr);
      66  		free(t->name);
      67  		free(t);
      68  	}
      69  }
      70  
      71  /**
      72   * fdisk_parttype_set_name:
      73   * @t: partition type
      74   * @str: type name
      75   *
      76   * Sets type name to allocated partition type, for static types
      77   * it returns -EINVAL.
      78   *
      79   * Return: 0 on success, <0 on error
      80   */
      81  int fdisk_parttype_set_name(struct fdisk_parttype *t, const char *str)
      82  {
      83  	if (!t || !fdisk_parttype_is_allocated(t))
      84  		return -EINVAL;
      85  	return strdup_to_struct_member(t, name, str);
      86  }
      87  
      88  /**
      89   * fdisk_parttype_set_typestr:
      90   * @t: partition type
      91   * @str: type identifier (e.g. GUID for GPT)
      92   *
      93   * Sets type string to allocated partition type, for static types
      94   * it returns -EINVAL. Don't use this function for MBR, see
      95   * fdisk_parttype_set_code().
      96   *
      97   * Return: 0 on success, <0 on error
      98   */
      99  int fdisk_parttype_set_typestr(struct fdisk_parttype *t, const char *str)
     100  {
     101  	if (!t || !fdisk_parttype_is_allocated(t))
     102  		return -EINVAL;
     103  	return strdup_to_struct_member(t, typestr, str);
     104  }
     105  
     106  /**
     107   * fdisk_parttype_set_code:
     108   * @t: partition type
     109   * @code: type identifier (e.g. MBR type codes)
     110   *
     111   * Sets type code to allocated partition type, for static types it returns
     112   * -EINVAL. Don't use this function for GPT, see fdisk_parttype_set_typestr().
     113   *
     114   * Return: 0 on success, <0 on error
     115   */
     116  int fdisk_parttype_set_code(struct fdisk_parttype *t, int code)
     117  {
     118  	if (!t || !fdisk_parttype_is_allocated(t))
     119  		return -EINVAL;
     120  	t->code = code;
     121  	return 0;
     122  }
     123  
     124  /**
     125   * fdisk_label_get_nparttypes:
     126   * @lb: label
     127   *
     128   * Returns: number of types supported by label.
     129   */
     130  size_t fdisk_label_get_nparttypes(const struct fdisk_label *lb)
     131  {
     132  	if (!lb)
     133  		return 0;
     134  	return lb->nparttypes;
     135  }
     136  
     137  /**
     138   * fdisk_label_get_parttype:
     139   * @lb: label
     140   * @n: number
     141   *
     142   * Returns: return parttype
     143   */
     144  struct fdisk_parttype *fdisk_label_get_parttype(const struct fdisk_label *lb, size_t n)
     145  {
     146  	if (!lb || n >= lb->nparttypes)
     147  		return NULL;
     148  	return &lb->parttypes[n];
     149  }
     150  
     151  /**
     152   * fdisk_label_get_parttype_shortcut:
     153   * @lb: label
     154   * @n: number
     155   * @typestr: returns type as string
     156   * @shortcut: returns type shortcut string
     157   * @alias: returns type alias string
     158   *
     159   * Returns: return 0 on success, <0 on error, 2 for deprecated alias, 1 for @n out of range
     160   *
     161   * Since: 2.36
     162   */
     163  int fdisk_label_get_parttype_shortcut(const struct fdisk_label *lb, size_t n,
     164  		const char **typestr, const char **shortcut, const char **alias)
     165  {
     166  	const struct fdisk_shortcut *sc;
     167  
     168  	if (!lb)
     169  		return -EINVAL;
     170  	if (n >= lb->nparttype_cuts)
     171  		return 1;
     172  
     173  	sc = &lb->parttype_cuts[n];
     174  	if (typestr)
     175  		*typestr = sc->data;
     176  	if (shortcut)
     177  		*shortcut = sc->shortcut;
     178  	if (alias)
     179  		*alias = sc->alias;
     180  
     181  	return sc->deprecated == 1 ? 2 : 0;
     182  
     183  }
     184  
     185  
     186  /**
     187   * fdisk_label_has_code_parttypes:
     188   * @lb: label
     189   *
     190   * Returns: 1 if the label uses code as partition type
     191   *          identifiers (e.g. MBR) or 0.
     192   */
     193  int fdisk_label_has_code_parttypes(const struct fdisk_label *lb)
     194  {
     195  	assert(lb);
     196  
     197  	if (lb->parttypes && lb->parttypes[0].typestr)
     198  		return 0;
     199  	return 1;
     200  }
     201  
     202  /**
     203   * fdisk_label_has_parttypes_shortcuts
     204   * @lb: label
     205   *
     206   * Returns: 1 if the label support shortuts/aliases for partition types or 0.
     207   *
     208   * Since: 2.36
     209   */
     210  int fdisk_label_has_parttypes_shortcuts(const struct fdisk_label *lb)
     211  {
     212  	assert(lb);
     213  	return lb->nparttype_cuts ? 1 : 0;
     214  }
     215  
     216  
     217  /**
     218   * fdisk_label_get_parttype_from_code:
     219   * @lb: label
     220   * @code: code to search for
     221   *
     222   * Search for partition type in label-specific table. The result
     223   * is pointer to static array of label types.
     224   *
     225   * Returns: partition type or NULL upon failure or invalid @code.
     226   */
     227  struct fdisk_parttype *fdisk_label_get_parttype_from_code(
     228  				const struct fdisk_label *lb,
     229  				unsigned int code)
     230  {
     231  	size_t i;
     232  
     233  	assert(lb);
     234  
     235  	if (!lb->nparttypes)
     236  		return NULL;
     237  
     238  	for (i = 0; i < lb->nparttypes; i++)
     239  		if (lb->parttypes[i].code == code)
     240  			return &lb->parttypes[i];
     241  	return NULL;
     242  }
     243  
     244  /**
     245   * fdisk_label_get_parttype_from_string:
     246   * @lb: label
     247   * @str: string to search for
     248   *
     249   * Search for partition type in label-specific table. The result
     250   * is pointer to static array of label types.
     251   *
     252   * Returns: partition type or NULL upon failure or invalid @str.
     253   */
     254  struct fdisk_parttype *fdisk_label_get_parttype_from_string(
     255  				const struct fdisk_label *lb,
     256  				const char *str)
     257  {
     258  	size_t i;
     259  
     260  	assert(lb);
     261  
     262  	if (!lb->nparttypes)
     263  		return NULL;
     264  
     265  	for (i = 0; i < lb->nparttypes; i++)
     266  		if (lb->parttypes[i].typestr
     267  		    && strcasecmp(lb->parttypes[i].typestr, str) == 0)
     268  			return &lb->parttypes[i];
     269  
     270  	return NULL;
     271  }
     272  
     273  /**
     274   * fdisk_new_unknown_parttype:
     275   * @code: type as number
     276   * @typestr: type as string
     277  
     278   * Allocates new 'unknown' partition type. Use fdisk_unref_parttype() to
     279   * deallocate.
     280   *
     281   * Returns: newly allocated partition type, or NULL upon failure.
     282   */
     283  struct fdisk_parttype *fdisk_new_unknown_parttype(unsigned int code,
     284  						  const char *typestr)
     285  {
     286  	struct fdisk_parttype *t = fdisk_new_parttype();
     287  
     288  	if (!t)
     289  		return NULL;
     290  
     291  	fdisk_parttype_set_name(t, _("unknown"));
     292  	fdisk_parttype_set_code(t, code);
     293  	fdisk_parttype_set_typestr(t, typestr);
     294  	t->flags |= FDISK_PARTTYPE_UNKNOWN;
     295  
     296  	return t;
     297  }
     298  
     299  /**
     300   * fdisk_copy_parttype:
     301   * @type: type to copy
     302   *
     303   * Use fdisk_unref_parttype() to deallocate.
     304   *
     305   * Returns: newly allocated partition type, or NULL upon failure.
     306   */
     307  struct fdisk_parttype *fdisk_copy_parttype(const struct fdisk_parttype *type)
     308  {
     309  	struct fdisk_parttype *t = fdisk_new_parttype();
     310  
     311  	if (!t)
     312  		return NULL;
     313  
     314  	fdisk_parttype_set_name(t, type->name);
     315  	fdisk_parttype_set_code(t, type->code);
     316  	fdisk_parttype_set_typestr(t, type->typestr);
     317  
     318  	return t;
     319  }
     320  
     321  static struct fdisk_parttype *parttype_from_data(
     322  				const struct fdisk_label *lb,
     323  				const char *str,
     324  				unsigned int *xcode,
     325  				int use_seqnum)
     326  {
     327  	struct fdisk_parttype *types, *ret = NULL;
     328  	char *end = NULL;
     329  
     330  	assert(lb);
     331  	assert(str);
     332  
     333  	if (xcode)
     334  		*xcode = 0;
     335  	if (!lb->nparttypes)
     336  		return NULL;
     337  
     338  	DBG(LABEL, ul_debugobj(lb, " parsing '%s' data", str));
     339  	types = lb->parttypes;
     340  
     341  	if (types[0].typestr == NULL) {
     342  		unsigned int code;
     343  
     344  		DBG(LABEL, ul_debugobj(lb, " +hex"));
     345  
     346  		errno = 0;
     347  		code = strtol(str, &end, 16);
     348  
     349  		if (errno || *end != '\0') {
     350  			DBG(LABEL, ul_debugobj(lb, "  failed: %m"));
     351  			return NULL;
     352  		}
     353  		if (xcode)
     354  			*xcode = code;
     355  		ret = fdisk_label_get_parttype_from_code(lb, code);
     356  	} else {
     357  		DBG(LABEL, ul_debugobj(lb, " +string"));
     358  
     359  		/* maybe specified by type string (e.g. UUID) */
     360  		ret = fdisk_label_get_parttype_from_string(lb, str);
     361  
     362  		if (!ret) {
     363  			/* maybe specified by order number */
     364  			int i;
     365  
     366  			errno = 0;
     367  			i = strtol(str, &end, 0);
     368  
     369  			if (use_seqnum && errno == 0
     370  			    && *end == '\0' && i > 0
     371  			    && i - 1 < (int) lb->nparttypes)
     372  				ret = &types[i - 1];
     373  		}
     374  	}
     375  
     376  	if (ret)
     377  		DBG(PARTTYPE, ul_debugobj(ret, " result '%s'", ret->name));
     378  	return ret;
     379  }
     380  
     381  static struct fdisk_parttype *parttype_from_shortcut(
     382  				const struct fdisk_label *lb,
     383  				const char *str, int deprecated)
     384  {
     385  	size_t i;
     386  
     387  	DBG(LABEL, ul_debugobj(lb, " parsing '%s' shortcut", str));
     388  
     389  	for (i = 0; i < lb->nparttype_cuts; i++) {
     390  		const struct fdisk_shortcut *sc = &lb->parttype_cuts[i];
     391  
     392  		if (sc->deprecated && !deprecated)
     393  			continue;
     394  		if (sc->shortcut && strcmp(sc->shortcut, str) == 0)
     395  			return parttype_from_data(lb, sc->data, NULL, 0);
     396  	}
     397  	return NULL;
     398  }
     399  
     400  static struct fdisk_parttype *parttype_from_alias(
     401  				const struct fdisk_label *lb,
     402  				const char *str, int deprecated)
     403  {
     404  	size_t i;
     405  
     406  	DBG(LABEL, ul_debugobj(lb, " parsing '%s' alias", str));
     407  
     408  	for (i = 0; i < lb->nparttype_cuts; i++) {
     409  		const struct fdisk_shortcut *sc = &lb->parttype_cuts[i];
     410  
     411  		if (sc->deprecated && !deprecated)
     412  			continue;
     413  		if (sc->alias && strcmp(sc->alias, str) == 0)
     414  			return parttype_from_data(lb, sc->data, NULL, 0);
     415  	}
     416  	return NULL;
     417  }
     418  
     419  static struct fdisk_parttype *parttype_from_name(
     420  				const struct fdisk_label *lb,
     421  				const char *str)
     422  {
     423  	size_t i;
     424  
     425  	DBG(LABEL, ul_debugobj(lb, " parsing '%s' name", str));
     426  
     427  	for (i = 0; i < lb->nparttypes; i++) {
     428  		const char *name = lb->parttypes[i].name;
     429  
     430  		if (name && *name && ul_stralnumcmp(name, str) == 0)
     431  			return &lb->parttypes[i];
     432  	}
     433  
     434  	return NULL;
     435  }
     436  
     437  /**
     438   * fdisk_label_advparse_parttype:
     439   * @lb: label
     440   * @str: string to parse from
     441   * @flags: FDISK_PARTTYPE_PARSE_*
     442   *
     443   * This function is advanced partition types parser. It parses partition type
     444   * from @str according to the label. The function returns a pointer to static
     445   * table of the partition types, or newly allocated partition type for unknown
     446   * types (see fdisk_parttype_is_unknown(). It's safe to call fdisk_unref_parttype()
     447   * for all results.
     448   *
     449   * The @str may be type data (hex code or UUID), alias or shortcut. For GPT
     450   * also sequence number of the type in the list of the supported types.
     451   *
     452   * Returns: pointer to type or NULL on error.
     453   */
     454  struct fdisk_parttype *fdisk_label_advparse_parttype(
     455  				const struct fdisk_label *lb,
     456  				const char *str,
     457  				int flags)
     458  {
     459  	struct fdisk_parttype *res = NULL;
     460  	unsigned int code = 0;
     461  
     462  	if (!lb || !lb->nparttypes)
     463  		return NULL;
     464  
     465  	DBG(LABEL, ul_debugobj(lb, "parsing '%s' (%s) type", str, lb->name));
     466  
     467  	if ((flags & FDISK_PARTTYPE_PARSE_DATA)
     468  	    && !(flags & FDISK_PARTTYPE_PARSE_DATALAST))
     469  		res = parttype_from_data(lb, str, &code,
     470  				flags & FDISK_PARTTYPE_PARSE_SEQNUM);
     471  
     472  	if (!res && (flags & FDISK_PARTTYPE_PARSE_ALIAS))
     473  		res = parttype_from_alias(lb, str,
     474  				flags & FDISK_PARTTYPE_PARSE_DEPRECATED);
     475  
     476  	if (!res && (flags & FDISK_PARTTYPE_PARSE_SHORTCUT))
     477  		res = parttype_from_shortcut(lb, str,
     478  				flags & FDISK_PARTTYPE_PARSE_DEPRECATED);
     479  
     480  	if (!res && (flags & FDISK_PARTTYPE_PARSE_NAME))
     481  		res = parttype_from_name(lb, str);
     482  
     483  	if (!res && (flags & FDISK_PARTTYPE_PARSE_DATA)
     484  	    && (flags & FDISK_PARTTYPE_PARSE_DATALAST))
     485  		res = parttype_from_data(lb, str, &code,
     486  				flags & FDISK_PARTTYPE_PARSE_SEQNUM);
     487  
     488  	if (!res && !(flags & FDISK_PARTTYPE_PARSE_NOUNKNOWN)) {
     489  		if (lb->parttypes[0].typestr)
     490  			res = fdisk_new_unknown_parttype(0, str);
     491  		else
     492  			res = fdisk_new_unknown_parttype(code, NULL);
     493  	}
     494  
     495  	if (res)
     496  		DBG(PARTTYPE, ul_debugobj(res, "returns parsed '%s' [%s] partition type",
     497  				res->name, res->typestr ? : ""));
     498  	return res;
     499  }
     500  
     501  /**
     502   * fdisk_label_parse_parttype:
     503   * @lb: label
     504   * @str: string to parse from (type name, UUID, etc.)
     505   *
     506   * Parses partition type from @str according to the label. The function returns
     507   * a pointer to static table of the partition types, or newly allocated
     508   * partition type for unknown types (see fdisk_parttype_is_unknown(). It's
     509   * safe to call fdisk_unref_parttype() for all results.
     510   *
     511   * Note that for GPT it accepts sequence number of UUID.
     512   *
     513   * Returns: pointer to type or NULL on error.
     514   */
     515  struct fdisk_parttype *fdisk_label_parse_parttype(
     516  				const struct fdisk_label *lb,
     517  				const char *str)
     518  {
     519  	return fdisk_label_advparse_parttype(lb, str, FDISK_PARTTYPE_PARSE_DATA);
     520  }
     521  
     522  /**
     523   * fdisk_parttype_get_string:
     524   * @t: type
     525   *
     526   * Returns: partition type string (e.g. GUID for GPT)
     527   */
     528  const char *fdisk_parttype_get_string(const struct fdisk_parttype *t)
     529  {
     530  	assert(t);
     531  	return t->typestr && *t->typestr ? t->typestr : NULL;
     532  }
     533  
     534  /**
     535   * fdisk_parttype_get_code:
     536   * @t: type
     537   *
     538   * Returns: partition type code (e.g. for MBR)
     539   */
     540  unsigned int fdisk_parttype_get_code(const struct fdisk_parttype *t)
     541  {
     542  	assert(t);
     543  	return t->code;
     544  }
     545  
     546  /**
     547   * fdisk_parttype_get_name:
     548   * @t: type
     549   *
     550   * Returns: partition type human readable name
     551   */
     552  const char *fdisk_parttype_get_name(const struct fdisk_parttype *t)
     553  {
     554  	assert(t);
     555  	return t->name;
     556  }
     557  
     558  /**
     559   * fdisk_parttype_is_unknown:
     560   * @t: type
     561   *
     562   * Checks for example result from fdisk_label_parse_parttype().
     563   *
     564   * Returns: 1 is type is "unknown" or 0.
     565   */
     566  int fdisk_parttype_is_unknown(const struct fdisk_parttype *t)
     567  {
     568  	return t && (t->flags & FDISK_PARTTYPE_UNKNOWN) ? 1 : 0;
     569  }