2 * Source: copy of util-linux' partx partx.c
4 * Copyrights of the original file applies
5 * Copyright (c) 2004, 2005 Christophe Varoqui
6 * Copyright (c) 2005 Kiyoshi Ueda
7 * Copyright (c) 2005 Lars Soltau
11 * Given a block device and a partition table type,
12 * try to parse the partition table, and list the
13 * contents. Optionally add or remove partitions.
15 * Read wholedisk and add all partitions:
16 * kpartx [-a|-d|-l] [-v] wholedisk
30 #include <sys/ioctl.h>
32 #include <sys/sysmacros.h>
33 #include <sys/types.h>
35 #include <libdevmapper.h>
37 #include "autoconfig.h"
38 #include "devmapper.h"
44 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
48 #define DM_TARGET "linear"
49 #define LO_NAME_SIZE 64
50 #define PARTNAME_SIZE 128
53 struct slice slices[MAXSLICES];
55 enum action { LIST, ADD, DELETE, UPDATE };
66 addpts(char *t, ptreader f)
68 if (ptct >= MAXTYPES) {
69 fprintf(stderr, "addpts: too many types\n");
80 addpts("gpt", read_gpt_pt);
81 addpts("dos", read_dos_pt);
82 addpts("bsd", read_bsd_pt);
83 addpts("solaris", read_solaris_pt);
84 addpts("unixware", read_unixware_pt);
85 addpts("dasd", read_dasd_pt);
86 addpts("mac", read_mac_pt);
87 addpts("sun", read_sun_pt);
88 addpts("ps3", read_ps3_pt);
91 static char short_opts[] = "rladfgvp:t:snu";
100 printf(VERSION_STRING);
102 printf(" kpartx [-a|-d|-u|-l] [-r] [-p] [-f] [-g] [-s|-n] [-v] wholedisk\n");
103 printf("\t-a add partition devmappings\n");
104 printf("\t-r devmappings will be readonly\n");
105 printf("\t-d del partition devmappings\n");
106 printf("\t-u update partition devmappings\n");
107 printf("\t-l list partitions devmappings that would be added by -a\n");
108 printf("\t-p set device name-partition number delimiter\n");
109 printf("\t-g force GUID partition table (GPT)\n");
110 printf("\t-f force devmap create\n");
111 printf("\t-v verbose\n");
112 printf("\t-n nosync mode. Return before the partitions are created\n");
113 printf("\t-s sync mode (Default). Don't return until the partitions are created\n");
118 set_delimiter (char * device, char * delimiter)
125 while (*(++p) != 0x0)
128 if (isdigit(*(p - 1)))
133 find_devname_offset (char * device)
145 return (int)(q - device);
149 get_hotplug_device(void)
151 unsigned int major, minor, off, len;
153 char *devname = NULL;
158 var = getenv("ACTION");
160 if (!var || strcmp(var, "add"))
163 /* Get dm mapname for hotpluged device. */
164 if (!(devname = getenv("DEVNAME")))
167 if (stat(devname, &buf))
170 major = major(buf.st_rdev);
171 minor = minor(buf.st_rdev);
173 if (!(mapname = dm_mapname(major, minor))) /* Not dm device. */
176 off = find_devname_offset(devname);
177 len = strlen(mapname);
179 /* Dirname + mapname + \0 */
180 if (!(device = (char *)malloc(sizeof(char) * (off + len + 1)))) {
185 /* Create new device name. */
186 snprintf(device, off + 1, "%s", devname);
187 snprintf(device + off, len + 1, "%s", mapname);
189 if (strlen(device) != (off + len)) {
199 check_uuid(char *uuid, char *part_uuid, char **err_msg) {
200 char *map_uuid = strchr(part_uuid, '-');
201 if (!map_uuid || strncmp(part_uuid, "part", 4) != 0) {
202 *err_msg = "not a kpartx partition";
206 if (strcmp(uuid, map_uuid) != 0) {
207 *err_msg = "a partition of a different device";
214 xmalloc (size_t size) {
223 fprintf(stderr, "Out of memory\n");
231 main(int argc, char **argv){
232 int i, j, m, n, op, off, arg, c, d, ro=0;
236 enum action what = LIST;
237 char *type, *diskdevice, *device, *progname;
239 char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
240 char * loopdev = NULL;
243 char *mapname = NULL;
251 type = device = diskdevice = NULL;
252 memset(&all, 0, sizeof(all));
253 memset(&partname, 0, sizeof(partname));
255 /* Check whether hotplug mode. */
256 progname = strrchr(argv[0], '/');
263 if (!strcmp(progname, "kpartx.dev")) { /* Hotplug mode */
266 /* Setup for original kpartx variables */
267 if (!(device = get_hotplug_device()))
272 } else if (argc < 2) {
277 while ((arg = getopt(argc, argv, short_opts)) != EOF)
320 #ifdef LIBDM_API_COOKIE
322 dm_udev_set_sync_support(0);
324 dm_udev_set_sync_support(1);
327 if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE || what == UPDATE)) {
328 fprintf(stderr, "device mapper prerequisites not met\n");
333 /* already got [disk]device */
334 } else if (optind == argc-2) {
335 device = argv[optind];
336 diskdevice = argv[optind+1];
337 } else if (optind == argc-1) {
338 diskdevice = device = argv[optind];
344 if (stat(device, &buf)) {
345 printf("failed to stat() %s\n", device);
349 if (S_ISREG (buf.st_mode)) {
350 /* already looped file ? */
351 char rpath[PATH_MAX];
352 if (realpath(device, rpath) == NULL) {
353 fprintf(stderr, "Error: %s: %s\n", device,
357 loopdev = find_loop_by_file(rpath);
359 if (!loopdev && what == DELETE)
363 if (set_loop(&loopdev, rpath, 0, &ro)) {
364 fprintf(stderr, "can't set up loop\n");
371 if (stat(device, &buf)) {
372 printf("failed to stat() %s\n", device);
376 else if (!S_ISBLK(buf.st_mode)) {
377 fprintf(stderr, "invalid device: %s\n", device);
381 off = find_devname_offset(device);
384 mapname = dm_mapname(major(buf.st_rdev), minor(buf.st_rdev));
386 uuid = dm_mapuuid(mapname);
390 * We are called for a non-DM device.
391 * Make up a fake UUID for the device, unless "-d -f" is given.
392 * This allows deletion of partitions created with older kpartx
393 * versions which didn't use the fake UUID during creation.
395 if (!uuid && !(what == DELETE && force_devmap))
396 uuid = nondm_create_uuid(buf.st_rdev);
399 mapname = device + off;
402 delim = xmalloc(DELIM_SIZE);
403 memset(delim, 0, DELIM_SIZE);
404 set_delimiter(mapname, delim);
407 fd = open(device, O_RDONLY | O_DIRECT);
414 /* add/remove partitions to the kernel devmapper tables */
417 if (what == DELETE) {
418 r = dm_remove_partmaps(mapname, uuid, buf.st_rdev,
421 if (del_loop(loopdev)) {
423 fprintf(stderr, "can't del loop : %s\n",
427 fprintf(stderr, "loop deleted : %s\n", loopdev);
432 for (i = 0; i < ptct; i++) {
435 if (type && strcmp(type, ptp->type))
438 /* here we get partitions */
439 n = ptp->fn(fd, all, slices, SIZE(slices));
443 printf("%s: %d slices\n", ptp->type, n);
450 for (j = 0, c = 0, m = 0; j < n; j++) {
451 if (slices[j].size == 0)
453 if (slices[j].container > 0) {
458 slices[j].minor = m++;
460 printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
462 slices[j].size, device,
465 /* Loop to resolve contained slices */
468 for (j = 0; j < n; j++) {
470 int k = slices[j].container - 1;
472 if (slices[j].size == 0)
474 if (slices[j].minor > 0)
476 if (slices[j].container == 0)
478 slices[j].minor = m++;
480 start = slices[j].start - slices[k].start;
481 printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
484 slices[k].minor, start);
487 /* Terminate loop if nothing more to resolve */
496 /* ADD and UPDATE share the same code that adds new partitions. */
497 for (j = 0, c = 0; j < n; j++) {
498 char *part_uuid, *reason;
500 if (slices[j].size == 0)
503 /* Skip all contained slices */
504 if (slices[j].container > 0) {
509 if (safe_sprintf(params, "%d:%d %" PRIu64 ,
510 major(buf.st_rdev), minor(buf.st_rdev), slices[j].start)) {
511 fprintf(stderr, "params too small\n");
515 op = (dm_find_part(mapname, delim, j + 1, uuid,
516 partname, sizeof(partname),
517 &part_uuid, verbose) ?
518 DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
520 if (part_uuid && uuid) {
521 if (check_uuid(uuid, part_uuid, &reason) != 0) {
522 fprintf(stderr, "%s is already in use, and %s\n", partname, reason);
530 if (!dm_addmap(op, partname, DM_TARGET, params,
531 slices[j].size, ro, uuid, j+1,
532 buf.st_mode & 0777, buf.st_uid,
534 fprintf(stderr, "create/reload failed on %s\n",
539 if (op == DM_DEVICE_RELOAD &&
540 !dm_simplecmd(DM_DEVICE_RESUME, partname,
541 1, MPATH_UDEV_RELOAD_FLAG)) {
542 fprintf(stderr, "resume failed on %s\n",
548 dm_devn(partname, &slices[j].major,
552 printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
553 partname, slices[j].major,
554 slices[j].minor, slices[j].size,
557 /* Loop to resolve contained slices */
560 for (j = 0; j < n; j++) {
561 char *part_uuid, *reason;
562 int k = slices[j].container - 1;
564 if (slices[j].size == 0)
567 /* Skip all existing slices */
568 if (slices[j].minor > 0)
571 /* Skip all simple slices */
572 if (slices[j].container == 0)
575 /* Check container slice */
576 if (slices[k].size == 0)
577 fprintf(stderr, "Invalid slice %d\n",
580 if (safe_sprintf(params, "%d:%d %" PRIu64,
581 major(buf.st_rdev), minor(buf.st_rdev),
583 fprintf(stderr, "params too small\n");
587 op = (dm_find_part(mapname, delim, j + 1, uuid,
590 &part_uuid, verbose) ?
591 DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
593 if (part_uuid && uuid) {
594 if (check_uuid(uuid, part_uuid, &reason) != 0) {
595 fprintf(stderr, "%s is already in use, and %s\n", partname, reason);
602 dm_addmap(op, partname, DM_TARGET, params,
603 slices[j].size, ro, uuid, j+1,
605 buf.st_uid, buf.st_gid);
607 if (op == DM_DEVICE_RELOAD)
608 dm_simplecmd(DM_DEVICE_RESUME,
610 MPATH_UDEV_RELOAD_FLAG);
611 dm_devn(partname, &slices[j].major,
615 printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
616 partname, slices[j].major, slices[j].minor, slices[j].size,
626 /* Skip code that removes devmappings for deleted partitions */
630 for (j = MAXSLICES-1; j >= 0; j--) {
631 char *part_uuid, *reason;
632 if (slices[j].size ||
633 !dm_find_part(mapname, delim, j + 1, uuid,
634 partname, sizeof(partname),
635 &part_uuid, verbose))
638 if (part_uuid && uuid) {
639 if (check_uuid(uuid, part_uuid, &reason) != 0) {
640 fprintf(stderr, "%s is %s. Not removing\n", partname, reason);
647 if (!dm_simplecmd(DM_DEVICE_REMOVE,
649 fprintf(stderr, "failed to remove %s",
655 printf("del devmap : %s\n", partname);
667 if (what == LIST && loopcreated) {
668 if (del_loop(device)) {
670 fprintf(stderr, "can't del loop : %s\n",
675 fprintf(stderr, "loop deleted : %s\n", device);
685 * sseek: seek to specified sector
689 sseek(int fd, unsigned int secnr, int secsz) {
691 in = ((off64_t) secnr * secsz);
694 if ((out = lseek64(fd, in, SEEK_SET)) != in)
696 fprintf(stderr, "llseek error\n");
703 aligned_malloc(void **mem_p, size_t align, size_t *size_p)
705 static size_t pgsize = 0;
709 if (!mem_p || !align || (size_p && !*size_p))
713 pgsize = getpagesize();
716 size = ((*size_p + align - 1) / align) * align;
720 err = posix_memalign(mem_p, pgsize, size);
726 /* always in sector size blocks */
734 /* blknr is always in 512 byte blocks */
736 getblock (int fd, unsigned int blknr) {
737 int secsz = get_sector_size(fd);
738 unsigned int blks_per_sec = secsz / 512;
739 unsigned int secnr = blknr / blks_per_sec;
740 unsigned int blk_off = (blknr % blks_per_sec) * 512;
743 for (bp = blockhead; bp; bp = bp->next)
745 if (bp->secnr == secnr)
746 return bp->block + blk_off;
748 if (sseek(fd, secnr, secsz))
751 bp = xmalloc(sizeof(struct block));
753 bp->next = blockhead;
755 if (aligned_malloc((void **)&bp->block, secsz, NULL)) {
756 fprintf(stderr, "aligned_malloc failed\n");
760 if (read(fd, bp->block, secsz) != secsz) {
761 fprintf(stderr, "read error, sector %d\n", secnr);
762 blockhead = bp->next;
768 return bp->block + blk_off;
772 get_sector_size(int filedes)
774 int rc, sector_size = 512;
776 rc = ioctl(filedes, BLKSSZGET, §or_size);