示例#1
0
文件: partx.c 项目: tcdog001/autelan
int
main(int argc, char **argv) {
    int fd, fd2, c, i, j, k, n;
    unsigned long long size;
    struct hd_geometry g;
    struct slice all;
    struct blkpg_ioctl_arg a;
    struct blkpg_partition pt;
    struct pt *ptp;
    enum action what = LIST;
    char *p, *type, *diskdevice, *device;
    int lower, upper;
    int verbose = 0;
    int ret = 0;

    initpts();
    init_crc32();

    lower = upper = 0;
    type = device = diskdevice = NULL;

    while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL))
            != -1) switch(c) {
        case 'l':
            what = LIST;
            break;
        case 'a':
            what = ADD;
            break;
        case 'd':
            what = DELETE;
            break;
        case 'g':
            force_gpt = 1;
            break;
        case 'n':
            p = optarg;
            lower = atoi(p);
            p = strchr(p, '-');
            if (p)
                upper = atoi(p+1);
            else
                upper = lower;
            break;
        case 't':
            type = optarg;
            break;
        case 'v':
            verbose = 1;
            break;
        case '?':
        default:
            fprintf(stderr, "unknown option\n");
            exit(1);
        }

    if (optind == argc-2) {
        device = argv[optind];
        diskdevice = argv[optind+1];
    } else if (optind == argc-1) {
        diskdevice = device = argv[optind];
    } else {
        fprintf(stderr, "call: partx -opts [device] wholedisk\n");
        exit(1);
    }

    fd = open(diskdevice, O_RDONLY);
    if (fd == -1) {
        perror(diskdevice);
        exit(1);
    }

    /* remove the indicated partitions from the kernel partition tables */
    if (what == DELETE) {
        if (device != diskdevice) {
            fprintf(stderr,
                    "call: partx -d [--nr M-N] wholedisk\n");
            exit(1);
        }

        if (!lower)
            lower = 1;

        while (upper == 0 || lower <= upper) {
            int err;

            if (lower > MAXSLICES)
                break;
            pt.pno = lower;
            pt.start = 0;
            pt.length = 0;
            pt.devname[0] = 0;
            pt.volname[0] = 0;
            a.op = BLKPG_DEL_PARTITION;
            a.flags = 0;
            a.datalen = sizeof(pt);
            a.data = &pt;
            if (ioctl(fd, BLKPG, &a) == -1)
                err = errno;
            else
                err = 0;
            errmerge(err, lower,
                     "error deleting partition %d: ",
                     "error deleting partitions %d-%d: ");
            /* expected errors:
               EBUSY: mounted or in use as swap
               ENXIO: no such nonempty partition
               EINVAL: not wholedisk, or bad pno
               EACCES/EPERM: permission denied
            */
            if (err && err != EBUSY && err != ENXIO) {
                ret = 1;
                break;
            }
            if (err == 0 && verbose)
                printf("deleted partition %d\n", lower);
            lower++;
        }
        errmerge(0, 0,
                 "error deleting partition %d: ",
                 "error deleting partitions %d-%d: ");
        return ret;
    }

    if (device != diskdevice) {
        fd2 = open(device, O_RDONLY);
        if (fd2 == -1) {
            perror(device);
            exit(1);
        }
    } else {
        fd2 = fd;
    }

    if (ioctl(fd, HDIO_GETGEO, &g)) {
        perror("HDIO_GETGEO");
        exit(1);
    }
    if (g.start != 0) {
        fprintf(stderr, "last arg is not the whole disk\n");
        fprintf(stderr, "call: partx -opts device wholedisk\n");
        exit(1);
    }

    if (ioctl(fd2, HDIO_GETGEO, &g)) {
        perror("HDIO_GETGEO");
        exit(1);
    }
    all.start = g.start;

    if (blkdev_get_sectors(fd2, &size) != 0) {
        perror("partx");
        exit(1);
    }
    all.size = (unsigned int) size;

    if (verbose)
        printf("device %s: start %d size %d\n",
               device, all.start, all.size);

    if (all.size == 0) {
        fprintf(stderr, "That disk slice has size 0\n");
        exit(0);
    }
    if (all.size == 2)
        all.size = 0;	/* probably extended partition */

    /* add the indicated partitions to the kernel partition tables */
    if (!lower)
        lower = 1;
    for (i = 0; i < ptct; i++) {
        ptp = &pts[i];
        if (!type || !strcmp(type, ptp->type)) {
            n = ptp->fn(fd, all, slices, ARRAY_SIZE(slices));
            if (n >= 0 && verbose)
                printf("%s: %d slices\n", ptp->type, n);
            if (n > 0 && (verbose || what == LIST)) {
                for (j=0; j<n; j++)
                    printf("#%2d: %9d-%9d (%9d sectors, %6d MB)\n",
                           lower+j,
                           slices[j].start,
                           slices[j].start+slices[j].size-1,
                           slices[j].size,
                           (int)((512 * (long long) slices[j].size)
                                 / 1000000));
            }
            if (n > 0 && what == ADD) {
                /* test for overlap, as in the case of an
                   extended partition, and reduce size */
                for (j=0; j<n; j++) {
                    for (k=j+1; k<n; k++) {
                        if (slices[k].start > slices[j].start &&
                                slices[k].start < slices[j].start +
                                slices[j].size) {
                            slices[j].size = slices[k].start -
                                             slices[j].start;
                            if (verbose)
                                printf("reduced size of "
                                       "partition #%d to %d\n",
                                       lower+j,
                                       slices[j].size);
                        }
                    }
                }
                for (j=0; j<n; j++) {
                    /* skip unused/empty partitions */
                    if (slices[j].size == 0)
                        continue;
                    pt.pno = lower+j;
                    pt.start = 512 * (long long) slices[j].start;
                    pt.length = 512 * (long long) slices[j].size;
                    pt.devname[0] = 0;
                    pt.volname[0] = 0;
                    a.op = BLKPG_ADD_PARTITION;
                    a.flags = 0;
                    a.datalen = sizeof(pt);
                    a.data = &pt;
                    if (ioctl(fd, BLKPG, &a) == -1) {
                        perror("BLKPG");
                        fprintf(stderr,
                                "error adding partition %d\n",
                                lower+j);
                    } else if (verbose)
                        printf("added partition %d\n", lower+j);
                }
            }
        }
    }

    return 0;
}
示例#2
0
int
main(int argc, char **argv){
	int fd, i, j, m, n, op, off, arg, c, d;
	struct slice all;
	struct pt *ptp;
	enum action what = LIST;
	char *type, *diskdevice, *device, *progname;
	int verbose = 0;
	char partname[PARTNAME_SIZE], params[PARTNAME_SIZE + 16];
	char * loopdev = NULL;
	char * delim = NULL;
	char *uuid = NULL;
	char *mapname = NULL;
	int loopro = 0;
	int hotplug = 0;
	int loopcreated = 0;
	int sync = 0;
	struct stat buf;
	uint32_t cookie = 0;

	initpts();
	init_crc32();

	type = device = diskdevice = NULL;
	memset(&all, 0, sizeof(all));
	memset(&partname, 0, sizeof(partname));

	/* Check whether hotplug mode. */
	progname = strrchr(argv[0], '/');

	if (!progname)
		progname = argv[0];
	else
		progname++;

	if (!strcmp(progname, "kpartx.dev")) { /* Hotplug mode */
		hotplug = 1;

		/* Setup for original kpartx variables */
		if (!(device = get_hotplug_device()))
			exit(1);

		diskdevice = device;
		what = ADD;
	} else if (argc < 2) {
		usage();
		exit(1);
	}

	while ((arg = getopt(argc, argv, short_opts)) != EOF) switch(arg) {
		case 'g':
			force_gpt=1;
			break;
		case 't':
			type = optarg;
			break;
		case 'v':
			verbose = 1;
			break;
		case 'p':
			delim = optarg;
			break;
		case 'l':
			what = LIST;
			break;
		case 'a':
			what = ADD;
			break;
		case 'd':
			what = DELETE;
			break;
		case 's':
			sync = 1;
			break;
		default:
			usage();
			exit(1);
	}

	if (!sync)
		dm_udev_set_sync_support(0);

	if (dm_prereq(DM_TARGET, 0, 0, 0) && (what == ADD || what == DELETE)) {
		fprintf(stderr, "device mapper prerequisites not met\n");
		exit(1);
	}

	if (hotplug) {
		/* already got [disk]device */
	} else if (optind == argc-2) {
		device = argv[optind];
		diskdevice = argv[optind+1];
	} else if (optind == argc-1) {
		diskdevice = device = argv[optind];
	} else {
		usage();
		exit(1);
	}

	if (stat(device, &buf)) {
		printf("failed to stat() %s\n", device);
		exit (1);
	}

	if (S_ISREG (buf.st_mode)) {
		/* already looped file ? */
		loopdev = find_loop_by_file(device);

		if (!loopdev && what == DELETE)
			exit (0);

		if (!loopdev) {
			loopdev = find_unused_loop_device();

			if (set_loop(loopdev, device, 0, &loopro)) {
				fprintf(stderr, "can't set up loop\n");
				exit (1);
			}
			loopcreated = 1;
		}
		device = loopdev;
	}

	if (delim == NULL) {
		delim = malloc(DELIM_SIZE);
		memset(delim, 0, DELIM_SIZE);
		set_delimiter(device, delim);
	}

	off = find_devname_offset(device);

	if (!loopdev) {
		uuid = dm_mapuuid((unsigned int)MAJOR(buf.st_rdev),
				  (unsigned int)MINOR(buf.st_rdev));
		mapname = dm_mapname((unsigned int)MAJOR(buf.st_rdev),
				     (unsigned int)MINOR(buf.st_rdev));
	}

	if (!uuid)
		uuid = device + off;

	if (!mapname)
		mapname = device + off;

	fd = open(device, O_RDONLY);

	if (fd == -1) {
		perror(device);
		exit(1);
	}

	/* add/remove partitions to the kernel devmapper tables */
	int r = 0;
	for (i = 0; i < ptct; i++) {
		ptp = &pts[i];

		if (type && strcmp(type, ptp->type))
			continue;

		/* here we get partitions */
		n = ptp->fn(fd, all, slices, SIZE(slices));

#ifdef DEBUG
		if (n >= 0)
			printf("%s: %d slices\n", ptp->type, n);
#endif

		if (n > 0)
			close(fd);
		else
			continue;

		switch(what) {
		case LIST:
			for (j = 0, c = 0, m = 0; j < n; j++) {
				if (slices[j].size == 0)
					continue;
				if (slices[j].container > 0) {
					c++;
					continue;
				}

				slices[j].minor = m++;

				printf("%s%s%d : 0 %" PRIu64 " %s %" PRIu64"\n",
				       mapname, delim, j+1,
				       slices[j].size, device,
				       slices[j].start);
			}
			/* Loop to resolve contained slices */
			d = c;
			while (c) {
				for (j = 0; j < n; j++) {
					uint64_t start;
					int k = slices[j].container - 1;

					if (slices[j].size == 0)
						continue;
					if (slices[j].minor > 0)
						continue;
					if (slices[j].container == 0)
						continue;
					slices[j].minor = m++;

					start = slices[j].start - slices[k].start;
					printf("%s%s%d : 0 %" PRIu64 " /dev/dm-%d %" PRIu64 "\n",
					       mapname, delim, j+1,
					       slices[j].size,
					       slices[k].minor, start);
					c--;
				}
				/* Terminate loop if nothing more to resolve */
				if (d == c)
					break;
			}

			if (loopcreated && S_ISREG (buf.st_mode)) {
				if (del_loop(device)) {
					if (verbose)
						printf("can't del loop : %s\n",
							device);
					exit(1);
				}
				printf("loop deleted : %s\n", device);
			}
			break;

		case DELETE:
			for (j = n-1; j >= 0; j--) {
				if (safe_sprintf(partname, "%s%s%d",
					     mapname, delim, j+1)) {
					fprintf(stderr, "partname too small\n");
					exit(1);
				}
				strip_slash(partname);

				if (!slices[j].size || !dm_map_present(partname))
					continue;

				if (!dm_simplecmd(DM_DEVICE_REMOVE, partname,
						  0, &cookie)) {
					r++;
					continue;
				}
				if (verbose)
					printf("del devmap : %s\n", partname);
			}

			if (S_ISREG (buf.st_mode)) {
				if (del_loop(device)) {
					if (verbose)
						printf("can't del loop : %s\n",
							device);
					exit(1);
				}
				printf("loop deleted : %s\n", device);
			}
			break;

		case ADD:
			for (j = 0, c = 0; j < n; j++) {
				if (slices[j].size == 0)
					continue;

				/* Skip all contained slices */
				if (slices[j].container > 0) {
					c++;
					continue;
				}

				if (safe_sprintf(partname, "%s%s%d",
					     mapname, delim, j+1)) {
					fprintf(stderr, "partname too small\n");
					exit(1);
				}
				strip_slash(partname);

				if (safe_sprintf(params, "%s %" PRIu64 ,
						 device, slices[j].start)) {
					fprintf(stderr, "params too small\n");
					exit(1);
				}

				op = (dm_map_present(partname) ?
					DM_DEVICE_RELOAD : DM_DEVICE_CREATE);

				if (!dm_addmap(op, partname, DM_TARGET, params,
					       slices[j].size, uuid, j+1,
					       buf.st_mode & 0777, buf.st_uid,
					       buf.st_gid, &cookie)) {
					fprintf(stderr, "create/reload failed on %s\n",
						partname);
					r++;
				}
				if (op == DM_DEVICE_RELOAD &&
				    !dm_simplecmd(DM_DEVICE_RESUME, partname,
						  1, &cookie)) {
					fprintf(stderr, "resume failed on %s\n",
						partname);
					r++;
				}
				dm_devn(partname, &slices[j].major,
					&slices[j].minor);

				if (verbose)
					printf("add map %s (%d:%d): 0 %" PRIu64 " %s %s\n",
					       partname, slices[j].major,
					       slices[j].minor, slices[j].size,
					       DM_TARGET, params);
			}
			/* Loop to resolve contained slices */
			d = c;
			while (c) {
				for (j = 0; j < n; j++) {
					uint64_t start;
					int k = slices[j].container - 1;

					if (slices[j].size == 0)
						continue;

					/* Skip all existing slices */
					if (slices[j].minor > 0)
						continue;

					/* Skip all simple slices */
					if (slices[j].container == 0)
						continue;

					/* Check container slice */
					if (slices[k].size == 0)
						fprintf(stderr, "Invalid slice %d\n",
							k);

					if (safe_sprintf(partname, "%s%s%d",
							 mapname, delim, j+1)) {
						fprintf(stderr, "partname too small\n");
						exit(1);
					}
					strip_slash(partname);

					start = slices[j].start - slices[k].start;
					if (safe_sprintf(params, "%d:%d %" PRIu64,
							 slices[k].major,
							 slices[k].minor,
							 start)) {
						fprintf(stderr, "params too small\n");
						exit(1);
					}

					op = (dm_map_present(partname) ?
					      DM_DEVICE_RELOAD : DM_DEVICE_CREATE);

					dm_addmap(op, partname, DM_TARGET, params,
						  slices[j].size, uuid, j+1,
						  buf.st_mode & 0777,
						  buf.st_uid, buf.st_gid,
						  &cookie);

					if (op == DM_DEVICE_RELOAD)
						dm_simplecmd(DM_DEVICE_RESUME,
							     partname, 1,
							     &cookie);

					dm_devn(partname, &slices[j].major,
						&slices[j].minor);

					if (verbose)
						printf("add map %s : 0 %" PRIu64 " %s %s\n",
						       partname, slices[j].size,
						       DM_TARGET, params);
					c--;
				}
				/* Terminate loop */
				if (d == c)
					break;
			}
			break;

		default:
			break;

		}
		if (n > 0)
			break;
	}
	dm_udev_wait(cookie);
	dm_lib_release();
	dm_lib_exit();

	return r;
}