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
29 #include <sys/ioctl.h>
31 #include <sys/types.h>
33 #include <libdevmapper.h>
35 #include "devmapper.h"
40 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
42 #define READ_SIZE 1024
45 #define DM_TARGET "linear"
46 #define LO_NAME_SIZE 64
47 #define PARTNAME_SIZE 128
50 struct slice slices[MAXSLICES];
52 enum action { LIST, ADD, DELETE, UPDATE };
63 addpts(char *t, ptreader f)
65 if (ptct >= MAXTYPES) {
66 fprintf(stderr, "addpts: too many types\n");
77 addpts("gpt", read_gpt_pt);
78 addpts("dos", read_dos_pt);
79 addpts("bsd", read_bsd_pt);
80 addpts("solaris", read_solaris_pt);
81 addpts("unixware", read_unixware_pt);
82 addpts("dasd", read_dasd_pt);
83 addpts("mac", read_mac_pt);
84 addpts("sun", read_sun_pt);
85 addpts("ps3", read_ps3_pt);
88 static char short_opts[] = "rladfgvp:t:su";
97 printf("usage : kpartx [-a|-d|-l] [-f] [-v] wholedisk\n");
98 printf("\t-a add partition devmappings\n");
99 printf("\t-r devmappings will be readonly\n");
100 printf("\t-d del partition devmappings\n");
101 printf("\t-u update partition devmappings\n");
102 printf("\t-l list partitions devmappings that would be added by -a\n");
103 printf("\t-p set device name-partition number delimiter\n");
104 printf("\t-g force GUID partition table (GPT)\n");
105 printf("\t-f force devmap create\n");
106 printf("\t-v verbose\n");
107 printf("\t-s sync mode. Don't return until the partitions are created\n");
112 set_delimiter (char * device, char * delimiter)
116 while (*(p++) != 0x0)
119 if (isdigit(*(p - 2)))
124 strip_slash (char * device)
128 while (*(p++) != 0x0) {
136 find_devname_offset (char * device)
146 return (int)(q - device) + 1;
150 get_hotplug_device(void)
152 unsigned int major, minor, off, len;
154 char *devname = NULL;
159 var = getenv("ACTION");
161 if (!var || strcmp(var, "add"))
164 /* Get dm mapname for hotpluged device. */
165 if (!(devname = getenv("DEVNAME")))
168 if (stat(devname, &buf))
171 major = major(buf.st_rdev);
172 minor = minor(buf.st_rdev);
174 if (!(mapname = dm_mapname(major, minor))) /* Not dm device. */
177 off = find_devname_offset(devname);
178 len = strlen(mapname);
180 /* Dirname + mapname + \0 */
181 if (!(device = (char *)malloc(sizeof(char) * (off + len + 1)))) {
186 /* Create new device name. */
187 snprintf(device, off + 1, "%s", devname);
188 snprintf(device + off, len + 1, "%s", mapname);
190 if (strlen(device) != (off + len)) {
200 check_uuid(char *uuid, char *part_uuid, char **err_msg) {
201 char *map_uuid = strchr(part_uuid, '-');
202 if (!map_uuid || strncmp(part_uuid, "part", 4) != 0) {
203 *err_msg = "not a kpartx partition";
207 if (strcmp(uuid, map_uuid) != 0) {
208 *err_msg = "a partition of a different device";
215 main(int argc, char **argv){
216 int i, j, m, n, op, off, arg, c, d, ro=0;
220 enum action what = LIST;
221 char *type, *diskdevice, *device, *progname;
223 char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
224 char * loopdev = NULL;
227 char *mapname = NULL;
235 type = device = diskdevice = NULL;
236 memset(&all, 0, sizeof(all));
237 memset(&partname, 0, sizeof(partname));
239 /* Check whether hotplug mode. */
240 progname = strrchr(argv[0], '/');
247 if (!strcmp(progname, "kpartx.dev")) { /* Hotplug mode */
250 /* Setup for original kpartx variables */
251 if (!(device = get_hotplug_device()))
256 } else if (argc < 2) {
261 while ((arg = getopt(argc, argv, short_opts)) != EOF) switch(arg) {
300 #ifdef LIBDM_API_COOKIE
302 dm_udev_set_sync_support(0);
304 dm_udev_set_sync_support(1);
307 if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE || what == UPDATE)) {
308 fprintf(stderr, "device mapper prerequisites not met\n");
313 /* already got [disk]device */
314 } else if (optind == argc-2) {
315 device = argv[optind];
316 diskdevice = argv[optind+1];
317 } else if (optind == argc-1) {
318 diskdevice = device = argv[optind];
324 if (stat(device, &buf)) {
325 printf("failed to stat() %s\n", device);
329 if (S_ISREG (buf.st_mode)) {
330 /* already looped file ? */
331 loopdev = find_loop_by_file(device);
333 if (!loopdev && what == DELETE)
337 loopdev = find_unused_loop_device();
339 if (set_loop(loopdev, device, 0, &ro)) {
340 fprintf(stderr, "can't set up loop\n");
347 if (stat(device, &buf)) {
348 printf("failed to stat() %s\n", device);
353 off = find_devname_offset(device);
356 uuid = dm_mapuuid(major(buf.st_rdev), minor(buf.st_rdev));
357 mapname = dm_mapname(major(buf.st_rdev), minor(buf.st_rdev));
364 mapname = device + off;
365 else if (!force_devmap &&
366 dm_no_partitions(major(buf.st_rdev), minor(buf.st_rdev))) {
367 /* Feature 'no_partitions' is set, return */
372 delim = malloc(DELIM_SIZE);
373 memset(delim, 0, DELIM_SIZE);
374 set_delimiter(mapname, delim);
377 fd = open(device, O_RDONLY);
384 /* add/remove partitions to the kernel devmapper tables */
386 for (i = 0; i < ptct; i++) {
389 if (type && strcmp(type, ptp->type))
392 /* here we get partitions */
393 n = ptp->fn(fd, all, slices, SIZE(slices));
397 printf("%s: %d slices\n", ptp->type, n);
409 for (j = 0, c = 0, m = 0; j < n; j++) {
410 if (slices[j].size == 0)
412 if (slices[j].container > 0) {
417 slices[j].minor = m++;
419 printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
421 slices[j].size, device,
424 /* Loop to resolve contained slices */
427 for (j = 0; j < n; j++) {
429 int k = slices[j].container - 1;
431 if (slices[j].size == 0)
433 if (slices[j].minor > 0)
435 if (slices[j].container == 0)
437 slices[j].minor = m++;
439 start = slices[j].start - slices[k].start;
440 printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
443 slices[k].minor, start);
446 /* Terminate loop if nothing more to resolve */
454 for (j = MAXSLICES-1; j >= 0; j--) {
455 char *part_uuid, *reason;
457 if (safe_sprintf(partname, "%s%s%d",
458 mapname, delim, j+1)) {
459 fprintf(stderr, "partname too small\n");
462 strip_slash(partname);
464 if (!dm_map_present(partname, &part_uuid))
467 if (part_uuid && uuid) {
468 if (check_uuid(uuid, part_uuid, &reason) != 0) {
469 fprintf(stderr, "%s is %s. Not removing\n", partname, reason);
476 if (!dm_simplecmd(DM_DEVICE_REMOVE, partname,
482 printf("del devmap : %s\n", partname);
486 if (del_loop(loopdev)) {
488 printf("can't del loop : %s\n",
492 printf("loop deleted : %s\n", loopdev);
498 /* ADD and UPDATE share the same code that adds new partitions. */
499 for (j = 0, c = 0; j < n; j++) {
500 char *part_uuid, *reason;
502 if (slices[j].size == 0)
505 /* Skip all contained slices */
506 if (slices[j].container > 0) {
511 if (safe_sprintf(partname, "%s%s%d",
512 mapname, delim, j+1)) {
513 fprintf(stderr, "partname too small\n");
516 strip_slash(partname);
518 if (safe_sprintf(params, "%d:%d %" PRIu64 ,
519 major(buf.st_rdev), minor(buf.st_rdev), slices[j].start)) {
520 fprintf(stderr, "params too small\n");
524 op = (dm_map_present(partname, &part_uuid) ?
525 DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
527 if (part_uuid && uuid) {
528 if (check_uuid(uuid, part_uuid, &reason) != 0) {
529 fprintf(stderr, "%s is already in use, and %s\n", partname, reason);
537 if (!dm_addmap(op, partname, DM_TARGET, params,
538 slices[j].size, ro, uuid, j+1,
539 buf.st_mode & 0777, buf.st_uid,
541 fprintf(stderr, "create/reload failed on %s\n",
546 if (op == DM_DEVICE_RELOAD &&
547 !dm_simplecmd(DM_DEVICE_RESUME, partname,
548 1, MPATH_UDEV_RELOAD_FLAG)) {
549 fprintf(stderr, "resume failed on %s\n",
555 dm_devn(partname, &slices[j].major,
559 printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
560 partname, slices[j].major,
561 slices[j].minor, slices[j].size,
564 /* Loop to resolve contained slices */
567 for (j = 0; j < n; j++) {
568 char *part_uuid, *reason;
569 int k = slices[j].container - 1;
571 if (slices[j].size == 0)
574 /* Skip all existing slices */
575 if (slices[j].minor > 0)
578 /* Skip all simple slices */
579 if (slices[j].container == 0)
582 /* Check container slice */
583 if (slices[k].size == 0)
584 fprintf(stderr, "Invalid slice %d\n",
587 if (safe_sprintf(partname, "%s%s%d",
588 mapname, delim, j+1)) {
589 fprintf(stderr, "partname too small\n");
592 strip_slash(partname);
594 if (safe_sprintf(params, "%d:%d %" PRIu64,
595 major(buf.st_rdev), minor(buf.st_rdev),
597 fprintf(stderr, "params too small\n");
601 op = (dm_map_present(partname,
603 DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
605 if (part_uuid && uuid) {
606 if (check_uuid(uuid, part_uuid, &reason) != 0) {
607 fprintf(stderr, "%s is already in use, and %s\n", partname, reason);
614 dm_addmap(op, partname, DM_TARGET, params,
615 slices[j].size, ro, uuid, j+1,
617 buf.st_uid, buf.st_gid);
619 if (op == DM_DEVICE_RELOAD)
620 dm_simplecmd(DM_DEVICE_RESUME,
622 MPATH_UDEV_RELOAD_FLAG);
623 dm_devn(partname, &slices[j].major,
627 printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
628 partname, slices[j].major, slices[j].minor, slices[j].size,
638 /* Skip code that removes devmappings for deleted partitions */
642 for (j = MAXSLICES-1; j >= 0; j--) {
643 char *part_uuid, *reason;
644 if (safe_sprintf(partname, "%s%s%d",
645 mapname, delim, j+1)) {
646 fprintf(stderr, "partname too small\n");
649 strip_slash(partname);
651 if (slices[j].size ||
652 !dm_map_present(partname, &part_uuid))
655 if (part_uuid && uuid) {
656 if (check_uuid(uuid, part_uuid, &reason) != 0) {
657 fprintf(stderr, "%s is %s. Not removing\n", partname, reason);
664 if (!dm_simplecmd(DM_DEVICE_REMOVE,
670 printf("del devmap : %s\n", partname);
680 if (what == LIST && loopcreated && S_ISREG (buf.st_mode)) {
683 if (del_loop(device)) {
685 printf("can't del loop : %s\n",
689 printf("loop deleted : %s\n", device);
699 xmalloc (size_t size) {
708 fprintf(stderr, "Out of memory\n");
716 * sseek: seek to specified sector
720 sseek(int fd, unsigned int secnr) {
722 in = ((off64_t) secnr << 9);
725 if ((out = lseek64(fd, in, SEEK_SET)) != in)
727 fprintf(stderr, "llseek error\n");
741 getblock (int fd, unsigned int secnr) {
744 for (bp = blockhead; bp; bp = bp->next)
746 if (bp->secnr == secnr)
749 if (sseek(fd, secnr))
752 bp = xmalloc(sizeof(struct block));
754 bp->next = blockhead;
756 bp->block = (char *) xmalloc(READ_SIZE);
758 if (read(fd, bp->block, READ_SIZE) != READ_SIZE) {
759 fprintf(stderr, "read error, sector %d\n", secnr);
767 get_sector_size(int filedes)
769 int rc, sector_size = 512;
771 rc = ioctl(filedes, BLKSSZGET, §or_size);