(root)/
util-linux-2.39/
libblkid/
src/
partitions/
partitions.c
       1  /*
       2   * partitions - partition tables parsing
       3   *
       4   * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
       5   *
       6   * This file may be redistributed under the terms of the
       7   * GNU Lesser General Public License.
       8   *
       9   */
      10  #include <stdio.h>
      11  #include <string.h>
      12  #include <stdlib.h>
      13  #include <unistd.h>
      14  #include <fcntl.h>
      15  #include <ctype.h>
      16  #include <sys/types.h>
      17  #include <sys/stat.h>
      18  #include <errno.h>
      19  #include <stdint.h>
      20  #include <inttypes.h>
      21  #include <stdarg.h>
      22  
      23  #include "partitions.h"
      24  #include "sysfs.h"
      25  #include "strutils.h"
      26  
      27  /**
      28   * SECTION: partitions
      29   * @title: Partitions probing
      30   * @short_description: partitions tables detection and parsing
      31   *
      32   * This chain supports binary and NAME=value interfaces, but complete PT
      33   * description is provided by binary interface only. The libblkid prober is
      34   * compatible with kernel partition tables parser. The parser does not return
      35   * empty (size=0) partitions or special hidden partitions.
      36   *
      37   * NAME=value interface, supported tags:
      38   *
      39   * @PTTYPE: partition table type (dos, gpt, etc.).
      40   *
      41   * @PTUUID: partition table id (uuid for gpt, hex for dos).
      42  
      43   * @PART_ENTRY_SCHEME: partition table type
      44   *
      45   * @PART_ENTRY_NAME: partition name (gpt and mac only)
      46   *
      47   * @PART_ENTRY_UUID: partition UUID (gpt, or pseudo IDs for MBR)
      48   *
      49   * @PART_ENTRY_TYPE: partition type, 0xNN (e.g. 0x82) or type UUID (gpt only) or type string (mac)
      50   *
      51   * @PART_ENTRY_FLAGS: partition flags (e.g. boot_ind) or  attributes (e.g. gpt attributes)
      52   *
      53   * @PART_ENTRY_NUMBER: partition number
      54   *
      55   * @PART_ENTRY_OFFSET: the begin of the partition
      56   *
      57   * @PART_ENTRY_SIZE: size of the partition
      58   *
      59   * @PART_ENTRY_DISK: whole-disk maj:min
      60   *
      61   * Example:
      62   *
      63   * <informalexample>
      64   *  <programlisting>
      65   * blkid_probe pr;
      66   * const char *ptname;
      67   *
      68   * pr = blkid_new_probe_from_filename(devname);
      69   * if (!pr)
      70   *	err("%s: failed to open device", devname);
      71   *
      72   * blkid_probe_enable_partitions(pr, TRUE);
      73   * blkid_do_fullprobe(pr);
      74   *
      75   * blkid_probe_lookup_value(pr, "PTTYPE", &ptname, NULL);
      76   * printf("%s partition type detected\n", pttype);
      77   *
      78   * blkid_free_probe(pr);
      79   *
      80   * // don't forget to check return codes in your code!
      81   *  </programlisting>
      82   * </informalexample>
      83   *
      84   * Binary interface:
      85   *
      86   * <informalexample>
      87   *  <programlisting>
      88   * blkid_probe pr;
      89   * blkid_partlist ls;
      90   * int nparts, i;
      91   *
      92   * pr = blkid_new_probe_from_filename(devname);
      93   * if (!pr)
      94   *	err("%s: failed to open device", devname);
      95   *
      96   * ls = blkid_probe_get_partitions(pr);
      97   * nparts = blkid_partlist_numof_partitions(ls);
      98   *
      99   * for (i = 0; i < nparts; i++) {
     100   *      blkid_partition par = blkid_partlist_get_partition(ls, i);
     101   *      printf("#%d: %llu %llu  0x%x",
     102   *               blkid_partition_get_partno(par),
     103   *               blkid_partition_get_start(par),
     104   *               blkid_partition_get_size(par),
     105   *               blkid_partition_get_type(par));
     106   * }
     107   *
     108   * blkid_free_probe(pr);
     109   *
     110   * // don't forget to check return codes in your code!
     111   *  </programlisting>
     112   * </informalexample>
     113   */
     114  
     115  /*
     116   * Chain driver function
     117   */
     118  static int partitions_probe(blkid_probe pr, struct blkid_chain *chn);
     119  static void partitions_free_data(blkid_probe pr, void *data);
     120  
     121  /*
     122   * Partitions chain probing functions
     123   */
     124  static const struct blkid_idinfo *idinfos[] =
     125  {
     126  	&aix_pt_idinfo,
     127  	&sgi_pt_idinfo,
     128  	&sun_pt_idinfo,
     129  	&dos_pt_idinfo,
     130  	&gpt_pt_idinfo,
     131  	&pmbr_pt_idinfo,	/* always after GPT */
     132  	&mac_pt_idinfo,
     133  	&ultrix_pt_idinfo,
     134  	&bsd_pt_idinfo,
     135  	&unixware_pt_idinfo,
     136  	&solaris_x86_pt_idinfo,
     137  	&minix_pt_idinfo,
     138  	&atari_pt_idinfo
     139  };
     140  
     141  /*
     142   * Driver definition
     143   */
     144  const struct blkid_chaindrv partitions_drv = {
     145  	.id           = BLKID_CHAIN_PARTS,
     146  	.name         = "partitions",
     147  	.dflt_enabled = FALSE,
     148  	.idinfos      = idinfos,
     149  	.nidinfos     = ARRAY_SIZE(idinfos),
     150  	.has_fltr     = TRUE,
     151  	.probe        = partitions_probe,
     152  	.safeprobe    = partitions_probe,
     153  	.free_data    = partitions_free_data
     154  };
     155  
     156  
     157  /*
     158   * For compatibility with the rest of libblkid API (with the old high-level
     159   * API) we use completely opaque typedefs for all structs. Don't forget that
     160   * the final blkid_* types are pointers! See blkid.h.
     161   *
     162   * [Just for the record, I hate typedef for pointers --kzak]
     163   */
     164  
     165  /* exported as opaque type "blkid_parttable" */
     166  struct blkid_struct_parttable {
     167  	const char	*type;		/* partition table type */
     168  	uint64_t	offset;		/* begin of the partition table (in bytes) */
     169  	int		nparts;		/* number of partitions */
     170  	blkid_partition	parent;		/* parent of nested partition table */
     171  	char		id[UUID_STR_LEN]; /* PT identifier (e.g. UUID for GPT) */
     172  
     173  	struct list_head t_tabs;	/* all tables */
     174  };
     175  
     176  /* exported as opaque type "blkid_partition" */
     177  struct blkid_struct_partition {
     178  	uint64_t	start;		/* begin of the partition (512-bytes sectors) */
     179  	uint64_t	size;		/* size of the partitions (512-bytes sectors) */
     180  
     181  	int		type;		/* partition type */
     182  	char		typestr[UUID_STR_LEN]; /* partition type string (GPT and Mac) */
     183  
     184  	unsigned long long flags;	/* partition flags / attributes */
     185  
     186  	int		partno;		/* partition number */
     187  	char		uuid[UUID_STR_LEN]; /* UUID (when supported by PT), e.g. GPT */
     188  	unsigned char	name[128];	/* Partition in UTF8 name (when supported by PT), e.g. Mac */
     189  
     190  	blkid_parttable	tab;		/* partition table */
     191  };
     192  
     193  /* exported as opaque type "blkid_partlist" */
     194  struct blkid_struct_partlist {
     195  	int		next_partno;	/* next partition number */
     196  	blkid_partition next_parent;	/* next parent if parsing nested PT */
     197  
     198  	int		nparts;		/* number of partitions */
     199  	int		nparts_max;	/* max.number of partitions */
     200  	blkid_partition	parts;		/* array of partitions */
     201  
     202  	struct list_head l_tabs;	/* list of partition tables */
     203  };
     204  
     205  static int blkid_partitions_probe_partition(blkid_probe pr);
     206  
     207  /**
     208   * blkid_probe_enable_partitions:
     209   * @pr: probe
     210   * @enable: TRUE/FALSE
     211   *
     212   * Enables/disables the partitions probing for non-binary interface.
     213   *
     214   * Returns: 0 on success, or -1 in case of error.
     215   */
     216  int blkid_probe_enable_partitions(blkid_probe pr, int enable)
     217  {
     218  	pr->chains[BLKID_CHAIN_PARTS].enabled = enable;
     219  	return 0;
     220  }
     221  
     222  /**
     223   * blkid_probe_set_partitions_flags:
     224   * @pr: prober
     225   * @flags: BLKID_PARTS_* flags
     226   *
     227   * Sets probing flags to the partitions prober. This function is optional.
     228   *
     229   * Returns: 0 on success, or -1 in case of error.
     230   */
     231  int blkid_probe_set_partitions_flags(blkid_probe pr, int flags)
     232  {
     233  	pr->chains[BLKID_CHAIN_PARTS].flags = flags;
     234  	return 0;
     235  }
     236  
     237  int blkid_probe_get_partitions_flags(blkid_probe pr)
     238  {
     239  	return pr->chains[BLKID_CHAIN_PARTS].flags;
     240  }
     241  
     242  /**
     243   * blkid_probe_reset_partitions_filter:
     244   * @pr: prober
     245   *
     246   * Resets partitions probing filter
     247   *
     248   * Returns: 0 on success, or -1 in case of error.
     249   */
     250  int blkid_probe_reset_partitions_filter(blkid_probe pr)
     251  {
     252  	return __blkid_probe_reset_filter(pr, BLKID_CHAIN_PARTS);
     253  }
     254  
     255  /**
     256   * blkid_probe_invert_partitions_filter:
     257   * @pr: prober
     258   *
     259   * Inverts partitions probing filter
     260   *
     261   * Returns: 0 on success, or -1 in case of error.
     262   */
     263  int blkid_probe_invert_partitions_filter(blkid_probe pr)
     264  {
     265  	return __blkid_probe_invert_filter(pr, BLKID_CHAIN_PARTS);
     266  }
     267  
     268  /**
     269   * blkid_probe_filter_partitions_type:
     270   * @pr: prober
     271   * @flag: filter BLKID_FLTR_{NOTIN,ONLYIN} flag
     272   * @names: NULL terminated array of probing function names (e.g. "vfat").
     273   *
     274   *  %BLKID_FLTR_NOTIN  - probe for all items which are NOT IN @names
     275   *
     276   *  %BLKID_FLTR_ONLYIN - probe for items which are IN @names
     277   *
     278   * Returns: 0 on success, or -1 in case of error.
     279   */
     280  int blkid_probe_filter_partitions_type(blkid_probe pr, int flag, char *names[])
     281  {
     282  	return __blkid_probe_filter_types(pr, BLKID_CHAIN_PARTS, flag, names);
     283  }
     284  
     285  /**
     286   * blkid_probe_get_partitions:
     287   * @pr: probe
     288   *
     289   * This is a binary interface for partitions. See also blkid_partlist_*
     290   * functions.
     291   *
     292   * This function is independent on blkid_do_[safe,full]probe() and
     293   * blkid_probe_enable_partitions() calls.
     294   *
     295   * WARNING: the returned object will be overwritten by the next
     296   *          blkid_probe_get_partitions() call for the same @pr. If you want to
     297   *          use more blkid_partlist objects in the same time you have to create
     298   *          more blkid_probe handlers (see blkid_new_probe()).
     299   *
     300   * Returns: list of partitions, or NULL in case of error.
     301   */
     302  blkid_partlist blkid_probe_get_partitions(blkid_probe pr)
     303  {
     304  	return (blkid_partlist) blkid_probe_get_binary_data(pr,
     305  			&pr->chains[BLKID_CHAIN_PARTS]);
     306  }
     307  
     308  /* for internal usage only */
     309  blkid_partlist blkid_probe_get_partlist(blkid_probe pr)
     310  {
     311  	return (blkid_partlist) pr->chains[BLKID_CHAIN_PARTS].data;
     312  }
     313  
     314  static void blkid_probe_set_partlist(blkid_probe pr, blkid_partlist ls)
     315  {
     316  	pr->chains[BLKID_CHAIN_PARTS].data = ls;
     317  }
     318  
     319  static void ref_parttable(blkid_parttable tab)
     320  {
     321  	if (tab)
     322  		tab->nparts++;
     323  }
     324  
     325  static void unref_parttable(blkid_parttable tab)
     326  {
     327  	if (!tab)
     328  		return;
     329  
     330  	tab->nparts--;
     331  	if (tab->nparts <= 0) {
     332  		list_del(&tab->t_tabs);
     333  		free(tab);
     334  	}
     335  }
     336  
     337  /* free all allocated parttables */
     338  static void free_parttables(blkid_partlist ls)
     339  {
     340  	if (!ls || !ls->l_tabs.next)
     341  		return;
     342  
     343  	/* remove unassigned partition tables */
     344  	while (!list_empty(&ls->l_tabs)) {
     345  		blkid_parttable tab = list_entry(ls->l_tabs.next,
     346  					struct blkid_struct_parttable, t_tabs);
     347  		unref_parttable(tab);
     348  	}
     349  }
     350  
     351  static void reset_partlist(blkid_partlist ls)
     352  {
     353  	if (!ls)
     354  		return;
     355  
     356  	free_parttables(ls);
     357  
     358  	if (ls->next_partno) {
     359  		/* already initialized - reset */
     360  		int tmp_nparts = ls->nparts_max;
     361  		blkid_partition tmp_parts = ls->parts;
     362  
     363  		memset(ls, 0, sizeof(struct blkid_struct_partlist));
     364  
     365  		ls->nparts_max = tmp_nparts;
     366  		ls->parts = tmp_parts;
     367  	}
     368  
     369  	ls->nparts = 0;
     370  	ls->next_partno = 1;
     371  	INIT_LIST_HEAD(&ls->l_tabs);
     372  
     373  	DBG(LOWPROBE, ul_debug("partlist reset"));
     374  }
     375  
     376  static blkid_partlist partitions_init_data(struct blkid_chain *chn)
     377  {
     378  	blkid_partlist ls;
     379  
     380  	if (chn->data)
     381  		ls = (blkid_partlist) chn->data;
     382  	else {
     383  		/* allocate the new list of partitions */
     384  		ls = calloc(1, sizeof(struct blkid_struct_partlist));
     385  		if (!ls)
     386  			return NULL;
     387  		chn->data = (void *) ls;
     388  	}
     389  
     390  	reset_partlist(ls);
     391  
     392  	DBG(LOWPROBE, ul_debug("parts: initialized partitions list (size=%d)", ls->nparts_max));
     393  	return ls;
     394  }
     395  
     396  static void partitions_free_data(blkid_probe pr __attribute__((__unused__)),
     397  				 void *data)
     398  {
     399  	blkid_partlist ls = (blkid_partlist) data;
     400  
     401  	if (!ls)
     402  		return;
     403  
     404  	free_parttables(ls);
     405  
     406  	/* deallocate partitions and partlist */
     407  	free(ls->parts);
     408  	free(ls);
     409  }
     410  
     411  blkid_parttable blkid_partlist_new_parttable(blkid_partlist ls,
     412  				const char *type, uint64_t offset)
     413  {
     414  	blkid_parttable tab;
     415  
     416  	tab = calloc(1, sizeof(struct blkid_struct_parttable));
     417  	if (!tab)
     418  		return NULL;
     419  	tab->type = type;
     420  	tab->offset = offset;
     421  	tab->parent = ls->next_parent;
     422  
     423  	INIT_LIST_HEAD(&tab->t_tabs);
     424  	list_add_tail(&tab->t_tabs, &ls->l_tabs);
     425  
     426  	DBG(LOWPROBE, ul_debug("parts: create a new partition table "
     427  		       "(type=%s, offset=%"PRId64")", type, offset));
     428  	return tab;
     429  }
     430  
     431  static blkid_partition new_partition(blkid_partlist ls, blkid_parttable tab)
     432  {
     433  	blkid_partition par;
     434  
     435  	if (ls->nparts + 1 > ls->nparts_max) {
     436  		/* Linux kernel has DISK_MAX_PARTS=256, but it's too much for
     437  		 * generic Linux machine -- let start with 32 partitions.
     438  		 */
     439  		void *tmp = realloc(ls->parts, (ls->nparts_max + 32) *
     440  					sizeof(struct blkid_struct_partition));
     441  		if (!tmp)
     442  			return NULL;
     443  		ls->parts = tmp;
     444  		ls->nparts_max += 32;
     445  	}
     446  
     447  	par = &ls->parts[ls->nparts++];
     448  	memset(par, 0, sizeof(struct blkid_struct_partition));
     449  
     450  	ref_parttable(tab);
     451  	par->tab = tab;
     452  	par->partno = blkid_partlist_increment_partno(ls);
     453  
     454  	return par;
     455  }
     456  
     457  blkid_partition blkid_partlist_add_partition(blkid_partlist ls,
     458  					blkid_parttable tab, uint64_t start, uint64_t size)
     459  {
     460  	blkid_partition par = new_partition(ls, tab);
     461  
     462  	if (!par)
     463  		return NULL;
     464  
     465  	par->start = start;
     466  	par->size = size;
     467  
     468  	DBG(LOWPROBE, ul_debug("parts: add partition (start=%"
     469  		PRIu64 ", size=%" PRIu64 ")",
     470  		par->start, par->size));
     471  	return par;
     472  }
     473  
     474  /* can be used to modify used partitions numbers (for example for logical partitions) */
     475  int blkid_partlist_set_partno(blkid_partlist ls, int partno)
     476  {
     477  	if (!ls)
     478  		return -1;
     479  	ls->next_partno = partno;
     480  	return 0;
     481  }
     482  
     483  int blkid_partlist_increment_partno(blkid_partlist ls)
     484  {
     485  	return ls ? ls->next_partno++ : -1;
     486  }
     487  
     488  /* can be used to set "parent" for the next nested partition */
     489  static int blkid_partlist_set_parent(blkid_partlist ls, blkid_partition par)
     490  {
     491  	if (!ls)
     492  		return -1;
     493  	ls->next_parent = par;
     494  	return 0;
     495  }
     496  
     497  blkid_partition blkid_partlist_get_parent(blkid_partlist ls)
     498  {
     499  	if (!ls)
     500  		return NULL;
     501  	return ls->next_parent;
     502  }
     503  
     504  int blkid_partitions_need_typeonly(blkid_probe pr)
     505  {
     506  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
     507  
     508  	return chn && chn->data && chn->binary ? FALSE : TRUE;
     509  }
     510  
     511  /* get private chain flags */
     512  int blkid_partitions_get_flags(blkid_probe pr)
     513  {
     514  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
     515  
     516  	return chn ? chn->flags : 0;
     517  }
     518  
     519  /* check if @start and @size are within @par partition */
     520  int blkid_is_nested_dimension(blkid_partition par,
     521  			uint64_t start, uint64_t size)
     522  {
     523  	uint64_t pstart;
     524  	uint64_t psize;
     525  
     526  	if (!par)
     527  		return 0;
     528  
     529  	pstart = blkid_partition_get_start(par);
     530  	psize = blkid_partition_get_size(par);
     531  
     532  	if (start < pstart || start + size > pstart + psize)
     533  		return 0;
     534  
     535  	return 1;
     536  }
     537  
     538  static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id,
     539  			struct blkid_chain *chn)
     540  {
     541  	const struct blkid_idmag *mag = NULL;
     542  	uint64_t off;
     543  	int rc = BLKID_PROBE_NONE;		/* default is nothing */
     544  
     545  	if (pr->size <= 0 || (id->minsz && (unsigned)id->minsz > pr->size))
     546  		goto nothing;	/* the device is too small */
     547  	if (pr->flags & BLKID_FL_NOSCAN_DEV)
     548  		goto nothing;
     549  
     550  	rc = blkid_probe_get_idmag(pr, id, &off, &mag);
     551  	if (rc != BLKID_PROBE_OK)
     552  		goto nothing;
     553  
     554  	/* final check by probing function */
     555  	if (id->probefunc) {
     556  		DBG(LOWPROBE, ul_debug(
     557  			"%s: ---> call probefunc()", id->name));
     558  		rc = id->probefunc(pr, mag);
     559  		if (rc < 0) {
     560  			/* reset after error */
     561  			reset_partlist(blkid_probe_get_partlist(pr));
     562  			if (chn && !chn->binary)
     563  				blkid_probe_chain_reset_values(pr, chn);
     564  			DBG(LOWPROBE, ul_debug("%s probefunc failed, rc %d",
     565  						  id->name, rc));
     566  		}
     567  		if (rc == BLKID_PROBE_OK && mag && chn && !chn->binary)
     568  			rc = blkid_probe_set_magic(pr, off, mag->len,
     569  					(const unsigned char *) mag->magic);
     570  
     571  		DBG(LOWPROBE, ul_debug("%s: <--- (rc = %d)", id->name, rc));
     572  	}
     573  
     574  	return rc;
     575  
     576  nothing:
     577  	return BLKID_PROBE_NONE;
     578  }
     579  
     580  /*
     581   * The blkid_do_probe() backend.
     582   */
     583  static int partitions_probe(blkid_probe pr, struct blkid_chain *chn)
     584  {
     585  	int rc = BLKID_PROBE_NONE;
     586  	size_t i;
     587  
     588  	if (!pr || chn->idx < -1)
     589  		return -EINVAL;
     590  
     591  	blkid_probe_chain_reset_values(pr, chn);
     592  
     593  	if (pr->flags & BLKID_FL_NOSCAN_DEV)
     594  		return BLKID_PROBE_NONE;
     595  
     596  	if (chn->binary)
     597  		partitions_init_data(chn);
     598  
     599  	if (!pr->wipe_size && (pr->prob_flags & BLKID_PROBE_FL_IGNORE_PT))
     600  		goto details_only;
     601  
     602  	DBG(LOWPROBE, ul_debug("--> starting probing loop [PARTS idx=%d]",
     603  		chn->idx));
     604  
     605  	i = chn->idx < 0 ? 0 : chn->idx + 1U;
     606  
     607  	for ( ; i < ARRAY_SIZE(idinfos); i++) {
     608  		const char *name;
     609  
     610  		chn->idx = i;
     611  
     612  		/* apply filter */
     613  		if (chn->fltr && blkid_bmp_get_item(chn->fltr, i))
     614  			continue;
     615  
     616  		/* apply checks from idinfo */
     617  		rc = idinfo_probe(pr, idinfos[i], chn);
     618  		if (rc < 0)
     619  			break;
     620  		if (rc != BLKID_PROBE_OK)
     621  			continue;
     622  
     623  		name = idinfos[i]->name;
     624  
     625  		if (!chn->binary)
     626  			/*
     627  			 * Non-binary interface, set generic variables. Note
     628  			 * that the another variables could be set in prober
     629  			 * functions.
     630  			 */
     631  			blkid_probe_set_value(pr, "PTTYPE",
     632  						(const unsigned char *) name,
     633  						strlen(name) + 1);
     634  
     635  		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (type=%s) [PARTS idx=%d]",
     636  			name, chn->idx));
     637  		rc = BLKID_PROBE_OK;
     638  		break;
     639  	}
     640  
     641  	if (rc != BLKID_PROBE_OK) {
     642  		DBG(LOWPROBE, ul_debug("<-- leaving probing loop (failed=%d) [PARTS idx=%d]",
     643  			rc, chn->idx));
     644  	}
     645  
     646  details_only:
     647  	/*
     648  	 * Gather PART_ENTRY_* values if the current device is a partition.
     649  	 */
     650  	if ((rc == BLKID_PROBE_OK || rc == BLKID_PROBE_NONE) && !chn->binary &&
     651  	    (blkid_partitions_get_flags(pr) & BLKID_PARTS_ENTRY_DETAILS)) {
     652  
     653  		int xrc = blkid_partitions_probe_partition(pr);
     654  
     655  		/* partition entry probing is optional, and "not-found" from
     656  		 * this sub-probing must not to overwrite previous success. */
     657  		if (xrc < 0)
     658  			rc = xrc;			/* always propagate errors */
     659  		else if (rc == BLKID_PROBE_NONE)
     660  			rc = xrc;
     661  	}
     662  
     663  	DBG(LOWPROBE, ul_debug("partitions probe done [rc=%d]",	rc));
     664  	return rc;
     665  }
     666  
     667  /* Probe for nested partition table within the parental partition */
     668  int blkid_partitions_do_subprobe(blkid_probe pr, blkid_partition parent,
     669  		const struct blkid_idinfo *id)
     670  {
     671  	blkid_probe prc;
     672  	int rc;
     673  	blkid_partlist ls;
     674  	uint64_t sz, off;
     675  
     676  	DBG(LOWPROBE, ul_debug(
     677  		"parts: ----> %s subprobe requested)",
     678  		id->name));
     679  
     680  	if (!pr || !parent || !parent->size)
     681  		return -EINVAL;
     682  	if (pr->flags & BLKID_FL_NOSCAN_DEV)
     683  		return BLKID_PROBE_NONE;
     684  
     685  	/* range defined by parent */
     686  	sz = parent->size << 9;
     687  	off = parent->start << 9;
     688  
     689  	if (off < pr->off || pr->off + pr->size < off + sz) {
     690  		DBG(LOWPROBE, ul_debug(
     691  			"ERROR: parts: <---- '%s' subprobe: overflow detected.",
     692  			id->name));
     693  		return -ENOSPC;
     694  	}
     695  
     696  	/* create private prober */
     697  	prc = blkid_clone_probe(pr);
     698  	if (!prc)
     699  		return -ENOMEM;
     700  
     701  	blkid_probe_set_dimension(prc, off, sz);
     702  
     703  	/* clone is always with reset chain, fix it */
     704  	prc->cur_chain = blkid_probe_get_chain(pr);
     705  
     706  	/*
     707  	 * Set 'parent' to the current list of the partitions and use the list
     708  	 * in cloned prober (so the cloned prober will extend the current list
     709  	 * of partitions rather than create a new).
     710  	 */
     711  	ls = blkid_probe_get_partlist(pr);
     712  	blkid_partlist_set_parent(ls, parent);
     713  
     714  	blkid_probe_set_partlist(prc, ls);
     715  
     716  	rc = idinfo_probe(prc, id, blkid_probe_get_chain(pr));
     717  
     718  	blkid_probe_set_partlist(prc, NULL);
     719  	blkid_partlist_set_parent(ls, NULL);
     720  
     721  	blkid_free_probe(prc);	/* free cloned prober */
     722  
     723  	DBG(LOWPROBE, ul_debug(
     724  		"parts: <---- %s subprobe done (rc=%d)",
     725  		id->name, rc));
     726  
     727  	return rc;
     728  }
     729  
     730  static int blkid_partitions_probe_partition(blkid_probe pr)
     731  {
     732  	blkid_probe disk_pr = NULL;
     733  	blkid_partlist ls;
     734  	blkid_partition par;
     735  	dev_t devno;
     736  
     737  	DBG(LOWPROBE, ul_debug("parts: start probing for partition entry"));
     738  
     739  	if (pr->flags & BLKID_FL_NOSCAN_DEV)
     740  		goto nothing;
     741  
     742  	devno = blkid_probe_get_devno(pr);
     743  	if (!devno)
     744  		goto nothing;
     745  
     746  	disk_pr = blkid_probe_get_wholedisk_probe(pr);
     747  	if (!disk_pr)
     748  		goto nothing;
     749  
     750  	/* parse PT */
     751  	ls = blkid_probe_get_partitions(disk_pr);
     752  	if (!ls)
     753  		goto nothing;
     754  
     755  	par = blkid_partlist_devno_to_partition(ls, devno);
     756  	if (!par)
     757  		goto nothing;
     758  	else {
     759  		const char *v;
     760  		blkid_parttable tab = blkid_partition_get_table(par);
     761  		dev_t disk = blkid_probe_get_devno(disk_pr);
     762  
     763  		if (tab) {
     764  			v = blkid_parttable_get_type(tab);
     765  			if (v)
     766  				blkid_probe_set_value(pr, "PART_ENTRY_SCHEME",
     767  					(const unsigned char *) v, strlen(v) + 1);
     768  		}
     769  
     770  		v = blkid_partition_get_name(par);
     771  		if (v)
     772  			blkid_probe_set_value(pr, "PART_ENTRY_NAME",
     773  				(const unsigned char *) v, strlen(v) + 1);
     774  
     775  		v = blkid_partition_get_uuid(par);
     776  		if (v)
     777  			blkid_probe_set_value(pr, "PART_ENTRY_UUID",
     778  				(const unsigned char *) v, strlen(v) + 1);
     779  
     780  		/* type */
     781  		v = blkid_partition_get_type_string(par);
     782  		if (v)
     783  			blkid_probe_set_value(pr, "PART_ENTRY_TYPE",
     784  				(const unsigned char *) v, strlen(v) + 1);
     785  		else
     786  			blkid_probe_sprintf_value(pr, "PART_ENTRY_TYPE",
     787  				"0x%x", blkid_partition_get_type(par));
     788  
     789  		if (blkid_partition_get_flags(par))
     790  			blkid_probe_sprintf_value(pr, "PART_ENTRY_FLAGS",
     791  				"0x%llx", blkid_partition_get_flags(par));
     792  
     793  		blkid_probe_sprintf_value(pr, "PART_ENTRY_NUMBER",
     794  				"%d", blkid_partition_get_partno(par));
     795  
     796  		blkid_probe_sprintf_value(pr, "PART_ENTRY_OFFSET", "%jd",
     797  				(intmax_t)blkid_partition_get_start(par));
     798  		blkid_probe_sprintf_value(pr, "PART_ENTRY_SIZE", "%jd",
     799  				(intmax_t)blkid_partition_get_size(par));
     800  
     801  		blkid_probe_sprintf_value(pr, "PART_ENTRY_DISK", "%u:%u",
     802  				major(disk), minor(disk));
     803  	}
     804  
     805  	DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [success]"));
     806  	return BLKID_PROBE_OK;
     807  
     808  nothing:
     809  	DBG(LOWPROBE, ul_debug("parts: end probing for partition entry [nothing]"));
     810  	return BLKID_PROBE_NONE;
     811  
     812  
     813  }
     814  
     815  /*
     816   * Returns 1 if the device is whole-disk and the area specified by @offset and
     817   * @size is covered by any partition.
     818   */
     819  int blkid_probe_is_covered_by_pt(blkid_probe pr,
     820  				 uint64_t offset, uint64_t size)
     821  {
     822  	blkid_probe prc = NULL;
     823  	blkid_partlist ls = NULL;
     824  	uint64_t start, end;
     825  	int nparts, i, rc = 0;
     826  
     827  	DBG(LOWPROBE, ul_debug(
     828  		"=> checking if off=%"PRIu64" size=%"PRIu64" covered by PT",
     829  		offset, size));
     830  
     831  	if (pr->flags & BLKID_FL_NOSCAN_DEV)
     832  		goto done;
     833  
     834  	prc = blkid_clone_probe(pr);
     835  	if (!prc)
     836  		goto done;
     837  
     838  	ls = blkid_probe_get_partitions(prc);
     839  	if (!ls)
     840  		goto done;
     841  
     842  	nparts = blkid_partlist_numof_partitions(ls);
     843  	if (!nparts)
     844  		goto done;
     845  
     846  	end = (offset + size) >> 9;
     847  	start = offset >> 9;
     848  
     849  	/* check if the partition table fits into the device */
     850  	for (i = 0; i < nparts; i++) {
     851  		blkid_partition par = &ls->parts[i];
     852  
     853  		if (par->start + par->size > (pr->size >> 9)) {
     854  			DBG(LOWPROBE, ul_debug("partition #%d overflows "
     855  				"device (off=%" PRId64 " size=%" PRId64 ")",
     856  				par->partno, par->start, par->size));
     857  			goto done;
     858  		}
     859  	}
     860  
     861  	/* check if the requested area is covered by PT */
     862  	for (i = 0; i < nparts; i++) {
     863  		blkid_partition par = &ls->parts[i];
     864  
     865  		if (start >= par->start && end <= par->start + par->size) {
     866  			rc = 1;
     867  			break;
     868  		}
     869  	}
     870  done:
     871  	blkid_free_probe(prc);
     872  
     873  	DBG(LOWPROBE, ul_debug("<= %s covered by PT", rc ? "IS" : "NOT"));
     874  	return rc;
     875  }
     876  
     877  /**
     878   * blkid_known_pttype:
     879   * @pttype: partition name
     880   *
     881   * Returns: 1 for known or 0 for unknown partition type.
     882   */
     883  int blkid_known_pttype(const char *pttype)
     884  {
     885  	size_t i;
     886  
     887  	if (!pttype)
     888  		return 0;
     889  
     890  	for (i = 0; i < ARRAY_SIZE(idinfos); i++) {
     891  		const struct blkid_idinfo *id = idinfos[i];
     892  		if (strcmp(id->name, pttype) == 0)
     893  			return 1;
     894  	}
     895  	return 0;
     896  }
     897  
     898  /**
     899   * blkid_partitions_get_name:
     900   * @idx: number >= 0
     901   * @name: returns name of a supported partition
     902   *
     903   * Since: 2.30
     904   *
     905   * Returns: -1 if @idx is out of range, or 0 on success.
     906   */
     907  int blkid_partitions_get_name(const size_t idx, const char **name)
     908  {
     909  	if (idx < ARRAY_SIZE(idinfos)) {
     910  		*name = idinfos[idx]->name;
     911  		return 0;
     912  	}
     913  	return -1;
     914  }
     915  
     916  /**
     917   * blkid_partlist_numof_partitions:
     918   * @ls: partitions list
     919   *
     920   * Returns: number of partitions in the list or -1 in case of error.
     921   */
     922  int blkid_partlist_numof_partitions(blkid_partlist ls)
     923  {
     924  	return ls->nparts;
     925  }
     926  
     927  /**
     928   * blkid_partlist_get_table:
     929   * @ls: partitions list
     930   *
     931   * Returns: top-level partition table or NULL if there is not a partition table
     932   * on the device.
     933   */
     934  blkid_parttable blkid_partlist_get_table(blkid_partlist ls)
     935  {
     936  	if (list_empty(&ls->l_tabs))
     937  		return NULL;
     938  
     939  	return list_entry(ls->l_tabs.next,
     940  			struct blkid_struct_parttable, t_tabs);
     941  }
     942  
     943  
     944  /**
     945   * blkid_partlist_get_partition:
     946   * @ls: partitions list
     947   * @n: partition number in range 0..N, where 'N' is blkid_partlist_numof_partitions().
     948   *
     949   * It's possible that the list of partitions is *empty*, but there is a valid
     950   * partition table on the disk. This happen when on-disk details about
     951   * partitions are unknown or the partition table is empty.
     952   *
     953   * See also blkid_partlist_get_table().
     954   *
     955   * Returns: partition object or NULL in case or error.
     956   */
     957  blkid_partition blkid_partlist_get_partition(blkid_partlist ls, int n)
     958  {
     959  	if (n < 0 || n >= ls->nparts)
     960  		return NULL;
     961  
     962  	return &ls->parts[n];
     963  }
     964  
     965  blkid_partition blkid_partlist_get_partition_by_start(blkid_partlist ls, uint64_t start)
     966  {
     967  	int i, nparts;
     968  	blkid_partition par;
     969  
     970  	nparts = blkid_partlist_numof_partitions(ls);
     971  	for (i = 0; i < nparts; i++) {
     972  		par = blkid_partlist_get_partition(ls, i);
     973  		if ((uint64_t) blkid_partition_get_start(par) == start)
     974  			return par;
     975  	}
     976  	return NULL;
     977  }
     978  
     979  /**
     980   * blkid_partlist_get_partition_by_partno
     981   * @ls: partitions list
     982   * @n: the partition number (e.g. 'N' from sda'N')
     983   *
     984   * This does not assume any order of the input blkid_partlist.  And correctly
     985   * handles "out of order" partition tables.  partition N is located after
     986   * partition N+1 on the disk.
     987   *
     988   * Returns: partition object or NULL in case or error.
     989   */
     990  blkid_partition blkid_partlist_get_partition_by_partno(blkid_partlist ls, int n)
     991  {
     992  	int i, nparts;
     993  	blkid_partition par;
     994  
     995  	nparts = blkid_partlist_numof_partitions(ls);
     996  	for (i = 0; i < nparts; i++) {
     997  		par = blkid_partlist_get_partition(ls, i);
     998  		if (n == blkid_partition_get_partno(par))
     999  			return par;
    1000  	}
    1001  	return NULL;
    1002  }
    1003  
    1004  
    1005  /**
    1006   * blkid_partlist_devno_to_partition:
    1007   * @ls: partitions list
    1008   * @devno: requested partition
    1009   *
    1010   * This function tries to get start and size for @devno from sysfs and
    1011   * returns a partition from @ls which matches with the values from sysfs.
    1012   *
    1013   * This function is necessary when you want to make a relation between an entry
    1014   * in the partition table (@ls) and block devices in your system.
    1015   *
    1016   * Returns: partition object or NULL in case or error.
    1017   */
    1018  blkid_partition blkid_partlist_devno_to_partition(blkid_partlist ls, dev_t devno)
    1019  {
    1020  	struct path_cxt *pc;
    1021  	uint64_t start = 0, size;
    1022  	int i, rc, partno = 0;
    1023  
    1024  	DBG(LOWPROBE, ul_debug("trying to convert devno 0x%llx to partition",
    1025  			(long long) devno));
    1026  
    1027  
    1028  	pc = ul_new_sysfs_path(devno, NULL, NULL);
    1029  	if (!pc) {
    1030  		DBG(LOWPROBE, ul_debug("failed t init sysfs context"));
    1031  		return NULL;
    1032  	}
    1033  	rc = ul_path_read_u64(pc, &size, "size");
    1034  	if (!rc) {
    1035  		rc = ul_path_read_u64(pc, &start, "start");
    1036  		if (rc) {
    1037  			/* try to get partition number from DM uuid.
    1038  			 */
    1039  			char *uuid = NULL, *tmp, *prefix;
    1040  
    1041  			ul_path_read_string(pc, &uuid, "dm/uuid");
    1042  			tmp = uuid;
    1043  			prefix = uuid ? strsep(&tmp, "-") : NULL;
    1044  
    1045  			if (prefix && strncasecmp(prefix, "part", 4) == 0) {
    1046  				char *end = NULL;
    1047  
    1048  				errno = 0;
    1049  				partno = strtol(prefix + 4, &end, 10);
    1050  				if (errno || prefix == end || (end && *end))
    1051  					partno = 0;
    1052  				else
    1053  					rc = 0;		/* success */
    1054  			}
    1055  			free(uuid);
    1056  		}
    1057  	}
    1058  
    1059  	ul_unref_path(pc);
    1060  
    1061  	if (rc)
    1062  		return NULL;
    1063  
    1064  	if (partno) {
    1065  		DBG(LOWPROBE, ul_debug("mapped by DM, using partno %d", partno));
    1066  
    1067  		/*
    1068  		 * Partition mapped by kpartx does not provide "start" offset
    1069  		 * in /sys, but if we know partno and size of the partition
    1070  		 * that we can probably make the relation between the device
    1071  		 * and an entry in partition table.
    1072  		 */
    1073  		 for (i = 0; i < ls->nparts; i++) {
    1074  			 blkid_partition par = &ls->parts[i];
    1075  
    1076  			 if (partno != blkid_partition_get_partno(par))
    1077  				 continue;
    1078  
    1079  			 if (size == (uint64_t)blkid_partition_get_size(par) ||
    1080  			     (blkid_partition_is_extended(par) && size <= 1024ULL))
    1081  				 return par;
    1082  
    1083  		 }
    1084  		 return NULL;
    1085  	}
    1086  
    1087  	DBG(LOWPROBE, ul_debug("searching by offset/size"));
    1088  
    1089  	for (i = 0; i < ls->nparts; i++) {
    1090  		blkid_partition par = &ls->parts[i];
    1091  
    1092  		if ((uint64_t)blkid_partition_get_start(par) == start &&
    1093  		    (uint64_t)blkid_partition_get_size(par) == size)
    1094  			return par;
    1095  
    1096  		/* exception for extended dos partitions */
    1097  		if ((uint64_t)blkid_partition_get_start(par) == start &&
    1098  		    blkid_partition_is_extended(par) && size <= 1024ULL)
    1099  			return par;
    1100  
    1101  	}
    1102  
    1103  	DBG(LOWPROBE, ul_debug("not found partition for device"));
    1104  	return NULL;
    1105  }
    1106  
    1107  
    1108  int blkid_parttable_set_uuid(blkid_parttable tab, const unsigned char *id)
    1109  {
    1110  	if (!tab)
    1111  		return -1;
    1112  
    1113  	blkid_unparse_uuid(id, tab->id, sizeof(tab->id));
    1114  	return 0;
    1115  }
    1116  
    1117  int blkid_parttable_set_id(blkid_parttable tab, const unsigned char *id)
    1118  {
    1119  	if (!tab)
    1120  		return -1;
    1121  
    1122  	xstrncpy(tab->id, (const char *) id, sizeof(tab->id));
    1123  	return 0;
    1124  }
    1125  
    1126  /* set PTUUID variable for non-binary API */
    1127  int blkid_partitions_set_ptuuid(blkid_probe pr, unsigned char *uuid)
    1128  {
    1129  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
    1130  	struct blkid_prval *v;
    1131  
    1132  	if (chn->binary || blkid_uuid_is_empty(uuid, 16))
    1133  		return 0;
    1134  
    1135  	v = blkid_probe_assign_value(pr, "PTUUID");
    1136  	if (!v)
    1137  		return -ENOMEM;
    1138  
    1139  	v->len = UUID_STR_LEN;
    1140  	v->data = calloc(1, v->len);
    1141  	if (v->data) {
    1142  		blkid_unparse_uuid(uuid, (char *) v->data, v->len);
    1143  		return 0;
    1144  	}
    1145  
    1146  	blkid_probe_free_value(v);
    1147  	return -ENOMEM;
    1148  }
    1149  
    1150  /* set PTUUID variable for non-binary API for tables where
    1151   * the ID is just a string */
    1152  int blkid_partitions_strcpy_ptuuid(blkid_probe pr, const char *str)
    1153  {
    1154  	struct blkid_chain *chn = blkid_probe_get_chain(pr);
    1155  
    1156  	if (chn->binary || !str || !*str)
    1157  		return 0;
    1158  
    1159  	if (!blkid_probe_set_value(pr, "PTUUID", (unsigned char *) str, strlen(str) + 1))
    1160  		return -ENOMEM;
    1161  
    1162  	return 0;
    1163  }
    1164  
    1165  /**
    1166   * blkid_parttable_get_id:
    1167   * @tab: partition table
    1168   *
    1169   * The ID is GPT disk UUID or DOS disk ID (in hex format).
    1170   *
    1171   * Returns: partition table ID (for example GPT disk UUID) or NULL
    1172   */
    1173  const char *blkid_parttable_get_id(blkid_parttable tab)
    1174  {
    1175  	return *tab->id ? tab->id : NULL;
    1176  }
    1177  
    1178  
    1179  int blkid_partition_set_type(blkid_partition par, int type)
    1180  {
    1181  	par->type = type;
    1182  	return 0;
    1183  }
    1184  
    1185  /**
    1186   * blkid_parttable_get_type:
    1187   * @tab: partition table
    1188   *
    1189   * Returns: partition table type (type name, e.g. "dos", "gpt", ...)
    1190   */
    1191  const char *blkid_parttable_get_type(blkid_parttable tab)
    1192  {
    1193  	return tab->type;
    1194  }
    1195  
    1196  /**
    1197   * blkid_parttable_get_parent:
    1198   * @tab: partition table
    1199   *
    1200   * Returns: parent for nested partition tables or NULL.
    1201   */
    1202  blkid_partition blkid_parttable_get_parent(blkid_parttable tab)
    1203  {
    1204  	return tab->parent;
    1205  }
    1206  
    1207  /**
    1208   * blkid_parttable_get_offset:
    1209   * @tab: partition table
    1210   *
    1211   * Note the position is relative to begin of the device as defined by
    1212   * blkid_probe_set_device() for primary partition table, and relative
    1213   * to parental partition for nested partition tables.
    1214   *
    1215   * <informalexample>
    1216   *   <programlisting>
    1217   * off_t offset;
    1218   * blkid_partition parent = blkid_parttable_get_parent(tab);
    1219   *
    1220   * offset = blkid_parttable_get_offset(tab);
    1221   *
    1222   * if (parent)
    1223   *      / * 'tab' is nested partition table * /
    1224   *	offset += blkid_partition_get_start(parent);
    1225   *   </programlisting>
    1226   * </informalexample>
    1227  
    1228   * Returns: position (in bytes) of the partition table or -1 in case of error.
    1229   *
    1230   */
    1231  blkid_loff_t blkid_parttable_get_offset(blkid_parttable tab)
    1232  {
    1233  	return (blkid_loff_t)tab->offset;
    1234  }
    1235  
    1236  /**
    1237   * blkid_partition_get_table:
    1238   * @par: partition
    1239   *
    1240   * The "parttable" describes partition table. The table is usually the same for
    1241   * all partitions -- except nested partition tables.
    1242   *
    1243   * For example bsd, solaris, etc. use a nested partition table within
    1244   * standard primary dos partition:
    1245   *
    1246   * <informalexample>
    1247   *   <programlisting>
    1248   *
    1249   *  -- dos partition table
    1250   *  0: sda1     dos primary partition
    1251   *  1: sda2     dos primary partition
    1252   *     -- bsd partition table (with in sda2)
    1253   *  2:    sda5  bds partition
    1254   *  3:    sda6  bds partition
    1255   *
    1256   *   </programlisting>
    1257   * </informalexample>
    1258   *
    1259   * The library does not to use a separate partition table object for dos logical
    1260   * partitions (partitions within extended partition). It's possible to
    1261   * differentiate between logical, extended and primary partitions by
    1262   *
    1263   *	blkid_partition_is_{extended,primary,logical}().
    1264   *
    1265   * Returns: partition table object or NULL in case of error.
    1266   */
    1267  blkid_parttable blkid_partition_get_table(blkid_partition par)
    1268  {
    1269  	return par->tab;
    1270  }
    1271  
    1272  static int partition_get_logical_type(blkid_partition par)
    1273  {
    1274  	blkid_parttable tab;
    1275  
    1276  	if (!par)
    1277  		return -1;
    1278  
    1279  	tab = blkid_partition_get_table(par);
    1280  	if (!tab || !tab->type)
    1281  		return -1;
    1282  
    1283  	if (tab->parent)
    1284  		return 'L';  /* report nested partitions as logical */
    1285  
    1286  	if (!strcmp(tab->type, "dos")) {
    1287  		if (par->partno > 4)
    1288  			return 'L';	/* logical */
    1289  
    1290  	        if(par->type == MBR_DOS_EXTENDED_PARTITION ||
    1291                     par->type == MBR_W95_EXTENDED_PARTITION ||
    1292  		   par->type == MBR_LINUX_EXTENDED_PARTITION)
    1293  			return 'E';
    1294  	}
    1295  	return 'P';
    1296  }
    1297  
    1298  /**
    1299   * blkid_partition_is_primary:
    1300   * @par: partition
    1301   *
    1302   * Note, this function returns FALSE for DOS extended partitions and
    1303   * all partitions in nested partition tables.
    1304   *
    1305   * Returns: 1 if the partitions is primary partition or 0 if not.
    1306   */
    1307  int blkid_partition_is_primary(blkid_partition par)
    1308  {
    1309  	return partition_get_logical_type(par) == 'P' ? TRUE : FALSE;
    1310  }
    1311  
    1312  /**
    1313   * blkid_partition_is_extended:
    1314   * @par: partition
    1315   *
    1316   * Returns: 1 if the partitions is extended (dos, windows or linux)
    1317   * partition or 0 if not.
    1318   */
    1319  int blkid_partition_is_extended(blkid_partition par)
    1320  {
    1321  	return partition_get_logical_type(par) == 'E' ? TRUE : FALSE;
    1322  }
    1323  
    1324  /**
    1325   * blkid_partition_is_logical:
    1326   * @par: partition
    1327   *
    1328   * Note that this function returns TRUE for all partitions in all
    1329   * nested partition tables (e.g. BSD labels).
    1330   *
    1331   * Returns: 1 if the partitions is logical partition or 0 if not.
    1332   */
    1333  int blkid_partition_is_logical(blkid_partition par)
    1334  {
    1335  	return partition_get_logical_type(par) == 'L' ? TRUE : FALSE;
    1336  }
    1337  
    1338  static void set_string(unsigned char *item, size_t max,
    1339  				const unsigned char *data, size_t len)
    1340  {
    1341  	if (len >= max)
    1342  		len = max - 1;
    1343  
    1344  	memcpy(item, data, len);
    1345  	item[len] = '\0';
    1346  
    1347  	blkid_rtrim_whitespace(item);
    1348  }
    1349  
    1350  int blkid_partition_set_name(blkid_partition par,
    1351  		const unsigned char *name, size_t len)
    1352  {
    1353  	if (!par)
    1354  		return -1;
    1355  
    1356  	set_string(par->name, sizeof(par->name), name, len);
    1357  	return 0;
    1358  }
    1359  
    1360  int blkid_partition_set_utf8name(blkid_partition par, const unsigned char *name,
    1361  		size_t len, int enc)
    1362  {
    1363  	if (!par)
    1364  		return -1;
    1365  
    1366  	ul_encode_to_utf8(enc, par->name, sizeof(par->name), name, len);
    1367  	blkid_rtrim_whitespace(par->name);
    1368  	return 0;
    1369  }
    1370  
    1371  int blkid_partition_set_uuid(blkid_partition par, const unsigned char *uuid)
    1372  {
    1373  	if (!par)
    1374  		return -1;
    1375  
    1376  	blkid_unparse_uuid(uuid, par->uuid, sizeof(par->uuid));
    1377  	return 0;
    1378  }
    1379  
    1380  int blkid_partition_gen_uuid(blkid_partition par)
    1381  {
    1382  	if (!par || !par->tab || !*par->tab->id)
    1383  		return -1;
    1384  
    1385  	snprintf(par->uuid, sizeof(par->uuid), "%.33s-%02x",
    1386  			par->tab->id, par->partno);
    1387  	return 0;
    1388  }
    1389  
    1390  /**
    1391   * blkid_partition_get_name:
    1392   * @par: partition
    1393   *
    1394   * Returns: partition name string if supported by PT (e.g. Mac) or NULL.
    1395   */
    1396  const char *blkid_partition_get_name(blkid_partition par)
    1397  {
    1398  	return *par->name ? (char *) par->name : NULL;
    1399  }
    1400  
    1401  /**
    1402   * blkid_partition_get_uuid:
    1403   * @par: partition
    1404   *
    1405   * Returns: partition UUID string if supported by PT (e.g. GPT) or NULL.
    1406   */
    1407  const char *blkid_partition_get_uuid(blkid_partition par)
    1408  {
    1409  	return *par->uuid ? par->uuid : NULL;
    1410  }
    1411  
    1412  /**
    1413   * blkid_partition_get_partno:
    1414   * @par: partition
    1415   *
    1416   * Returns: proposed partition number (e.g. 'N' from sda'N') or -1 in case of
    1417   * error. Note that the number is generated by library independently of your OS.
    1418   */
    1419  int blkid_partition_get_partno(blkid_partition par)
    1420  {
    1421  	return par->partno;
    1422  }
    1423  
    1424  /**
    1425   * blkid_partition_get_start:
    1426   * @par: partition
    1427   *
    1428   * Be careful if you _not_ probe whole disk:
    1429   *
    1430   * 1) the offset is usually relative to begin of the disk -- but if you probe a
    1431   *    fragment of the disk only -- then the offset could be still relative to
    1432   *    the begin of the disk rather that relative to the fragment.
    1433   *
    1434   * 2) the offset for nested partitions could be relative to parent (e.g. Solaris)
    1435   *    _or_ relative to the begin of the whole disk (e.g. bsd).
    1436   *
    1437   * You don't have to care about such details if you probe whole disk. In such
    1438   * a case libblkid always returns the offset relative to the begin of the disk.
    1439   *
    1440   * Returns: start of the partition (in 512-sectors).
    1441   */
    1442  blkid_loff_t blkid_partition_get_start(blkid_partition par)
    1443  {
    1444  	return (blkid_loff_t)par->start;
    1445  }
    1446  
    1447  /**
    1448   * blkid_partition_get_size:
    1449   * @par: partition
    1450   *
    1451   * WARNING: be very careful when you work with MS-DOS extended partitions. The
    1452   *          library always returns full size of the partition. If you want to
    1453   *          add the partition to the Linux system (BLKPG_ADD_PARTITION ioctl)
    1454   *          you need to reduce the size of the partition to 1 or 2 blocks. The
    1455   *          rest of the partition has to be inaccessible for mkfs or mkswap
    1456   *          programs, we need a small space for boot loaders only.
    1457   *
    1458   *          For some unknown reason this (safe) practice is not to used for
    1459   *          nested BSD, Solaris, ..., partition tables in Linux kernel.
    1460   *
    1461   * Returns: size of the partition (in 512-sectors).
    1462   */
    1463  blkid_loff_t blkid_partition_get_size(blkid_partition par)
    1464  {
    1465  	return (blkid_loff_t)par->size;
    1466  }
    1467  
    1468  /**
    1469   * blkid_partition_get_type:
    1470   * @par: partition
    1471   *
    1472   * Returns: partition type.
    1473   */
    1474  int blkid_partition_get_type(blkid_partition par)
    1475  {
    1476  	return par->type;
    1477  }
    1478  
    1479  /* Sets partition 'type' for PT where the type is defined by string rather
    1480   * than by number
    1481   */
    1482  int blkid_partition_set_type_string(blkid_partition par,
    1483  		const unsigned char *type, size_t len)
    1484  {
    1485  	set_string((unsigned char *) par->typestr,
    1486  			sizeof(par->typestr), type, len);
    1487  	return 0;
    1488  }
    1489  
    1490  /* Sets partition 'type' for PT where the type is defined by UUID rather
    1491   * than by number
    1492   */
    1493  int blkid_partition_set_type_uuid(blkid_partition par, const unsigned char *uuid)
    1494  {
    1495  	blkid_unparse_uuid(uuid, par->typestr, sizeof(par->typestr));
    1496  	return 0;
    1497  }
    1498  
    1499  /**
    1500   * blkid_partition_get_type_string:
    1501   * @par: partition
    1502   *
    1503   * The type string is supported by a small subset of partition tables (e.g. Mac
    1504   * and EFI GPT).  Note that GPT uses type UUID and this function returns this
    1505   * UUID as string.
    1506   *
    1507   * Returns: partition type string or NULL.
    1508   */
    1509  const char *blkid_partition_get_type_string(blkid_partition par)
    1510  {
    1511  	return *par->typestr ? par->typestr : NULL;
    1512  }
    1513  
    1514  
    1515  int blkid_partition_set_flags(blkid_partition par, unsigned long long flags)
    1516  {
    1517  	par->flags = flags;
    1518  	return 0;
    1519  }
    1520  
    1521  /**
    1522   * blkid_partition_get_flags
    1523   * @par: partition
    1524   *
    1525   * Returns: partition flags (or attributes for gpt).
    1526   */
    1527  unsigned long long blkid_partition_get_flags(blkid_partition par)
    1528  {
    1529  	return par->flags;
    1530  }
    1531