(root)/
util-linux-2.39/
libfdisk/
src/
utils.c
       1  
       2  #include "fdiskP.h"
       3  #include "pathnames.h"
       4  #include "canonicalize.h"
       5  
       6  #include <ctype.h>
       7  
       8  /**
       9   * SECTION: utils
      10   * @title: Utils
      11   * @short_description: misc fdisk functions
      12   */
      13  
      14  static int read_from_device(struct fdisk_context *cxt,
      15  		unsigned char *buf,
      16  		uintmax_t start, size_t size)
      17  {
      18  	ssize_t r;
      19  
      20  	assert(cxt);
      21  
      22  	DBG(CXT, ul_debugobj(cxt, "reading: offset=%ju, size=%zu",
      23  				start, size));
      24  
      25  	r = lseek(cxt->dev_fd, start, SEEK_SET);
      26  	if (r == -1)
      27  	{
      28  		DBG(CXT, ul_debugobj(cxt, "failed to seek to offset %ju: %m", start));
      29  		return -errno;
      30  	}
      31  
      32  	r = read(cxt->dev_fd, buf, size);
      33  	if (r < 0 || (size_t)r != size) {
      34  		if (!errno)
      35  			errno = EINVAL;	/* probably too small file/device */
      36  		DBG(CXT, ul_debugobj(cxt, "failed to read %zu from offset %ju: %m",
      37  				size, start));
      38  		return -errno;
      39  	}
      40  
      41  	return 0;
      42  }
      43  
      44  
      45  /*
      46   * Zeros in-memory first sector buffer
      47   */
      48  int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
      49  				  unsigned int protect_off,
      50  				  unsigned int protect_size)
      51  {
      52  	if (!cxt)
      53  		return -EINVAL;
      54  
      55  	assert(protect_off + protect_size <= cxt->sector_size);
      56  
      57  	if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) {
      58  		/* Let's allocate a new buffer if no allocated yet, or the
      59  		 * current buffer has incorrect size */
      60  		if (!cxt->parent || cxt->parent->firstsector != cxt->firstsector)
      61  			free(cxt->firstsector);
      62  
      63  		DBG(CXT, ul_debugobj(cxt, "initialize in-memory first sector "
      64  				"buffer [sector_size=%lu]", cxt->sector_size));
      65  		cxt->firstsector = calloc(1, cxt->sector_size);
      66  		if (!cxt->firstsector)
      67  			return -ENOMEM;
      68  
      69  		cxt->firstsector_bufsz = cxt->sector_size;
      70  		return 0;
      71  	}
      72  
      73  	DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer"));
      74  	memset(cxt->firstsector, 0, cxt->firstsector_bufsz);
      75  
      76  	if (protect_size) {
      77  		/*
      78  		 * It would be possible to reuse data from cxt->firstsector
      79  		 * (call memset() for non-protected area only) and avoid one
      80  		 * read() from the device, but it seems like a too fragile
      81  		 * solution as we have no clue about stuff in the buffer --
      82  		 * maybe it was already modified. Let's re-read from the device
      83  		 * to be sure.			-- kzak 13-Apr-2015
      84  		 */
      85  		DBG(CXT, ul_debugobj(cxt, "first sector protection enabled -- re-reading"));
      86  		read_from_device(cxt, cxt->firstsector, protect_off, protect_size);
      87  	}
      88  	return 0;
      89  }
      90  
      91  int fdisk_read_firstsector(struct fdisk_context *cxt)
      92  {
      93  	int rc;
      94  
      95  	assert(cxt);
      96  	assert(cxt->sector_size);
      97  
      98  	rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
      99  	if (rc)
     100  		return rc;
     101  
     102  	assert(cxt->sector_size == cxt->firstsector_bufsz);
     103  
     104  
     105  	return  read_from_device(cxt, cxt->firstsector, 0, cxt->sector_size);
     106  }
     107  
     108  /**
     109   * fdisk_partname:
     110   * @dev: device name
     111   * @partno: partition name
     112   *
     113   * Return: allocated buffer with partition name, use free() to deallocate.
     114   */
     115  char *fdisk_partname(const char *dev, size_t partno)
     116  {
     117  	char *res = NULL;
     118  	const char *p = "";
     119  	char *dev_mapped = NULL;
     120  	int w = 0;
     121  
     122  	if (!dev || !*dev) {
     123  		if (asprintf(&res, "%zd", partno) > 0)
     124  			return res;
     125  		return NULL;
     126  	}
     127  
     128  	/* It is impossible to predict /dev/dm-N partition names. */
     129  	if (strncmp(dev, "/dev/dm-", sizeof("/dev/dm-") - 1) == 0) {
     130  		dev_mapped = canonicalize_dm_name (dev + 5);
     131  		if (dev_mapped)
     132  			dev = dev_mapped;
     133  	}
     134  
     135  	w = strlen(dev);
     136  	if (isdigit(dev[w - 1]))
     137  #ifdef __GNU__
     138  		p = "s";
     139  #else
     140  		p = "p";
     141  #endif
     142  
     143  	/* devfs kludge - note: fdisk partition names are not supposed
     144  	   to equal kernel names, so there is no reason to do this */
     145  	if (endswith(dev, "disc")) {
     146  		w -= 4;
     147  		p = "part";
     148  	}
     149  
     150  	/* udev names partitions by appending -partN
     151  	   e.g. ata-SAMSUNG_SV8004H_0357J1FT712448-part1
     152  	   multipath-tools kpartx.rules also append -partN */
     153  	if ((strncmp(dev, _PATH_DEV_BYID, sizeof(_PATH_DEV_BYID) - 1) == 0) ||
     154  	     strncmp(dev, _PATH_DEV_BYPATH, sizeof(_PATH_DEV_BYPATH) - 1) == 0 ||
     155  	     strncmp(dev, "/dev/mapper", sizeof("/dev/mapper") - 1) == 0) {
     156  
     157  		/* check for <name><partno>, e.g. mpatha1 */
     158  		if (asprintf(&res, "%.*s%zu", w, dev, partno) <= 0)
     159  			res = NULL;
     160  		if (res && access(res, F_OK) == 0)
     161  			goto done;
     162  
     163  		free(res);
     164  
     165  		/* check for partition separator "p" */
     166  		if (asprintf(&res, "%.*sp%zu", w, dev, partno) <= 0)
     167  			res = NULL;
     168  		if (res && access(res, F_OK) == 0)
     169  			goto done;
     170  
     171  		free(res);
     172  
     173  		/* otherwise, default to "-path" */
     174  		p = "-part";
     175  	}
     176  
     177  	if (asprintf(&res, "%.*s%s%zu", w, dev, p, partno) <= 0)
     178  		res = NULL;
     179  done:
     180  	free(dev_mapped);
     181  	return res;
     182  }
     183  
     184  #ifdef TEST_PROGRAM
     185  struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; }
     186  struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; }
     187  
     188  static int test_partnames(struct fdisk_test *ts, int argc, char *argv[])
     189  {
     190  	size_t i;
     191  	const char *disk = argv[1];
     192  
     193  	for (i = 0; i < 5; i++) {
     194  		char *p = fdisk_partname(disk, i + 1);
     195  		if (p)
     196  			printf("%zu: '%s'\n", i + 1, p);
     197  		free(p);
     198  	}
     199  
     200  	return 0;
     201  }
     202  
     203  int main(int argc, char *argv[])
     204  {
     205  	struct fdisk_test tss[] = {
     206  		{ "--partnames",  test_partnames,  "<diskname>" },
     207  		{ NULL }
     208  	};
     209  
     210  	return fdisk_run_test(tss, argc, argv);
     211  }
     212  
     213  #endif