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/types.h>
32 #include <libdevmapper.h>
34 #include "devmapper.h"
39 #define SIZE(a) (sizeof(a)/sizeof((a)[0]))
41 #define READ_SIZE 1024
44 #define DM_TARGET "linear"
45 #define LO_NAME_SIZE 64
46 #define PARTNAME_SIZE 128
49 struct slice slices[MAXSLICES];
51 enum action { LIST, ADD, DELETE, UPDATE };
61 addpts(char *t, ptreader f)
63 if (ptct >= MAXTYPES) {
64 fprintf(stderr, "addpts: too many types\n");
75 addpts("gpt", read_gpt_pt);
76 addpts("dos", read_dos_pt);
77 addpts("bsd", read_bsd_pt);
78 addpts("solaris", read_solaris_pt);
79 addpts("unixware", read_unixware_pt);
80 addpts("dasd", read_dasd_pt);
81 addpts("mac", read_mac_pt);
82 addpts("sun", read_sun_pt);
85 static char short_opts[] = "rladfgvp:t:su";
94 printf("usage : kpartx [-a|-d|-l] [-f] [-v] wholedisk\n");
95 printf("\t-a add partition devmappings\n");
96 printf("\t-r devmappings will be readonly\n");
97 printf("\t-d del partition devmappings\n");
98 printf("\t-u update partition devmappings\n");
99 printf("\t-l list partitions devmappings that would be added by -a\n");
100 printf("\t-p set device name-partition number delimiter\n");
101 printf("\t-g force GUID partition table (GPT)\n");
102 printf("\t-f force devmap create\n");
103 printf("\t-v verbose\n");
104 printf("\t-s sync mode. Don't return until the partitions are created\n");
109 set_delimiter (char * device, char * delimiter)
113 while (*(p++) != 0x0)
116 if (isdigit(*(p - 2)))
121 strip_slash (char * device)
125 while (*(p++) != 0x0) {
133 find_devname_offset (char * device)
143 return (int)(q - device) + 1;
147 get_hotplug_device(void)
149 unsigned int major, minor, off, len;
151 char *devname = NULL;
156 var = getenv("ACTION");
158 if (!var || strcmp(var, "add"))
161 /* Get dm mapname for hotpluged device. */
162 if (!(devname = getenv("DEVNAME")))
165 if (stat(devname, &buf))
168 major = (unsigned int)MAJOR(buf.st_rdev);
169 minor = (unsigned int)MINOR(buf.st_rdev);
171 if (!(mapname = dm_mapname(major, minor))) /* Not dm device. */
174 off = find_devname_offset(devname);
175 len = strlen(mapname);
177 /* Dirname + mapname + \0 */
178 if (!(device = (char *)malloc(sizeof(char) * (off + len + 1))))
181 /* Create new device name. */
182 snprintf(device, off + 1, "%s", devname);
183 snprintf(device + off, len + 1, "%s", mapname);
185 if (strlen(device) != (off + len))
192 main(int argc, char **argv){
193 int i, j, m, n, op, off, arg, c, d, ro=0;
197 enum action what = LIST;
198 char *type, *diskdevice, *device, *progname;
200 char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
201 char * loopdev = NULL;
204 char *mapname = NULL;
215 type = device = diskdevice = NULL;
216 memset(&all, 0, sizeof(all));
217 memset(&partname, 0, sizeof(partname));
219 /* Check whether hotplug mode. */
220 progname = strrchr(argv[0], '/');
227 if (!strcmp(progname, "kpartx.dev")) { /* Hotplug mode */
230 /* Setup for original kpartx variables */
231 if (!(device = get_hotplug_device()))
236 } else if (argc < 2) {
241 while ((arg = getopt(argc, argv, short_opts)) != EOF) switch(arg) {
280 #ifdef LIBDM_API_COOKIE
282 dm_udev_set_sync_support(0);
285 if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE || what == UPDATE)) {
286 fprintf(stderr, "device mapper prerequisites not met\n");
291 /* already got [disk]device */
292 } else if (optind == argc-2) {
293 device = argv[optind];
294 diskdevice = argv[optind+1];
295 } else if (optind == argc-1) {
296 diskdevice = device = argv[optind];
302 if (stat(device, &buf)) {
303 printf("failed to stat() %s\n", device);
307 if (S_ISREG (buf.st_mode)) {
308 /* already looped file ? */
309 loopdev = find_loop_by_file(device);
311 if (!loopdev && what == DELETE)
315 loopdev = find_unused_loop_device();
317 if (set_loop(loopdev, device, 0, &loopro)) {
318 fprintf(stderr, "can't set up loop\n");
327 delim = malloc(DELIM_SIZE);
328 memset(delim, 0, DELIM_SIZE);
329 set_delimiter(device, delim);
332 off = find_devname_offset(device);
335 uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
336 (unsigned int)MINOR(buf.st_rdev));
337 mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev),
338 (unsigned int)MINOR(buf.st_rdev));
345 mapname = device + off;
346 else if (!force_devmap &&
347 dm_no_partitions((unsigned int)MAJOR(buf.st_rdev),
348 (unsigned int)MINOR(buf.st_rdev))) {
349 /* Feature 'no_partitions' is set, return */
353 fd = open(device, O_RDONLY);
360 /* add/remove partitions to the kernel devmapper tables */
362 for (i = 0; i < ptct; i++) {
365 if (type && strcmp(type, ptp->type))
368 /* here we get partitions */
369 n = ptp->fn(fd, all, slices, SIZE(slices));
373 printf("%s: %d slices\n", ptp->type, n);
385 for (j = 0, c = 0, m = 0; j < n; j++) {
386 if (slices[j].size == 0)
388 if (slices[j].container > 0) {
393 slices[j].minor = m++;
395 printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
397 slices[j].size, device,
400 /* Loop to resolve contained slices */
403 for (j = 0; j < n; j++) {
405 int k = slices[j].container - 1;
407 if (slices[j].size == 0)
409 if (slices[j].minor > 0)
411 if (slices[j].container == 0)
413 slices[j].minor = m++;
415 start = slices[j].start - slices[k].start;
416 printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
419 slices[k].minor, start);
422 /* Terminate loop if nothing more to resolve */
430 for (j = n-1; j >= 0; j--) {
431 if (safe_sprintf(partname, "%s%s%d",
432 mapname, delim, j+1)) {
433 fprintf(stderr, "partname too small\n");
436 strip_slash(partname);
438 if (!slices[j].size || !dm_map_present(partname))
441 if (!dm_simplecmd(DM_DEVICE_REMOVE, partname,
447 printf("del devmap : %s\n", partname);
450 if (S_ISREG (buf.st_mode)) {
451 if (del_loop(device)) {
453 printf("can't del loop : %s\n",
457 printf("loop deleted : %s\n", device);
463 /* ADD and UPDATE share the same code that adds new partitions. */
464 for (j = 0, c = 0; j < n; j++) {
465 if (slices[j].size == 0)
468 /* Skip all contained slices */
469 if (slices[j].container > 0) {
474 if (safe_sprintf(partname, "%s%s%d",
475 mapname, delim, j+1)) {
476 fprintf(stderr, "partname too small\n");
479 strip_slash(partname);
481 if (safe_sprintf(params, "%s %" PRIu64 ,
482 device, slices[j].start)) {
483 fprintf(stderr, "params too small\n");
487 op = (dm_map_present(partname) ?
488 DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
490 if (!dm_addmap(op, partname, DM_TARGET, params,
491 slices[j].size, ro, uuid, j+1,
492 buf.st_mode & 0777, buf.st_uid,
493 buf.st_gid, &cookie)) {
494 fprintf(stderr, "create/reload failed on %s\n",
498 if (op == DM_DEVICE_RELOAD &&
499 !dm_simplecmd(DM_DEVICE_RESUME, partname,
501 fprintf(stderr, "resume failed on %s\n",
505 dm_devn(partname, &slices[j].major,
509 printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
510 partname, slices[j].major,
511 slices[j].minor, slices[j].size,
514 /* Loop to resolve contained slices */
517 for (j = 0; j < n; j++) {
519 int k = slices[j].container - 1;
521 if (slices[j].size == 0)
524 /* Skip all existing slices */
525 if (slices[j].minor > 0)
528 /* Skip all simple slices */
529 if (slices[j].container == 0)
532 /* Check container slice */
533 if (slices[k].size == 0)
534 fprintf(stderr, "Invalid slice %d\n",
537 if (safe_sprintf(partname, "%s%s%d",
538 mapname, delim, j+1)) {
539 fprintf(stderr, "partname too small\n");
542 strip_slash(partname);
544 start = slices[j].start - slices[k].start;
545 if (safe_sprintf(params, "%d:%d %" PRIu64,
549 fprintf(stderr, "params too small\n");
553 op = (dm_map_present(partname) ?
554 DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
556 dm_addmap(op, partname, DM_TARGET, params,
557 slices[j].size, ro, uuid, j+1,
559 buf.st_uid, buf.st_gid,
562 if (op == DM_DEVICE_RELOAD)
563 dm_simplecmd(DM_DEVICE_RESUME,
567 dm_devn(partname, &slices[j].major,
571 printf("add map %s : 0 %" PRIu64 " %s %s\n",
572 partname, slices[j].size,
582 /* Skip code that removes devmappings for deleted partitions */
586 for (j = MAXSLICES-1; j >= 0; j--) {
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 (slices[j].size || !dm_map_present(partname))
597 if (!dm_simplecmd(DM_DEVICE_REMOVE,
598 partname, 1, &cookie)) {
603 printf("del devmap : %s\n", partname);
613 if (what == LIST && loopcreated && S_ISREG (buf.st_mode)) {
616 if (del_loop(device)) {
618 printf("can't del loop : %s\n",
622 printf("loop deleted : %s\n", device);
624 #ifdef LIBDM_API_COOKIE
625 dm_udev_wait(cookie);
634 xmalloc (size_t size) {
643 fprintf(stderr, "Out of memory\n");
651 * sseek: seek to specified sector
655 sseek(int fd, unsigned int secnr) {
657 in = ((off64_t) secnr << 9);
660 if ((out = lseek64(fd, in, SEEK_SET)) != in)
662 fprintf(stderr, "llseek error\n");
676 getblock (int fd, unsigned int secnr) {
679 for (bp = blockhead; bp; bp = bp->next)
681 if (bp->secnr == secnr)
684 if (sseek(fd, secnr))
687 bp = xmalloc(sizeof(struct block));
689 bp->next = blockhead;
691 bp->block = (char *) xmalloc(READ_SIZE);
693 if (read(fd, bp->block, READ_SIZE) != READ_SIZE) {
694 fprintf(stderr, "read error, sector %d\n", secnr);